diff --git a/.gitignore b/.gitignore index d451ff16c1010b8dc4285ef4d338028792a0ecd3..37861b36819a137886ee87d1b0c8331eac6349b0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,16 @@ node_modules .DS_Store dist dist-ssr +build +lib +types *.local +pnpm-lock.yaml +package-lock.json +yarn-error.log +.history +.vscode +.idea +packages/devui-vue/devui/vue-devui.ts +packages/devui-vue/devui/theme/theme.scss +packages/devui-vue/docs/.vitepress/config/sidebar.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..752af08930180076a6eb5c81f48d9d6efae35d78 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "htmlWhitespaceSensitivity": "ignore", + "jsxSingleQuote": true, + "printWidth": 100, + "semi": false, + "useTabs": false, + "trailingComma": "none", + "singleQuote": true, + "tabWidth": 2 +} diff --git a/LICENSE b/LICENSE index e69accf89f0979125691c0bbd398c68d2385ecc8..e3a2b0425c06727332e53b757349d33b0c5835df 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License -Copyright (c) 2021 Kagol +Copyright (c) 2019 - present DevUI. +Copyright (c) 2019 - present Huawei Technologies Co., Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,3 +20,4 @@ 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. + diff --git a/README.md b/README.md index df34440437a773027c8a50ebabee0fa24dfd02b1..a930fe3ad9699f981e3cebadf5f9b352de1d0cd5 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,26 @@ -# Vue DevUI +

+ + DevUI Logo + +

-Vue3版本的DevUI组件库,基于[https://github.com/devcloudfe/ng-devui](https://github.com/devcloudfe/ng-devui) +Vue DevUI 是 Vue3 版本的 DevUI 组件库,基于 [https://github.com/devcloudfe/ng-devui](https://github.com/devcloudfe/ng-devui),倡导`沉浸`、`灵活`、`至简`的设计价值观。 -DevUI官方网站:[https://devui.design](https://devui.design) +DevUI 官方网站:[https://devui.design](https://devui.design) -Tips: 该项目目前还处于孵化和演进阶段,欢迎大家一起参与建设🤝 +# 当前状态: Beta -目前,组件移植的基本流程已经打通,欢迎大家参与到 Vue DevUI 项目的建设中来!👏🎉 +该项目还处于孵化和演进阶段,欢迎大家参与到 Vue DevUI 项目的建设中来!🎉🎉 通过参与 Vue DevUI 项目,你可以: -- 学习最新的 Vite+Vue3+TSX 技术 -- 学习如何设计和开发组件 -- 参与到开源社区中来 -- 结识一群热爱学习、热爱开源的朋友 - -## 任务安排 - -|任务名 |作用 |责任人|进度| -|-- |-- |--|--| -|移植 d-accordion 组件 |显示左侧组件导航 |[kagol](https://github.com/kagol)|50%| -|移植 d-tabs 组件 |让 Demo/API 的展示分开 |星辰大海|0%| -|移植 d-codebox 组件 |展示 Demo 中的示例代码 |[to0simple](https://github.com/to0simple)|50%| -|移植 d-highlight 组件 |代码高亮 |[to0simple](https://github.com/to0simple)|0%| -|移植 d-button 组件 |该组件将成为第一个成功移植过程的 Vue 组件|[Zcating](https://github.com/Zcating)|50%| -|编写 Button 组件的 Demo|显示组件的 Demo |待认领|0%| -|集成 API 文档 |显示组件的 API |[kagol](https://github.com/kagol)|50%| -|组件库打包 |打包并发布到npm |待认领|0%| +- 🔥 学习最新的 `Vite`+`Vue3`+`TypeScript`+`JSX` 技术 +- 🎁 学习如何设计和开发组件 +- ⭐ 参与到开源社区中来 +- 🎊 结识一群热爱学习、热爱开源的朋友 + +[贡献指南](https://gitee.com/devui/vue-devui/wikis/【必看】快速开始) + +# 快速开始 ## 1 安装依赖 @@ -44,10 +39,6 @@ yarn dev(推荐) or -npx vite - -or - npm run dev ``` @@ -64,3 +55,118 @@ or npm run build ``` + +# 使用 Vue DevUI + +## 1. 安装 + +``` +yarn add vue-devui +``` + +## 2. 全量引入 + +``` +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入 Vue DevUI 组件库 +import DevUI from 'vue-devui' +// Step 2: 引入组件库样式 +import 'vue-devui/style.css' + +createApp(App) +.use(DevUI) // Step 3: 使用 Vue DevUI +.mount('#app') +``` + +## 3. 按需引入 + +除了全量引入,我们也支持单个组件按需引入。 + +``` +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入单个组件 +import { Button } from 'vue-devui' +// or import Button from 'vue-devui/button' +// Step 2: 引入组件样式 +import 'vue-devui/button/style.css' + +createApp(App) +.use(Button) // Step 3: 使用组件 +.mount('#app') +``` + +## 4. 使用 + +``` + +``` + +# 图标库 + +图标库可以使用[DevUI图标库](https://devui.design/icon/ruleResource),也可以使用第三方图标库,比如:iconfont。 + +## 使用DevUI图标库 + +### 安装 + +``` +yarn add @devui-design/icons(推荐) + +or + +npm i @devui-design/icons +``` + +### 引入 + +在`main.ts`文件中,编写以下代码: + +``` +import '@devui-design/icons/icomoon/devui-icon.css' +``` + +### 使用 + +``` + +``` + +## 使用第三方图标库 + +如果有第三方图标库,可以用类似的方式引入。 + +### 引入 + +在`main.ts`文件中,编写以下代码: + +``` +import 'your-folder/my-icon.css' +``` + +### 使用 + +``` + +``` + +其中的`classPrefix`参数的值,应该和你的字体图标样式文件`my-icon.css`里定义的样式前缀保持一致。 + +比如`my-icon.css`里的图标样式: + +```css +.my-icon-branch-node:before { + content: "\E001"; +} +``` + +那么`classPrefix`就是`my-icon`。 + +# License + +[MIT](https://gitee.com/devui/vue-devui/blob/dev/LICENSE) diff --git a/devui/accordion/demo/accordion.route.ts b/devui/accordion/demo/accordion.route.ts deleted file mode 100644 index ca347814f2eb8ce2b306c9e1e2f6aac074d939de..0000000000000000000000000000000000000000 --- a/devui/accordion/demo/accordion.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import AccordionDemoComponent from './accordion-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: AccordionDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/accordion/doc/api-cn.md b/devui/accordion/doc/api-cn.md deleted file mode 100644 index e99775072ed05da5bdd742d3be093d275d4b4bda..0000000000000000000000000000000000000000 --- a/devui/accordion/doc/api-cn.md +++ /dev/null @@ -1,193 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```typescript -import { AccordionModule } from 'ng-devui/accordion'; -``` - -在页面中使用: - -```html - -``` - -## Accordion - -### d-accordion 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------: | :---------------------------------------------------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------- | -| data | `Array \| AccordionMenuType` | -- | 必选,数据源,可以自定义数组或者使用预设的`AccordionMenuType` | [基本用法](demo#basic-usage) | -| titleKey | `string` | 'title' | 可选,标题的属性名,item[titleKey]类型为`string`,为标题显示内容 | [改变键值](demo#change-values) | -| loadingKey | `string` | 'loading' | 可选,子菜单是否加载中的判断属性名,item[loadingKey]类型为`boolean` | [改变键值](demo#change-values) | -| childrenKey | `string` | 'children' | 可选,子菜单的属性名,item[childrenKey]类型为`Array` | [改变键值](demo#change-values) | -| disabledKey | `string` | 'disabled' | 可选,是否禁用的属性名,item[disabledKey]类型为`boolean` | [改变键值](demo#change-values) | -| activeKey | `string` | 'active' | 可选,子菜单是否激活的属性名,item[activeKey]类型为`boolean` | [改变键值](demo#change-values) | -| openKey | `string` | 'open' | 可选,菜单是否展开的属性名,item[openKey]类型为`boolean` | [改变键值](demo#change-values) | -| restrictOneOpen | `boolean` | false | 可选,限制一级菜单同时只能打开一个, 默认不限制 | [基本用法](demo#basic-usage) | -| menuItemTemplate | `TemplateRef` | 内置 | 可选, 可展开菜单内容条模板,可用变量值见下 | [使用模板](demo#using-templates) | -| itemTemplate | `TemplateRef` | 内置 | 可选,可点击菜单内容条模板,可用变量值见下 | [使用模板](demo#using-templates) | -| noContentTemplate | `TemplateRef` | 内置 | 可选,没有内容的时候使用自定义模板,可用变量值见下 | [使用模板](demo#using-templates) | -| loadingTemplate | `TemplateRef` | 内置 | 可选,加载中使用自定义模板,可用变量值见下 | [使用模板](demo#using-templates) | -| innerListTemplate | `TemplateRef` | 内置 | 可选,子列表内容完全自定义,用做折叠面板,可用变量值见下 | [使用模板](demo#using-templates) | -| linkType | `'routerLink'\|'hrefLink'\|'dependOnLinkTypeKey'\|''` | '' | 可选,`'routerLink'`为路由场景;`'hrefLink'`为外部链接场景;`'dependOnLinkTypeKey'`为动态路由或外部链接场景;`''`为默认非链接类型(无法右键打开新标签页) | [内置路由和链接类型](demo#use-built-in-routing-and-link-types) | -| linkTypeKey | `string` | 'linkType' | 可选,链接内容的类型的 key 值,用于 linkType 为`'dependOnLinkTypeKey'`时指定对象链接类型属性名,item[linkTypeKey]类型为`'routerLink'\|'hrefLink'\| string`,其中`'routerLink'`为路由链接,`'hrefLink'`为外部链接,其他为默认非链接类型 | -| linkKey | `string` | 'link' | 可选,链接内容的 key,用于 linkType 为连接类型记非`''`时,链接的取值的属性值,item[linkKey]为路由地址或者超链接地址 | -| linkTargetKey | `string` | 'target' | 可选,链接目标窗口的 key,用于链接类型,item[linkTargetKey]为单个链接的目标窗口 | -| linkDefaultTarget | `string` | '\_self' | 可选,不设置 target 的时候 target 默认值为`'_self'`,用于链接类型, 取值等同于 a 链接的 target 属性 | [内置路由和链接类型](demo#use-built-in-routing-and-link-types) | -| autoOpenActiveMenu | `boolean` | false | 可选,是否自动展开带有活跃子项的菜单 | [复合层级和自动展开](demo#compound-level-and-auto-expand) | -| accordionType | `'normal'\|'embed'` | 'normal' | 可选,菜单形式是普通(带阴影)还是内嵌(不带阴影) | [基本用法](demo#basic-usage) | -| showAnimation | `boolean` | true | 可选,是否展示动画 | [内置路由和链接类型](demo#use-built-in-routing-and-link-types) | - -### d-accordion 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :--------------: | :-----------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------- | -| menuToggle | `EventEmitter<`[`AccordionMenuToggleEvent`](#accordionmenutoggleevent)`>` | 可选,可展开菜单展开事件,返回对象里属性 item 为点击的对象数据,open 为 true 则将要展开 false 则将要关闭, parent 为父对象数据,event 为点击事件的原生事件 | [基本用法](demo#basic-usage) | -| itemClick | `EventEmitter<`[`AccordionItemClickEvent`](#accordionitemclickevent)`>` | 可选,可点击菜单点击事件,返回对象里属性 item 为点击的对象数据,preActive 对象为上一次展开的对象, parent 为父对象数据,event 为点击事件的原生事件 | [基本用法](demo#basic-usage) | -| activeItemChange | `EventEmitter` | 可选,子项切换的时候会发出新激活的子项的数据 | [基本用法](demo#basic-usage) | - -### AccordionMenuType 定义 - -```typescript -/* 基础数据类型 */ -type AccordionMenuItemLinkType = 'routerLink' | 'hrefLink' | string; -export interface AccordionBase { - title: string; - disabled?: boolean; - [prop: string]: any; -} -interface IAccordionActiveable { - active?: boolean; -} -interface IAccordionFoldable { - open?: boolean; - loading?: boolean; - children?: Array; -} - -interface IAccordionLinkable { - link?: string; - target?: boolean; - linkType?: AccordionMenuItemLinkType; -} -export interface AccordionBaseItem extends AccordionBase, IAccordionActiveable {} -export interface AccordionBaseMenu extends AccordionBase, IAccordionFoldable {} - -export interface AccordionLinkableItem extends AccordionBase, IAccordionActiveable, IAccordionLinkable {} -export interface AccordionMenuItem extends AccordionBase, IAccordionActiveable, IAccordionFoldable, IAccordionLinkable {} - -export type AccordionMenuType = Array; - -/* 通用公共配置数据类型 */ -interface AccordionMenuKeyGroup { - titleKey?: string; - activeKey?: string; - disabledKey?: string; - openKey?: string; - loadingKey?: string; - childrenKey?: string; - linkKey?: string; - linkTargetKey?: string; - linkTypeKey?: string; -} - -type AccordionTemplateRefArray = 'itemTemplate' | 'menuItemTemplate' | 'noContentTemplate' | 'loadingTemplate' | 'innerListTemplate'; -type AccordionTemplateRefGroup = { - [p in AccordionTemplateRefArray]: TemplateRef; -}; -interface AccordionConfigOptions { - restrictOneOpen?: boolean; - autoOpenActiveMenu?: boolean; - showNoContent?: boolean; - linkDefaultTarget?: string; - i18nText: any; - linkType: 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | ''; -} -export interface AccordionOptions extends AccordionConfigOptions, AccordionMenuKeyGroup, AccordionTemplateRefGroup {} -``` - -## AccordionMenuToggleEvent - -``` typescript -export type AccordionMenuToggleEvent = { - item: any; - open: boolean; - parent: any; - event: MouseEvent; -}; -``` - -## AccordionItemClickEvent - -``` typescript -export type AccordionItemClickEvent = { - item: any; - prevActiveItem?: any; - parent: any; - event: MouseEvent; -}; -``` - -### 模板可以用变量值 - -#### 变量使用方法 - -```html -{{myitem}} -``` - -#### menuItemTemplate 可用变量值 - -| 变量 | 类型 | 变量含义说明 | -| :----------------: | :--------: | :-----------------------------------------------: | -| item | `any` | 可展开类型菜单数据 | -| deepth | `number` | 表示嵌套结构层级 | -| parent | `any` | 所属父级菜单数据 | -| ~~~titleKey~~~ | `string` | `已经废弃`~~~组件的 titleKey 值~~~ | -| ~~~disabledKey~~~ | `string` | `已经废弃`~~~组件的 disabledKey 值~~~ | -| ~~~openKey~~~ | `string` | `已经废弃`~~~组件的 openKey 值~~~ | -| ~~~menuToggleFn~~~ | `Function` | `已经废弃`~~~参数应为 item,表示一级菜单被点击~~~ | - -#### itemTemplate 可用变量值 - -| 变量 | 类型 | 变量含义说明 | -| :---------------: | :--------: | :-----------------------------------------------: | -| item | `any` | 可点击类型菜单数据 | -| deepth | `number` | 值表示嵌套结构层级 | -| parent | `any` | 所属父级菜单数据 | -| ~~~titleKey~~~ | `string` | `已经废弃`~~~ 组件的 titleKey 值~~~ | -| ~~~disabledKey~~~ | `string` | `已经废弃`~~~ 组件的 disabledKey 值~~~ | -| ~~~activeKey~~~ | `string` | `已经废弃`~~~ 组件的 activeKey 值~~~ | -| ~~~itemClickFn~~~ | `Function` | `已经废弃`~~~参数应为 item,表示二级菜单被点击~~~ | - -#### noContentTemplate 可用变量值 - -| 变量 | 类型 | 变量含义说明 | -| :----: | :------: | :----------------: | -| item | `any` | 父级菜单单个数据 | -| deepth | `number` | 值表示嵌套结构层级 | - -#### loadingTemplate 可用变量值 - -| 变量 | 类型 | 变量含义说明 | -| :--------------: | :------: | :------------------------: | -| item | `any` | 父级菜单单个数据 | -| deepth | `number` | 值表示嵌套结构层级 | -| ~~~loadingKey~~~ | `string` | ~~~组件的 loadingKey 值~~~ | - -#### innerListTemplate 可用变量值 - -| 变量 | 类型 | 变量含义说明 | -| :---------------: | :--------: | :----------------------------------------------------------------: | -| item | `any` | 父级菜单单个数据 | -| deepth | `number` | 值表示嵌套结构层级 | -| ~~~titleKey~~~ | `string` | `已经废弃`~~~组件的 titleKey 值~~~ | -| ~~~loadingKey~~~ | `string` | `已经废弃`~~~组件的 loadingKey 值~~~ | -| ~~~childrenKey~~~ | `string` | `已经废弃`~~~组件的 childrenKey 值~~~ | -| ~~~disabledKey~~~ | `string` | `已经废弃`~~~组件的 disabledKey 值~~~ | -| ~~~openKey~~~ | `string` | `已经废弃`~~~组件的 openKey 值~~~ | -| ~~~activeKey~~~ | `string` | `已经废弃`~~~组件的 activeKey 值,用二级菜单~~~ | -| menuToggleFn | `Function` | 参数应为 item,表示菜单被展开,可选参数 event,原始事件 | -| itemClickFn | `Function` | 参数应为可点击菜单的 item,表示菜单被点击,可选参数 event,原始事件 | diff --git a/devui/accordion/doc/api-en.md b/devui/accordion/doc/api-en.md deleted file mode 100644 index e6467537d0eea5b76a05c9e600dc1c8320403e63..0000000000000000000000000000000000000000 --- a/devui/accordion/doc/api-en.md +++ /dev/null @@ -1,189 +0,0 @@ -# How to use - -Import into module: - -```typescript -import { AccordionModule } from ' ng-devui/accordion'; -``` - -On the page: - -```html - -``` - -## Accordion - -### d-accordion parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------: | :----------------------------------------------------: | :--------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------------------- | -| data | `Array \| AccordionMenuType` | -- | Required. Data source. You can customize an array or use the preset `AccordionMenuType` | [Basic usage](demo#basic-usage) | -| titleKey | `string` | 'title' | Optional. Title attribute name. The type of item[titleKey] is `string`, indicating the title content. | [Change key value](demo#change-values) | -| loadingKey | `string` | 'loading' | Optional. attribute name for determining whether a submenu is loaded. The type of item[loadingKey] is `boolean` | [Change key value](demo#change-values) | -| childrenKey | `string` | 'children' | Optional. Submenu attribute name. The type of item[childrenKey] is `Array` | [Change key value](demo#change-values) | -| disabledKey | `string` | 'disabled' | Optional. indicating whether to disable the attribute. The type of item[disabledKey] is `boolean` | [Change key value](demo#change-values) | -| activeKey | `string` | 'active' | Optional. indicating whether a submenu is activated. The type of item[activeKey] is `boolean` | [Change key value](demo#change-values) | -| openKey | `string` | 'open' | Optional. indicating whether a menu is expanded. The type of item[openKey] is `boolean` | [Change key value](demo#change-values) | -| restrictOneOpen | `boolean` | false | Optional. Only one level-1 menu can be opened at a time. By default, there is no restriction. | [Basic usage](demo#basic-usage) | -| menuItemTemplate | `TemplateRef` | Built-in | Optional. It can expand the menu content bar template. The available variable values are as follows. | [Using a Template](demo#using-templates) | -| itemTemplate | `TemplateRef` | Built-in | Optional. The menu content bar template can be clicked. The available variable values are as follows: | [Using a Template](demo#using-templates) | -| noContentTemplate | `TemplateRef` | Built-in | Optional. If there is no content, use a customized template. The available variable values are as follows: | [Using a Template](demo#using-templates) | -| loadingTemplate | `TemplateRef` | Built-in | Optional. A customized template is used for loading. The available variable values are as follows | [Using a Template](demo#using-templates) | -| innerListTemplate | `TemplateRef` | Built-in | Optional. The sublist content is customized and used as a folding panel. The available variable values are as follows. | [Using a Template](demo#using-templates) | -| linkType | `'routerLink'\|'hrefLink'\|'dependOnLinkTypeKey'\|'''` | '' | Optional. `routerLink'` indicates the routing scenario. `hrefLink'` indicates the external link scenario. `dependOnLinkTypeKey'` indicates the dynamic routing or external link scenario. `''` is the default non-link type (you cannot right-click to open a new tab page) | [Built-in route and link type](demo#use-built-in-routing-and-link-types) | -| linkTypeKey | `string` | 'linkType' | Optional. Key value of the link type, which is used to specify the object link type attribute name when linkType is set to `'dependOnLinkTypeKey'`. The value of item[linkTypeKey] is `'routerLink'\|'hrefLink'\| string`, in the preceding information, `routerLink'` indicates a route link, `hrefLink'` indicates an external link, and other values are default non-link types. | -| linkKey | `string` | 'link' | Optional. Key of the link content, which is used to set the value of the link value when linkType is not set to ````. item[linkKey] indicates the route address or hyperlink address. | -| linkTargetKey | `string` | 'target' | Optional. Key of the target window to be linked, which is used for the link type. item[linkTargetKey] indicates the target window of a single link. | -| linkDefaultTarget | `string` | '\_self' | Optional. If target is not set, the default value of target is `'\_self'`, which is used for the link type and its value is the same as that of target attribute of link a. | [Built-in route and link type](demo#use-built-in-routing-and-link-types) | -| autoOpenActiveMenu | `boolean` | false | Optional. Whether to automatically expand menus with active subitems | [Composite Hierarchy and Auto Expand](demo#compound-level-and-auto-expand) | -| accordionType | `normal ' \| 'embed'` | 'normal' | Optional. The menu format is common (with shadow) or embedded (without shadow). | [Basic usage](demo#basic-usage) | -| showAnimation | `boolean` | true | Optional. Indicating whether to display animations. | [Built-in route and link type](demo#use-built-in-routing-and-link-types) | - -### d-accordion event - -| Event | Type | Description | Jump to Demo | -| :--------------: | :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ------------------------------- | -| menuToggle | `EventEmitter<`[`AccordionMenuToggleEvent`](#accordionmenutoggleevent)`>` | Optional. The menu can be expanded. In the returned object, the attribute item is the object data clicked. If open is true, the object will be expanded. If open is false, the object will be closed. If parent is the parent object data. Event is the native event of the click event. | [Basic usage](demo#basic-usage) | -| itemClick | `EventEmitter<`[`AccordionItemClickEvent`](#accordionitemclickevent)`>` | Optional. It can click a menu event. In the returned object, the attribute item is the object data of the clicked object, the preActive object is the object expanded last time, the parent object is the data of the parent object, and the event is the native event of the click event. | [Basic usage](demo#basic-usage) | -| activeItemChange | `EventEmitter` | Optional. Data of the newly activated sub-item is sent when the sub-item is switched. | [Basic usage](demo#basic-usage) | - -### AccordionMenuType Definition - -```typescript -/* Basic data type */ -type AccordionMenuItemLinkType = 'routerLink' | 'hrefLink' | string; -export interface AccordionBase { - title: string; - disabled?: boolean; - [prop: string]: any; -} -interface IAccordionActiveable { - active?: boolean; -} -interface IAccordionFoldable { - open?: boolean; - loading?: boolean; - children?: Array; -} -interface IAccordionLinkable { - link?: string; - target?: boolean; - linkType?: AccordionMenuItemLinkType; -} -export interface AccordionBaseItem extends AccordionBase, IAccordionActiveable {} -export interface AccordionBaseMenu extends AccordionBase, IAccordionFoldable {} -export interface AccordionLinkableItem extends AccordionBase, IAccordionActiveable, IAccordionLinkable {} -export interface AccordionMenuItem extends AccordionBase, IAccordionActiveable, IAccordionFoldable, IAccordionLinkable {} -export type AccordionMenuType = Array; - -/* Common configuration data type */ -interface AccordionMenuKeyGroup { - titleKey?: string; - activeKey?: string; - disabledKey?: string; - openKey?: string; - loadingKey?: string; - childrenKey?: string; - linkKey?: string; - linkTargetKey?: string; - linkTypeKey?: string; -} -type AccordionTemplateRefArray = 'itemTemplate' | 'menuItemTemplate' | 'noContentTemplate' | 'loadingTemplate' | 'innerListTemplate'; -type AccordionTemplateRefGroup = { - [p in AccordionTemplateRefArray]: TemplateRef; -}; -interface AccordionConfigOptions { - restrictOneOpen?: boolean; - autoOpenActiveMenu?: boolean; - showNoContent?: boolean; - linkDefaultTarget?: string; - i18nText: any; - linkType: 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | ''; -} -export interface AccordionOptions extends AccordionConfigOptions, AccordionMenuKeyGroup, AccordionTemplateRefGroup {} -``` - -## AccordionMenuToggleEvent - -```typescript -export type AccordionMenuToggleEvent = { - item: any; - open: boolean; - parent: any; - event: MouseEvent; -}; -``` - -## AccordionItemClickEvent - -```typescript -export type AccordionItemClickEvent = { - item: any; - prevActiveItem?: any; - parent: any; - event: MouseEvent; -}; -``` - -### Templates can use variable values. - -#### Variable Usage - -```html -{{myitem}} -``` - -#### menuItemTemplate Available variable values - -| Variable | Type | Variable Description | -| :----------------: | :--------: | :------------------------------------------------------------------------------------------: | -| item | `any` | Expandable menu data | -| deepth | `number` | Indicates the nested structure level. | -| parent | `any` | Parent menu data | -| ~~~titleKey~~~ | `string` | Deprecated.~~~ The titleKey value of the component. ~~~ | -| ~~~disabledKey~~~ | `string` | Deprecated. ~~~ The value of the disabledKey of the component. ~~~ | -| ~~~openKey~~~ | `string` | Deprecated. ~~~ The openKey value of the component. ~~~ | -| ~~~menuToggleFn~~~ | `Function` | Deprecated.~~~ The parameter should be item, indicating that the level-1 menu is clicked.~~~ | - -#### itemTemplate Available variable values - -| Variable | Type | Variable Description | -| :---------------: | :--------: | :------------------------------------------------------------------------------------------: | -| item | `any` | Clickable menu data | -| deepth | `number` | The value indicates the nested structure level. | -| parent | `any` | Parent menu data | -| ~~~titleKey~~~ | `string` | Deprecated.~~~ The titleKey value of the component ~~~ | -| ~~~disabledKey~~~ | `string` | Deprecated.~~~ The value of the disabledKey of the component ~~~ | -| ~~~activeKey~~~ | `string` | Deprecated.~~~ The activeKey value of the component ~~~ | -| ~~~itemClickFn~~~ | `Function` | Deprecated. ~~~The parameter should be item, indicating that the level-2 menu is clicked.~~~ | - -#### noContentTemplate Available variable value - -| Variable | Type | Variable Description | -| :------: | :------: | :---------------------------------------------: | -| item | `any` | Parent menu single data | -| deepth | `number` | The value indicates the nested structure level. | - -#### loadingTemplate Available variable values - -| Variable | Type | Variable Description | -| :---------------------: | :--------------: | :---------------------------------------------: | -| item | `any` | Parent menu single data | -| deepth | `number` | The value indicates the nested structure level. | -| LoadingKey value of the | ~~~loadingKey~~~ | `string` | ~~~ component ~~~ | - -#### InnerListTemplate Available Variable Values - -| Variable | Type | Variable Description | -| :---------------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: | -| item | `any` | Parent menu single data | -| deepth | `number` | The value indicates the nested structure level. | -| ~~~titleKey~~~ | `string` | Deprecated.~~~The titleKey value of the component ~~~ | -| ~~~loadingKey~~~ | `string` | Deprecated.~~~ The loading key value of the component ~~~ | -| ~~~childrenKey~~~ | `string` | Deprecated.~~~ The value of childrenKey of the component ~~~ | -| ~~~disabledKey~~~ | `string` | Deprecated.~~~ The value of the disabledKey of the component ~~~ | -| ~~~openKey~~~ | `string` | Deprecated.~~~ The openKey value of the component ~~~ | -| ~~~activeKey~~~ | `string` | Deprecated. ~~~ The activeKey value of the component Use the level-2 menu ~~~ | -| menuToggleFn | `Function` | The parameter should be item, indicating that the menu is expanded. The optional parameter event, original event, is used. | -| itemClickFn | `Function` | The parameter must be an item of a menu that can be clicked, indicating that the menu is clicked. The optional parameter event, original event, is used. | diff --git a/devui/alert/demo/alert.route.ts b/devui/alert/demo/alert.route.ts deleted file mode 100644 index 2ac85e3629e4738060bd247e08954e03f6066880..0000000000000000000000000000000000000000 --- a/devui/alert/demo/alert.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import AlertDemoComponent from './alert-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: AlertDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/alert/doc/api-cn.md b/devui/alert/doc/api-cn.md deleted file mode 100644 index f0e41dd9f39bb98a4c961625609b247cad376799..0000000000000000000000000000000000000000 --- a/devui/alert/doc/api-cn.md +++ /dev/null @@ -1,38 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { AlertModule } from 'ng-devui/alert'; -``` - -在页面中使用: - -```xml - -``` -# d-alert -## d-alert 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :--------------------------------------: | :----: | :---------------------------------------- | ------------------------------------------ | -| type | [`AlertType`](#alerttype) | 'info' | 必选,指定警告提示的样式 | [基本用法](demo#basic-usage) | -| cssClass | `string` | -- | 可选,自定义 class 名 | -| closeable | `boolean` | true | 可选,默认显示关闭按钮 | [基本用法](demo#tips-to-close) | -| dismissTime | `number` | -- | 可选,自动关闭 alert 的延迟时间(`ms`) | -| showIcon | `boolean` | true | 可选,是否使用默认的类型图标 | [不使用默认图标](demo#without-icon) | - -## d-alert 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :--------: | :-----------------: | :------------------------- | -------------------------------------------- | -| closeEvent | `EventEmitter` | 可选,关闭时触发的回调函数 | [可关闭的提示](demo#tips-to-close) | - -# 接口 & 类型定义 -### AlertType - -默认值为'info', 指定alert警告提示的类型 - -```ts -export type AlertType = 'success' | 'danger' | 'warning' | 'info'; -``` \ No newline at end of file diff --git a/devui/alert/doc/api-en.md b/devui/alert/doc/api-en.md deleted file mode 100644 index 58701b5b7fdfa2430a5c96eee0800d76b20620d7..0000000000000000000000000000000000000000 --- a/devui/alert/doc/api-en.md +++ /dev/null @@ -1,38 +0,0 @@ -# How to use - -Import into module: - -```ts -import { AlertModule } from 'ng-devui/alert'; -``` - -In the page: - -```xml - -``` -# d-alert -## d-alert Parameter - -| Attributes | Type | Default | Description | Jump to Demo | -| :---------: | :--------------------------------------: | :----: | :---------------------------------------- | ------------------------------------------ | -| type | [`AlertType`](#alerttype) | 'info' | Required. Specify the style of the warning prompt | [Basic Usage](demo#basic-usage) | -| cssClass | `string` | -- | Optional. Customize className | -| closeable | `boolean` | true | Optional. The close button is displayed by default | [Basic Usage](demo#tips-to-close) | -| dismissTime | `number` | -- | Optional. Toggle off the delay time of Alert(`ms`) | -| showIcon | `boolean` | true | Optional. Whether to use the default type icon | [Without Icon](demo#without-icon) | - -## d-alert Event - -| Attributes | Type | Description | Jump to Demo | -| :--------: | :-----------------: | :------------------------- | -------------------------------------------- | -| closeEvent | `EventEmitter` | Optional. Callback when alert is closed | [Closable Prompt](demo#tips-to-close) | - -# Interface & Type Definition -### AlertType - -The default value is 'info', which specifies the type of alert warning. - -```ts -export type AlertType = 'success' | 'danger' | 'warning' | 'info'; -``` \ No newline at end of file diff --git a/devui/anchor/anchor.tsx b/devui/anchor/anchor.tsx deleted file mode 100644 index 6a7920becb16ff4db7b510c2a6c08aff9bdd6eab..0000000000000000000000000000000000000000 --- a/devui/anchor/anchor.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-anchor', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-anchor
- } - } -}) \ No newline at end of file diff --git a/devui/anchor/demo/anchor-demo.tsx b/devui/anchor/demo/anchor-demo.tsx deleted file mode 100644 index d976d45d5b531c1abd426e034c50ef5296f55dd5..0000000000000000000000000000000000000000 --- a/devui/anchor/demo/anchor-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-anchor-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-anchor-demo
- } - } -}) \ No newline at end of file diff --git a/devui/anchor/demo/anchor.route.ts b/devui/anchor/demo/anchor.route.ts deleted file mode 100644 index 3559e13052b2b72b21063a3108d8e55437293b67..0000000000000000000000000000000000000000 --- a/devui/anchor/demo/anchor.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import AnchorDemoComponent from './anchor-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: AnchorDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/anchor/doc/api-cn.md b/devui/anchor/doc/api-cn.md deleted file mode 100644 index 601316e484ceade4f1bb1a502ce70ab9564fb57f..0000000000000000000000000000000000000000 --- a/devui/anchor/doc/api-cn.md +++ /dev/null @@ -1,123 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { AnchorModule } from 'ng-devui'; -``` - -在页面中使用: - -```html -
-
    -
  • anchorlink-one
  • -
  • anchorlink-two
  • -
  • anchorlink-three
  • -
  • anchorlink-four
  • -
-
-
- anchorlink-one -
-
- anchorlink-two -
-
- anchorlink-three -
-
- anchorlink-four -
-
-
-``` - -```ts -// using router (cross-route), anchorName means your own anchor -this.router.navigateByUrl('../xx/xxx#anchorName'); -this.router.navigate(['/xxx'], { fragment: 'anchorName' }); - -// using router (at the same level), anchorName means your own anchor -this.router.navigateByUrl('#anchorName'); -this.router.navigate([], { fragment: 'anchorName' }); -``` -# dAnchor - -定义一个锚点。 -## dAnchor 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :------: | :--: | :---------------------------------------------------: | ---------------------------- | -| dAnchor | `string` | -- | 必选,设置一个锚点的名字 | [基本用法](demo#basic-usage) | -| anchorActive | `string` | -- | 可选,锚点处于激活状态的时候,模块生效对应的 css 类名 | [基本用法](demo#basic-usage) | - -## dAnchor 锚点激活事件 - -自动会给锚点加上以下类对应不同激活的对象。 - -| css 类名 | 代表意义 | -| :---------------------------: | :--------------------: | -| anchor-active-by-anchor-link | 点击锚点链接激活 | -| anchor-active-by-scroll | 容器滚动到锚点位置激活 | -| anchor-active-by-click-inside | 点击锚点内部内容激活 | -| anchor-active-by-initial | 初始化滚动条位置激活 | - -# dAnchorLink - -定义一个锚点的链接,点击链接会滑动到锚点,锚点处于页面顶部的时候也会激活链接的 class。 - -## dAnchorLink 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :------: | :--: | :---------------------------------------------------: | ---------------------------- | -| dAnchorLink | `string` | -- | 必选,点击滑动的目标锚点的名字 | [基本用法](demo#basic-usage) | -| anchorActive | `string` | -- | 可选,锚点处于激活状态的时候,链接生效对应的 css 类名 | [基本用法](demo#basic-usage) | - -# dAnchorBox - -必须有一个容器,否则功能无法使用。 - -定义一个扫描锚点的容器,放在 dAnchor 与 dAnchorLink 的公共父节点上,用于锚点和链接之间的通信。 - -## dAnchorBox 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :----------------------------: | :-------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------: | ---------------------------------- | -| view | `{top?:number,bottom?:number}` | {top:0,bottom:0} | 可选,用于可视区域的调整,比如顶部有固定位置的头部等,数值对应被遮挡的顶部或底部的高度 | [基本用法](demo#basic-usage) | -| defaultAnchor | `string` | -- | 可选,进入页面后默认被激活的锚点链接,一般设置为第一个锚点,如果不设置,那么第一个锚点需要在滑动到顶部位置的时候才能激活链接 | [基本用法](demo#basic-usage) | -| scrollTarget | `HTMLElement` | document.documentElement(document.body) | 可选,设置要发生滚动的容器,一般为滚动条所在容器,为主页面的滚动条时候可以不设置 | [更换滚动容器](demo#scroll-target) | - -# dAnchorHashSupport - -dAnchorBox 辅助指令。 -## dAnchorHashSupport 参数 - -以下参数为高级配置参数,一般不需要使用,只需要直接使用 dAnchorHashSupport。 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------------------: | :-------: | :---: | :-----------------------------------------------------------------------------------: | ---------------------------------- | -| updateUrlWhenAnchorActive | `boolean` | true | 可选,当激活 anchor 的时候更新 url,用于处理复杂场景, 默认为 true 即可 | [支持 url 锚点](demo#support-hash) | -| scrollToAnchorByHashOnlyInit | `boolean` | false | 可选,true 为只有初始化的时候接收来自路由的 fragment 字段变化并接收,用于处理复杂场景 | [支持 url 锚点](demo#support-hash) | - -dAnchorHashSupport 指令搭配 dAnchorBox 使用, 可以绑定路由的 hash fragment, 举例 xxx.xxx/xxx#foo, foo 字段为哈希字段。 -跳转哈希字段可以使用 anchor 组件,路由 navigate,routerLink 的 fragment 字段等。 - -# 注意事项 - -注意不可和 ng6.1 以上路由模块自带的 RouterScoller 混用, routerlScroller 会滚动到传统的 id 锚点。 -单独使用 RouterScroller 可以通过配置路由模块。 - -```ts -@NgModule({ - // ...... - imports: [ - // ...... - RouterModule.forRoot(routes, { - anchorScrolling: 'enabled', // 该策略与锚点组件的dAnchorHashSupport指令相冲突 - }), - ], - // ...... -}) -export class DemoModule {} -``` diff --git a/devui/anchor/doc/api-en.md b/devui/anchor/doc/api-en.md deleted file mode 100644 index f44c25a2ae103cffbfd5b50e2b5cfcffdd5835fb..0000000000000000000000000000000000000000 --- a/devui/anchor/doc/api-en.md +++ /dev/null @@ -1,126 +0,0 @@ -# How to use - -Import into module: - -```ts -import { AnchorModule } from 'ng-devui'; -``` - -In the page: - -```html -
-
    -
  • anchorlink-one
  • -
  • anchorlink-two
  • -
  • anchorlink-three
  • -
  • anchorlink-four
  • -
-
-
- anchorlink-one -
-
- anchorlink-two -
-
- anchorlink-three -
-
- anchorlink-four -
-
-
-``` - -```ts -// using router (cross-route), anchorName means your own anchor -this.router.navigateByUrl('../xx/xxx#anchorName'); -this.router.navigate(['/xxx'], { fragment: 'anchorName' }); - -// using router (at the same level), anchorName means your own anchor -this.router.navigateByUrl('#anchorName'); -this.router.navigate([], { fragment: 'anchorName' }); -``` - -# dAnchor - -Define an anchor point - -## dAnchor Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :------: | :-----: | :---------------------------------------------------------------------------------------------------: | -------------------------------------------------- | -| dAnchor | `string` | -- | Required. Sets an anchor name. | [Basic Usage](demo#basic-usage) | -| anchorActive | `string` | -- | Optional. When the anchor is activated, the corresponding CSS class name takes effect for the module. | [Basic Usage](demo#basic-usage) | - -## dAnchor Anchor Activation Event - -The following classes are automatically added to the anchor to correspond to different activated objects: - -| css class name | Meaning | -| :---------------------------: | :-------------------------------------------------------: | -| anchor-active-by-anchor-link | Click the anchor link to activate it. | -| anchor-active-by-scroll | The container scrolls to the anchor point for activation. | -| anchor-active-by-click-inside | Click the anchor content to activate it. | -| anchor-active-by-initial | Initialize the scroll bar position. | - -# dAnchorLink - -Define a link of an anchor point. Click the link to slide to the anchor point. When the anchor point is at the top of the page, the link class is activated. - -## dAnchorLink Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :------: | :-----: | :------------------------------------------------------------------------------------------------: | -------------------------------------------------- | -| dAnchorLink | `string` | -- | Required. Name of the target anchor point for sliding. | [Basic Usage](demo#basic-usage) | -| anchorActive | `string` | -- | Optional. CSS class name corresponding to the link that takes effect when the anchor is activated. | [Basic Usage](demo#basic-usage) | - -# dAnchorBox - -There must be one container. Otherwise, the function cannot be used. - -Defines a container for scanning anchor points, placed on the common parent node of dAnchor and dAnchorLink, for communication between anchor points and links. - -## dAnchorBox Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------: | :----------------------------: | :-------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | --------------------------------------------------------------------- | -| view | `{top?:number,bottom?:number}` | {top:0,bottom:0} | Optional. It is used to adjust the visible region, for example, the head with a fixed position on the top. The value corresponds to the height of the blocked top or bottom. | [Basic Usage](demo#basic-usage) | -| defaultAnchor | `string` | -- | Optional. An anchor link that is activated by default after a page is displayed. Generally, the first anchor link is set to the first anchor link. If this parameter is not set, the first anchor link can be activated only when the first anchor is moved to the top position. | [Basic Usage](demo#basic-usage) | -| scrollTarget | `HTMLElement` | document.documentElement(document.body) | Optional. Sets the container where the scroll bar is located. This parameter is optional when the scroll bar is on the home page. | [Replace Rolling Container](demo#scroll-target) | - -# dAnchorHashSupport - -dAnchorBox support instruction - -## dAnchorHashSupport Parameters - -The following parameters are advanced configuration parameters and are not required. You only need to use dAnchorHashSupport. - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------------: | :-------: | :-----: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------ | -| updateUrlWhenAnchorActive | `boolean` | true | Optional. The URL is updated when the anchor is activated. The default value is true. | [URL Hash Anchor](demo#support-hash) | -| scrollToAnchorByHashOnlyInit | `boolean` | false | Optional. True indicates that the fragment field changes from routes are received only during initialization. This field is used for complex scenarios. | [URL Hash Anchor](demo#support-hash) | - -The dAnchorHashSupport command is used together with the dAnchorBox command to bind the hash fragment of a route. For example, xxx.xxx/xxx#foo, where the foo field is a hash field. -The hop hash field can be the anchor component, route navigate, and routerLink fragment field. - -# Note - -Note that this parameter cannot be used together with the RouterScoller of the routing module of ng6.1 or later. The routerlScroller will scroll to the traditional ID anchor point. -Using RouterScroller alone, you can configure the routing module. - -```ts -@NgModule({ - //...... - imports: [ - //...... - RouterModule.forRoot(routes, { - anchorScrolling: 'enabled', // This policy conflicts with the dAnchorHashSupport instruction of the anchor component. - }), - ], - //...... -}) -export class DemoModule {} -``` diff --git a/devui/auto-complete/auto-complete.tsx b/devui/auto-complete/auto-complete.tsx deleted file mode 100644 index 95159c6b3cbc2eee124a88c3076d1786869bea65..0000000000000000000000000000000000000000 --- a/devui/auto-complete/auto-complete.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-auto-complete', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-auto-complete
- } - } -}) \ No newline at end of file diff --git a/devui/auto-complete/demo/auto-complete-demo.tsx b/devui/auto-complete/demo/auto-complete-demo.tsx deleted file mode 100644 index e5d44d8b9c29c8f15f166b0498d296c06fc035e9..0000000000000000000000000000000000000000 --- a/devui/auto-complete/demo/auto-complete-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-auto-complete-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-auto-complete-demo
- } - } -}) \ No newline at end of file diff --git a/devui/auto-complete/demo/auto-complete.route.ts b/devui/auto-complete/demo/auto-complete.route.ts deleted file mode 100644 index bd1eea2cb200a02028573cd13737cdd5c72dac19..0000000000000000000000000000000000000000 --- a/devui/auto-complete/demo/auto-complete.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import AutoCompleteDemoComponent from './auto-complete-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: AutoCompleteDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/auto-complete/doc/api-cn.md b/devui/auto-complete/doc/api-cn.md deleted file mode 100644 index 8173d6e9bbf5d5cc18ad328ff1c64596e65ca4d1..0000000000000000000000000000000000000000 --- a/devui/auto-complete/doc/api-cn.md +++ /dev/null @@ -1,64 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { AutoCompleteModule } from 'ng-devui/auto-complete'; -``` -在页面中使用: -```html - -``` - -# dAutoComplete -## dAutoComplete 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------------------: | :-------------------------------: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | -| source | `Array` | -- | 必选,有 searchFn 的情况下可以不必选 | [基本用法](demo#basic-usage) | -| allowEmptyValueSearch | `boolean` | false | 可选,在绑定的输入框 value 为空时,是否进行搜索提示操作 | [自定义模板展示](demo#auto-custom) | -| appendToBody | `boolean` | false | 可选,下拉弹出是否 append to body | [自定义模板展示](demo#auto-custom) | -| disabled | `boolean` | false | 可选,是否禁止指令 | [设置禁用](demo#auto-disable) | -| delay | `number` | 300 | 可选,只有在 delay 时间经过后并且输入新值,才做搜索查询(`ms`) | [自定义模板展示](demo#auto-custom) | -| disabledKey | `string` | -- | 可选,禁用单个选项,当传入资源 source 选项类型为对象,比如设置为'disabled',则当对象的 disable 属性为 true 时,比如{ label: xxx, disabled: true },该选项将禁用 | [设置禁用](demo#auto-disable) | -| itemTemplate | `TemplateRef` | -- | 可选,自定义展示模板 | [自定义模板展示](demo#auto-custom) | -| noResultItemTemplate | `TemplateRef` | -- | 可选,没有匹配项的展示结果 | [自定义模板展示](demo#auto-custom) | -| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | 可选,格式化函数 | [设置禁用](demo#auto-disable) | -| isSearching | `boolean` | false | 可选,是否在搜索中,用于控制 searchingTemplate 是否显示 | [自定义模板展示](demo#auto-custom) | -| searchingTemplate | `TemplateRef` | -- | 可选,自定义搜索中显示模板 | [自定义模板展示](demo#auto-custom) | -| sceneType | `string` | -- | 可选,值为 'select'、'suggest' | [启用懒加载](demo#auto-lazy-load) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | 可选,自定义搜索过滤 | [自定义数据匹配方法](demo#auto-object) | -| tipsText | `string` | '最近输入' | 可选,提示文字 | [设置禁用](demo#auto-disable) | -| latestSource | `Array` | -- | 可选, 最近输入 | [最近输入](demo#auto-latest) | -| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | 可选, 对选中后数据进行处理 | [启用懒加载](demo#auto-lazy-load) | -| enableLazyLoad | `boolean` | false | 可选,是否允许懒加载 | [启用懒加载](demo#auto-lazy-load) | -| dAutoCompleteWidth | `number` | -- | 可选,调整宽度(`px`) | - -## dAutoComplete 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :-----------------: | :-------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------- | -| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [启用懒加载](demo#auto-lazy-load) | -| selectValue | `EventEmitter` | 可选,选择选项之后的回调函数 | [启用懒加载](demo#auto-lazy-load) | -| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | 可选,Input focus 时回调函数 | [启用懒加载](demo#auto-lazy-load) | - -# 接口 & 类型定义 -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { - return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` -term 为输入的关键字。 - -### defaultFormatter -```ts -defaultFormatter = (item) => (item ? item.label || item.toString() : ''); -``` -item 为数据项。 - -### defaultValueParse -```ts -defaultValueParse = (item) => item; -``` -item 为数据项。 - diff --git a/devui/auto-complete/doc/api-en.md b/devui/auto-complete/doc/api-en.md deleted file mode 100644 index f47e9f3a307d4b761063733b4339cb2b8a361451..0000000000000000000000000000000000000000 --- a/devui/auto-complete/doc/api-en.md +++ /dev/null @@ -1,74 +0,0 @@ -# How to use - -Import into module - -```ts -import { AutoCompleteModule } from 'ng-devui/auto-complete'; -``` - -In the page - -```html - -``` - -# dAutoComplete - -## dAutoComplete Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------------: | :-----------------------------------: | :---------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -| source | `Array` | -- | Required. This parameter is optional if searchFn is specified. | [Basic usage](demo#basic-usage) | -| allowEmptyValueSearch | `boolean` | false | Optional. indicates whether to display a search message when the bound text box value is empty. | [Customized template display](demo#auto-custom) | -| appendToBody | `boolean` | false | Optional. Whether to append to body is displayed in the drop-down list box. | [Customized template display](demo#auto-custom) | -| disabled | `boolean` | false | Optional. Indicating whether to disable commands. | [Disabled](demo#auto-disable) | -| delay | `number` | 300 | Optional. The search is performed only after the delay time elapses and a new value is entered. (`ms`) | [Customized template display](demo#auto-custom) | -| disabledKey | `string` | -- | Optional. Disable a single option. If the input resource source option type is an object, for example, disabled, and the disable attribute of the object is true, for example, {label: xxx, disabled: true}, this option will be disabled | [Disabled](demo#auto-disable) | -| itemTemplate | `TemplateRef` | -- | Optional. Customized display template | [Customized template display](demo#auto-custom) | -| noResultItemTemplate | `TemplateRef` | -- | Optional. No matching item is displayed. | [Customized template display](demo#auto-custom) | -| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | Optional. Formatting function | [Disabled](demo#auto-disable) | -| isSearching | `boolean` | false | Optional. indicating whether the search template is displayed. | [Customized template display](demo#auto-custom) | -| searchingTemplate | `TemplateRef` | -- | Optional. The template is displayed in customized search. | [Customized template display](demo#auto-custom) | -| sceneType | `string` | -- | Optional. The value can be select or suggestion. | [Enable lazy load](demo#auto-lazy-load) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | Optional. Customized search filtering | [Customized data matching method](demo#auto-object) | -| tipsText | `string` | 'Latest input' | Optional. prompt text | [Disabled](demo#auto-disable) | -| latestSource | `Array` | -- | Optional. Latest input | [Latest input](demo#auto-latest) | -| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | (optional) Process selected data | [Enable lazy load](demo#auto-lazy-load) | -| enableLazyLoad | `boolean` | false | Optional. Whether lazy loading is allowed | [Enable lazy load](demo#auto-lazy-load) | -| dAutoCompleteWidth | `number` | -- | Optional. Adjust the width (`px`) | - -## dAutoComplete Event - -| Parameter | Type | Description | Jump to Demo | -| :-----------------: | :----------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------- | -| loadMore | `EventEmitter>` | : optional. It is a lazy loading trigger event. It is used together with enableLazyLoad. \`$event.loadFinish()\` is used to disable the loading status. $event is the instance of the pop-up component AutoCompletePopupComponent | [Enable lazy load](demo#auto-lazy-load) | -| selectValue | `EventEmitter` | (optional), callback function after selecting an option | [Enable lazy load](demo#auto-lazy-load) | -| transInputFocusEmit | `EventEmitter<{focus: boolean, popupRef: ComponentRef}>` | (optional). Callback function for input focus | [Enable lazy load](demo#auto-lazy-load) | - -# Interface & Type Definition - -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { - return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` - -term indicates the entered keyword. - -### defaultFormatter - -```ts -defaultFormatter = (item) => (item ? item.label || item.toString() : ''); -``` - -item indicates a data item. - -### defaultValueParse - -```ts -defaultValueParse = (item) => item; -``` - -item indicates a data item. diff --git a/devui/avatar/avatar.tsx b/devui/avatar/avatar.tsx deleted file mode 100644 index 9d3d0fb1e5595472a37c50d2ca0c4c1358a2a3bd..0000000000000000000000000000000000000000 --- a/devui/avatar/avatar.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-avatar', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-avatar
- } - } -}) \ No newline at end of file diff --git a/devui/avatar/demo/avatar-demo.tsx b/devui/avatar/demo/avatar-demo.tsx deleted file mode 100644 index deea987d7a727e4f430fe9d4c4b2e8c42a41e83a..0000000000000000000000000000000000000000 --- a/devui/avatar/demo/avatar-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-avatar-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-avatar-demo
- } - } -}) \ No newline at end of file diff --git a/devui/avatar/demo/avatar.route.ts b/devui/avatar/demo/avatar.route.ts deleted file mode 100644 index 72dd63b30e31b99871ea13ec8065d4d2c1727b6f..0000000000000000000000000000000000000000 --- a/devui/avatar/demo/avatar.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import AvatarDemoComponent from './avatar-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: AvatarDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/avatar/doc/api-cn.md b/devui/avatar/doc/api-cn.md deleted file mode 100644 index edc114bc88b0f79f613e7dd786ba6e5a477944e4..0000000000000000000000000000000000000000 --- a/devui/avatar/doc/api-cn.md +++ /dev/null @@ -1,42 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { AvatarModule } from 'ng-devui/avatar'; -``` - -在页面中使用: - -```xml - -``` - -# d-avatar -## d-avatar 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :--------: | :--------------------: | :--: | :-------------------------------------------------------------------------- | ------------------------------------------------------------- | -| name | `string` | -- | 必选,传入字符串用于制作头像 | [头像显示的基本规则](demo#basic-rules) | -| gender | `string \| male \| female` | -- | 可选,根据性别区分头像颜色,传入 string,可以是`female \| male`的任意大小写形式 | [头像显示的基本规则](demo#basic-rules) | -| width | `number` | 40 | 可选,设定头像的宽度, 单位为`px` | [头像的基础配置](demo#basic-configuration) | -| height | `number` | 40 | 可选,设定头像的高度,单位为`px` | [头像的基础配置](demo#basic-configuration) | -| isRound | `boolean` | true | 可选,是否显示为圆形头像 | [头像的基础配置](demo#basic-configuration) | -| imgSrc | `string` | -- | 可选,传入自定义图片作为头像 | [头像的基础配置](demo#basic-configuration) | -| customText | `string` | -- | 可选,传入自定义显示文字 | [头像的基础配置](demo#basic-configuration) | - -### 头像显示基本规则 - -- `中文开头`:取传入字符串的最后两个字符 -- `英文开头`:取传入字符串的前面两个字符 -- `多个英文名连用`:取传入字符串的前两个英文名首字母 -- `非中英文开头`:取传入字符串的前两个字符 - -### 头像特殊显示规则 - -- 未传入`name`,`customText`,`imgSrc`,视为使用该头像的用户不存在 -- 传入`name`,`customText`,`imgSrc`的值为空,视为使用该头像的用户无昵称,使用默认头像 - -### 显示优先级排序 - -imgSrc > customText > name diff --git a/devui/avatar/doc/api-en.md b/devui/avatar/doc/api-en.md deleted file mode 100644 index 4d411154a66f7ece2438fef51ac266459eccd22b..0000000000000000000000000000000000000000 --- a/devui/avatar/doc/api-en.md +++ /dev/null @@ -1,42 +0,0 @@ -# How to use - -Import into module: - -```ts -import { AvatarModule } from 'ng-devui/avatar'; -``` - -In the page: - -```xml - -``` -# d-avatar -## d-avatar Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------: | :--------------------: | :--: | :-------------------------------------------------------------------------- | ------------------------------------------------------------- | -| name | `string` | -- | Required. The input character string is used to create a profile picture. | [Basic Rules](demo#basic-rules) | -| gender | `string \| male \| female` | -- | Optional. The profile picture color is differentiated by gender. The input string can be in the format of `female \| male`. | [Basic Rules](demo#basic-rules) | -| width | `number` | 40 | Optional. Width of the avatar(`px`) | [Basic Configuration](demo#basic-configuration) | -| height | `number` | 40 | Optional. Set the height of the avatar(`px`) | [Basic Configuration](demo#basic-configuration) | -| isRound | `boolean` | true | Optional. Indicating whether to display a circular avatar | [Basic Configuration](demo#basic-configuration) | -| imgSrc | `string` | -- | Optional. Import a customized image as the avatar | [Basic Configuration](demo#basic-configuration) | -| customText | `string` | -- | Optional. Input the customized display text | [Basic Configuration](demo#basic-configuration) | - - -### Basic Profile Picture Display Rules - -- `Begin with Chinese `: Use the last two characters. -- `Begin with English `: Use the first two characters. -- `Use multiple English names together`: Use the first two letters of the first English name. -- `Not starting with Chinese or English `: Use the first two characters. - -### Special avatar display rules - -- If `name`, `customText`, and `imgSrc` are not transferred, the user who uses the avatar does not exist. -- If the values of `name`, `customText`, and `imgSrc` are empty, the user who uses the avatar does not have a nickname and the default avatar is used. - -### Display Priority - -imgSrc > customText > name diff --git a/devui/back-top/back-top.tsx b/devui/back-top/back-top.tsx deleted file mode 100644 index 651d1a31d741b6f55d6fc9fc7b9667ca24a51a82..0000000000000000000000000000000000000000 --- a/devui/back-top/back-top.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-back-top', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-back-top
- } - } -}) \ No newline at end of file diff --git a/devui/back-top/demo/back-top-demo.tsx b/devui/back-top/demo/back-top-demo.tsx deleted file mode 100644 index c07b12b1ac04e528f81295ec204403d32f3b3ed8..0000000000000000000000000000000000000000 --- a/devui/back-top/demo/back-top-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-back-top-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-back-top-demo
- } - } -}) \ No newline at end of file diff --git a/devui/back-top/demo/back-top.route.ts b/devui/back-top/demo/back-top.route.ts deleted file mode 100644 index da4819014fbac9a66399e051344c970501cb081c..0000000000000000000000000000000000000000 --- a/devui/back-top/demo/back-top.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import BackTopDemoComponent from './back-top-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: BackTopDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/back-top/doc/api-cn.md b/devui/back-top/doc/api-cn.md deleted file mode 100644 index 5c56c387632a9874cb041aad45272669bb45a1d2..0000000000000000000000000000000000000000 --- a/devui/back-top/doc/api-cn.md +++ /dev/null @@ -1,30 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { BackTopModule } from 'ng-devui/back-top'; -``` - -在页面中使用: - -```xml - -``` - -# d-back-top -## d-back-top 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | -| customTemplate | `TemplateRef` | -- | 可选,自定义按钮样式 | [自定义](demo#back-top-customize) | -| bottom | `string` | '50px' | 可选,按钮距离页面底部位置 | [自定义](demo#back-top-customize) | -| right | `string` | '30px' | 可选,按钮距离页面右边距 | [自定义](demo#back-top-customize) | -| visibleHeight | `number` | 300 | 可选,滚动高度达到visibleHeight所设值后展示回到顶部按钮,单位为`px` | [自定义](demo#back-top-customize) | -| scrollTarget | `HTMLElement` | Window | 可选,触发滚动的对象 | [滚动容器](demo#back-top-scroll-container) | - -## d-back-top 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :------: | :-----------------: | :-------------------------------------------------------------------------------------- | ---------------------------------------------- | -| backTopEvent | `EventEmitter` | 可选,点击回到顶部按钮的回调函数 | [基本用法](demo#back-top-basic) | diff --git a/devui/back-top/doc/api-en.md b/devui/back-top/doc/api-en.md deleted file mode 100644 index 3bfb59a502abf260ed0a24e4d400b1af2c941a74..0000000000000000000000000000000000000000 --- a/devui/back-top/doc/api-en.md +++ /dev/null @@ -1,29 +0,0 @@ -# How to use - -Import into module: - -```ts -import { BackTopModule } from 'ng-devui/back-top'; -``` - -In the page: - -```xml - -``` -# d-back-top -## d-back-top Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | -| customTemplate | `TemplateRef` | -- | Optional. Custom button style | [Customize](demo#back-top-customize) | -| bottom | `string` | '50px' | Optional. Position between the button and the bottom of the page | [Customize](demo#back-top-customize) | -| right | `string` | '30px' | Optional. It is the right margin between the button and the page | [Customize](demo#back-top-customize) | -| visibleHeight | `number` | 300 | Optional. When the scrolling height reaches the value of visibleHeight, the button is displayed to the top. The unit is `px` | [Customize](demo#back-top-customize) | -| scrollTarget | `HTMLElement` | Window | Optional. Object that triggers scrolling | [Scrolling Container](demo#back-top-scroll-container) | - -## d-back-top Event - -| Parameter | Type | Description | Jump to Demo | -| :------: | :-----------------: | :-------------------------------------------------------------------------------------- | ---------------------------------------------- | -| backTopEvent | `EventEmitter` | Optional. Callback function for clicking the button to return to the top | [Basic Usage](demo#back-top-basic) | diff --git a/devui/badge/badge.tsx b/devui/badge/badge.tsx deleted file mode 100644 index 560de1b58c07938b4f9063af9d88ab441e229dd6..0000000000000000000000000000000000000000 --- a/devui/badge/badge.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-badge', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-badge
- } - } -}) \ No newline at end of file diff --git a/devui/badge/demo/badge-demo.tsx b/devui/badge/demo/badge-demo.tsx deleted file mode 100644 index d0ec38591178cebc2ad4aad63b08782fc1ed5cce..0000000000000000000000000000000000000000 --- a/devui/badge/demo/badge-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-badge-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-badge-demo
- } - } -}) \ No newline at end of file diff --git a/devui/badge/demo/badge.route.ts b/devui/badge/demo/badge.route.ts deleted file mode 100644 index 7a25019903bd81c368e87d69e9843a853877d0a8..0000000000000000000000000000000000000000 --- a/devui/badge/demo/badge.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import BadgeDemoComponent from './badge-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: BadgeDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/badge/doc/api-cn.md b/devui/badge/doc/api-cn.md deleted file mode 100644 index b0858655b111bf7ff1e5ccee2923ef78ae7c17ba..0000000000000000000000000000000000000000 --- a/devui/badge/doc/api-cn.md +++ /dev/null @@ -1,27 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { BadgeModule } from 'ng-devui/badge'; -``` - -在页面中使用: -```html - -
未读消息
-
- -``` -# Badge - -## d-badge 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | :--------------------------- | -| count | `number` | -- | 可选,设置基本徽章和计数徽章中显示的数目 | [基本徽章](demo#badge-basic) | -| maxCount | `number` | 99 | 可选,设置基本徽章和计数徽章最大可显示数目,当 count > maxCount 时显示maxCount+ | [基本徽章](demo#badge-basic) | -| showDot | `boolean` | false | 可选,true时为点状徽章(有包裹)或状态徽章(无包裹),false时为基本徽章(有包裹)或计数徽章(无包裹) | [点状徽章](demo#badge-dot) | -| status |`BadgeStatusType` | -- | 可选,状态色 'danger' \| 'warning' \| 'waiting' \| 'success' \| 'info' | [基本徽章](demo#badge-basic) | -| badgePos | `BadgePositionType` | 'top-right' | 可选,徽标位置 'top-left' \| 'top-right' \| 'bottpm-left' \| ''bottom-right'' | [徽章位置](demo#position) | -| offsetXY | `[number, number]` | -- | 可选,有包裹时徽标位置偏移量,格式为[x,y],单位为px。x为相对right偏移量(right: -x `px`),y为相对top偏移量(top: y `px`) | [自定义](demo#custom) | -| bgColor | `string` | -- | 可选,自定义徽标色,此时status参数设置的徽章状态色失效 | [自定义](demo#custom) | -| textColor | `string` | -- | 可选, 可自定义徽标文字颜色 | [自定义](demo#custom) | diff --git a/devui/badge/doc/api-en.md b/devui/badge/doc/api-en.md deleted file mode 100644 index 0d628a7a6505ab6968b0bf8ecfc89b39de75285e..0000000000000000000000000000000000000000 --- a/devui/badge/doc/api-en.md +++ /dev/null @@ -1,27 +0,0 @@ -# How to use -Import into module: -```ts -import { BadgeModule } from 'ng-devui/badge'; -``` - -In the page: -```html - -
Unread messages
-
- -``` -# Badge - -## d-badge Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | :--------------------------- | -| count | `number` | -- | Optional. Set the number of basic badges and count badges to be displayed. | [Basic Badge](demo#badge-basic) | -| maxCount | `number` | 99 | Optional. Sets the maximum number of basic and counting badges that can be displayed. When count is greater than maxCount, maxCount+ is displayed. | [Basic Badge](demo#badge-basic) | -| showDot | `boolean` | false | Optional. The value true indicates the dot badge (with package) or status badge (without package). The value false indicates the basic badge (with package) or count badge (without package). | [Dotted Badge](demo#badge-dot) | -| status |`BadgeStatusType` | -- | Optional. The status color is'danger'\| 'warning' \| 'waiting' \| 'success' \| 'info'. | [Basic Badge](demo#badge-basic) | -| badgePos | `BadgePositionType` | 'top-right' | Optional. Logo position'top-left' \|'top-right' \|'bottpm-left' \|'bottom-right'. | [Badge Position](demo#position) | -| offsetXY | `[number, number]` | -- |Optional. Indicates the logo position offset when there is a package. The format is [x,y], in px. This parameter is optional. x is the relative right offset (right: -x `px`), y is the relative top offset (top: y `px`). | [Custom](demo#custom) | -| bgColor | `string` | -- | Optional. The badge color can be customized. In this case, the badge status color specified by status is invalid.| [Custom](demo#custom) | -| textColor | `string` | -- | Optional. You can customize the logo text color. | [Custom](demo#custom) | diff --git a/devui/breadcrumb/breadcrumb.tsx b/devui/breadcrumb/breadcrumb.tsx deleted file mode 100644 index 97c04f954fab712044d93e69e4587b732627cada..0000000000000000000000000000000000000000 --- a/devui/breadcrumb/breadcrumb.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-breadcrumb', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-breadcrumb
- } - } -}) \ No newline at end of file diff --git a/devui/breadcrumb/demo/breadcrumb-demo.tsx b/devui/breadcrumb/demo/breadcrumb-demo.tsx deleted file mode 100644 index 3e6b9d400bbbf469d1d9ea144811a218515732ae..0000000000000000000000000000000000000000 --- a/devui/breadcrumb/demo/breadcrumb-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-breadcrumb-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-breadcrumb-demo
- } - } -}) \ No newline at end of file diff --git a/devui/breadcrumb/demo/breadcrumb.route.ts b/devui/breadcrumb/demo/breadcrumb.route.ts deleted file mode 100644 index 969e8dad147abf567cd388ed42b6ef40f368d942..0000000000000000000000000000000000000000 --- a/devui/breadcrumb/demo/breadcrumb.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import BreadcrumbDemoComponent from './breadcrumb-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: BreadcrumbDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/breadcrumb/doc/api-cn.md b/devui/breadcrumb/doc/api-cn.md deleted file mode 100644 index 9b26dd11d59caa800396dbd4485c981a463964b3..0000000000000000000000000000000000000000 --- a/devui/breadcrumb/doc/api-cn.md +++ /dev/null @@ -1,98 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { BreadcrumbModule } from 'ng-devui/breadcrumb'; -``` - -在页面中使用: - -```xml -//通过d-breadcrumb-item定义显示 - - - - -//通过传入source显示 - -``` -# d-breadcrumb-item -## d-breadcrumb-item 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------: | :-----------------: | :---: | :------------------------------------------------------ | -------------------------------------------------------------------------------------- | -| showMenu | `boolean` | false | 可选,是否需要显示下拉箭头及下拉列表内容 | [可下拉的面包屑](demo#drop-down-breadcrumbs) | -| menuList | [`Array`](#menuconfig) | -- | 可选,showMenu 为 true 时传入,下拉列表的显示内容 | [可下拉的面包屑](demo#drop-down-breadcrumbs) | -| isSearch | `boolean` | false | 可选,showMenu 为 true 时传入,下拉列表是否需要搜索功能 | [可下拉的面包屑](demo#drop-down-breadcrumbs) | -| customMenuTemplate | `TemplateRef` | -- | 可选,showMenu 为 true 时传入,自定义下拉列表 | [自定义下拉列表和分隔符的面包屑](demo#self-defined-breadcrumbs) | - -## d-breadcrumb-item 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :---------: | :-----------------: | :-----------------------------------------------------: | ------------------------------------------------------------------- | -| toggleEvent | `EventEmitter` | dropdown 菜单展开和收起的事件,返回值为当前菜单是否打开 | [可下拉的面包屑](demo#drop-down-breadcrumbs) | - -# d-breadcrumb -## d-breadcrumb 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :-------------------: | :---: | :------------------------------------------------- | -------------------------------------------------------------------------------------- | -| separatorIcon | `TemplateRef` | ' / ' | 可选,自定义分隔符样式 | [自定义下拉列表和分隔符的面包屑](demo#self-defined-breadcrumbs) | -| source | [`Array`](#sourceconfig) | [] | 可选,面包屑根据配置的 source 按照默认渲染方式显示 | [传入source](demo#source-config-breadcrumbs) - -# 接口 & 类型定义 -### MenuConfig - -```ts -export interface MenuConfig { - name: string; - link: string; - linkType?: 'hrefLink' | 'routerLink'; - target?: string; -} -``` - -`name`:显示的名称 - -`link`:跳转的路径,可为绝对路径与相对路径,注意需要与路由的配置一致 - -`linkType`: 链接类型,默认为'hrefLink'方式,可选'hrefLink' 或 'routerLink' - -`target`: 规定在何处打开链接文档 - -### SourceConfig - -```ts -export interface SourceConfig { - title: string; - link?: string; - showMenu?: boolean; - isSearch?: boolean; - target?: string; - menuList?: Array; - customMenuTemplate?: TemplateRef; - noNavigation?: boolean; - linkType?: 'hrefLink' | 'routerLink'; -} -``` - -`title`: 显示的名称 - -`link`: 跳转的路径 - -`showMenu`: 是否显示下拉列表 - -`isSearch`: 下拉列表是否可搜索 - -`menuList`: 下拉列表的数据,配置参考上方 MenuConfig - -`customMenuTemplate`: 自定义下拉列表 - -`noNavigation`: 链接是否不可跳转,一般用于当前所处位置不可跳转的配置 - -`linkType`: 链接类型,默认为'hrefLink'方式,可选'hrefLink' 或 'routerLink' - -`target`: 规定在何处打开链接文档 - -备注:source 数据改变使用`Object.assign`方式触发变更检测 diff --git a/devui/breadcrumb/doc/api-en.md b/devui/breadcrumb/doc/api-en.md deleted file mode 100644 index 7bde383a9a3a066eecd152ccf603c12981f5f4fe..0000000000000000000000000000000000000000 --- a/devui/breadcrumb/doc/api-en.md +++ /dev/null @@ -1,98 +0,0 @@ -# How to use - -Import into module: - -```ts -import { BreadcrumbModule } from 'ng-devui/breadcrumb'; -``` - -In the page: - -```xml -//use d-breadcrumb-item - - - - -//use source - -``` -# d-breadcrumb-item -## d-breadcrumb-item Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------: | :-----------------: | :---: | :------------------------------------------------------ | -------------------------------------------------------------------------------------- | -| showMenu | `boolean` | false | Optional. Indicating whether to display the drop-down arrow and content in the drop-down list | [Breadcrumbs with Dropdown menu](demo#drop-down-breadcrumbs) | -| menuList | [`Array`](#menuconfig) | -- | Optional. This parameter is transferred when showMenu is set to true. Content displayed in the drop-down list box | [Breadcrumbs with Dropdown menu](demo#drop-down-breadcrumbs) | -| isSearch | `boolean` | false | Optional. This parameter is transferred when showMenu is set to true. Whether the search function is required in the drop-down list box | [Breadcrumbs with Dropdown menu](demo#drop-down-breadcrumbs) | -| customMenuTemplate | `TemplateRef` | -- | Optional. This parameter is transferred when showMenu is set to true. Customized drop-down list box | [Customize](demo#self-defined-breadcrumbs) | - -## d-breadcrumb-item Event - -| Event | Type | Description | Jump to Demo | -| :---------: | :-----------------: | :-----------------------------------------------------: | ------------------------------------------------------------------- | -| toggleEvent | `EventEmitter` | Event of expanding or collapsed Dropdown menus. The return value is whether the current menu is opened | [Breadcrumbs with Dropdown menu](demo#drop-down-breadcrumbs) | - -# d-breadcrumb -## d-breadcrumb Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------: | :-------------------: | :---: | :------------------------------------------------- | -------------------------------------------------------------------------------------- | -| separatorIcon | `TemplateRef` | ' / ' | Optional. Custom separator style | [Customize](demo#self-defined-breadcrumbs) | -| source | [`Array`](#sourceconfig) | [] | Optional. The breadcrumbs are displayed in the default rendering mode based on the configured source | [Source Config](demo#source-config-breadcrumbs) | - -# Interface & Type Definition -### MenuConfig - -```ts -export interface MenuConfig { - name: string; - link: string; - linkType?: 'hrefLink' | 'routerLink'; - target?: string; -} -``` - -`name`: Indicates the name to be displayed. - -`link`: Indicates the jump path, which can be an absolute path or a relative path. The path must be the same as the route configuration. - -`linkType`: Link type. The default value is hrefLink. The value can be hrefLink or routerLink. - -`target`: Specifies where to open the linked document. - -### SourceConfig - -```ts -export interface SourceConfig { - title: string; - link?: string; - showMenu?: boolean; - isSearch?: boolean; - target?: string; - menuList?: Array; - customMenuTemplate?: TemplateRef; - noNavigation?: boolean; - linkType?: 'hrefLink' | 'routerLink'; -} -``` - -`title`: Name to be displayed - -`link`: Indicates the path to be redirected. - -`showMenu`: Indicates whether to display the drop-down list box. - -`isSearch`: Indicates whether the drop-down list box can be searched. - -`menuList`: Data in the drop-down list box. For details, see MenuConfig. - -`customMenuTemplate`: Customized drop-down list box - -`noNavigation`: Indicates whether a link cannot be redirected. This parameter is used to configure the link that cannot be redirected to the current location. - -`linkType`: Link type. The default value is hrefLink. The value can be hrefLink or routerLink. - -`target`: Specifies where to open the linked document. - -Note: Source data changes use the `Object.assign` method to trigger change detection. diff --git a/devui/button/button.tsx b/devui/button/button.tsx deleted file mode 100644 index 166d0c08f3a5edec5a60f7a40d27889457e96261..0000000000000000000000000000000000000000 --- a/devui/button/button.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { computed, defineComponent, ref } from "vue"; - -export type IButtonType = 'button' | 'submit' | 'reset'; -export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; -export type IButtonPosition = 'left' | 'right' | 'default'; -export type IButtonSize = 'lg' | 'md' | 'sm' | 'xs'; - -import './button.scss'; - -export default defineComponent({ - name: 'd-button', - inheritAttrs: false, - props: { - id: { - type: [String, Number] - }, - type: { - type: String as () => IButtonType, - default: 'button' - }, - bsStyle: { - type: String as () => IButtonStyle, - default: 'primary' - }, - bsSize: { - type: String as () => IButtonSize, - default: 'md' - }, - bsPosition: { - type: String as () => IButtonPosition, - default: 'default' - }, - bordered: { - type: Boolean, - default: false - }, - icon: { - type: String, - default: '' - }, - showLoading: { - type: Boolean, - default: false - }, - width: { - type: Number, - default: 0 - }, - disabled: { - type: Boolean, - default: false - }, - autofocus: { - type: Boolean, - default: false - }, - btnClick: { - type: Function as unknown as () => ((event: MouseEvent) => void) - } - }, - setup(props, ctx) { - const buttonContent = ref(null); - - const onClick = (e: MouseEvent) => { - if (props.showLoading) { - return; - } - props.btnClick?.(e); - } - - const hasContent = computed(() => { - return buttonContent.value && buttonContent.value.innerHTML.trim(); - }) - - const btnClazz = computed(() => { - const {bsStyle, bsSize, bsPosition, bordered, icon} = props; - const origin = `devui-btn devui-btn-${ bsStyle } devui-btn-${ bsSize } devui-btn-${ bsPosition }`; - const broderedClazz = bordered ? 'bordered' : ''; - const btnIcon = !!icon && !hasContent.value && bsStyle !== 'primary' ? 'd-btn-icon' : ''; - const btnIconWrap = !!icon ? 'd-btn-icon-wrap' : ''; - return `${origin} ${broderedClazz} ${btnIcon} ${btnIconWrap}`; - }); - - const iconClazz = computed(() => { - if (!props.icon) { - return; - } - const origin = `devui-icon-fix icon ${ props.icon }`; - if (hasContent.value) { - return `${origin} clear-right-5`; - } else { - return origin; - } - }); - - return () => { - const { - icon, - type, - disabled, - showLoading, - width - } = props; - const hasIcon = !!icon; - return ( - - ); - } - } -}); \ No newline at end of file diff --git a/devui/button/demo/button-demo.tsx b/devui/button/demo/button-demo.tsx deleted file mode 100644 index a751cc43b1101b072d3eaf0ec58514051b277eb1..0000000000000000000000000000000000000000 --- a/devui/button/demo/button-demo.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { defineComponent } from 'vue' -import CodeBox from '../../shared/devui-codebox/devui-codebox' -import ButtonPrimary from './primary/primary' -import ButtonCommon from './common/common' -import PrimaryCode from './primary/primary.tsx?raw' -import CommonCode from './common/common.tsx?raw' - -export default defineComponent({ - name: 'd-button-demo', - setup() { - const primarySource: any[] = [{title: 'TSX', language: 'TSX', code: PrimaryCode}]; - const commonSource: any[] = [{title: 'TSX', language: 'TSX', code: CommonCode}]; - return () => { - return
-
-
{ '主要按钮' }
-
- - - -
-
-
{ '次要按钮' }
-
- - - -
-
- } - } -}) \ No newline at end of file diff --git a/devui/button/demo/button.route.ts b/devui/button/demo/button.route.ts deleted file mode 100644 index 50144c127b1af69940da6dac131899b90a25ef7e..0000000000000000000000000000000000000000 --- a/devui/button/demo/button.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ButtonDemoComponent from './button-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ButtonDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/button/demo/common/common.tsx b/devui/button/demo/common/common.tsx deleted file mode 100644 index 02a9125ca92bf1cda2d3654de1dc996175860e10..0000000000000000000000000000000000000000 --- a/devui/button/demo/common/common.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { defineComponent } from 'vue'; -import Button from '../../button'; - -export default defineComponent({ - name: 'd-button-common', - setup() { - return () => { - return ( -
- -
- ); - } - } -}); \ No newline at end of file diff --git a/devui/button/demo/primary/primary.tsx b/devui/button/demo/primary/primary.tsx deleted file mode 100644 index 2a1bba16958e0a7eb359d35685f85ddae86de8b1..0000000000000000000000000000000000000000 --- a/devui/button/demo/primary/primary.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { defineComponent } from 'vue'; -import Button from '../../button'; - -export default defineComponent({ - name: 'd-button-primary', - setup() { - return () => { - return ( -
- - -
- ); - } - } -}); \ No newline at end of file diff --git a/devui/button/doc/api-cn.md b/devui/button/doc/api-cn.md deleted file mode 100644 index 7751ae0e48bf8eb3d43f06c0724e9b8381d94e12..0000000000000000000000000000000000000000 --- a/devui/button/doc/api-cn.md +++ /dev/null @@ -1,82 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { ButtonModule } from 'ng-devui/button'; -``` - -在页面中使用: - -```xml - -``` -# d-button -## d-button 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | ---------------------------------------------- | -| id | `string` | -- | 可选,button id | [主要按钮](demo#button-primary) | -| type | [`IButtonType`](#ibuttontype) | 'button' | 可选,类型 `'button' \| 'submit' \| 'reset' ` | [警示按钮](demo#button-danger) | -| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | 可选,风格 `'primary' \| 'common' \| 'text' \| 'text-dark' \| 'danger'` | [次要按钮](demo#button-common) | -| bsSize | [`IButtonSize`](#ibuttonsize) | 'md' | 可选,大小 `'lg' \| 'md' \| 'sm' \| 'xs'` | [按钮尺寸](demo#button-size) | -| bsPosition |[`IButtonPosition`](#ibuttonposition) |'default' | 可选,按钮位置 `'default' \| 'left' \| 'right'` | [左右按钮](demo#button-left-right) | -| bordered | `boolean` | false | 可选,是否有边框 | [自动获得焦点](demo#button-auto-focus) | -| icon | `string` | -- | 可选, 自定义按钮图标 | [图标按钮](demo#button-icon) | -| showLoading | `boolean` | false | 可选,是否显示加载提示 | [加载中状态](demo#button-loading) | -| width | `number` | -- | 可选,button 宽度 | [主要按钮与次要按钮组合](demo#button-primary-and-common) | -| disabled | `boolean` | false | 可选,是否禁用 button | [主要按钮](demo#button-primary) | -| autofocus | `boolean` | false | 可选,按钮加载时是否自动获得焦点 | [自动获得焦点](demo#button-auto-focus) | - -## d-button 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :------: | :-----------------: | :-------------------------------------------------------------------------------------- | ---------------------------------------------- | -| btnClick | `EventEmitter` | 可选,button 点击事件,解决disabled还会触发 click, 返回点击下后鼠标事件对象 | [加载中状态](demo#button-loading) | - -# d-button-group -## d-button-group 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | ---------------------------------------------- | -| size | [`IButtonGroupSize`](#ibuttongroupsize) | 'md' | 可选,大小`'lg' \| 'md' \| 'sm' \| 'xs'` | [按钮组](demo#button-groups) | - - -# 接口 & 类型定义 -### IButtonType - -默认值为'button',表示button类型 - -```ts -export type IButtonType = 'button' | 'submit' | 'reset'; -``` - -### IButtonStyle - -默认值为'primary',表示button风格 - -```ts -export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; -``` - -### IButtonPosition - -默认值为'default',表示button位置 - -```ts -export type IButtonPosition = 'left' | 'right' | 'default'; -``` - -### IButtonSize -默认值为'md',表示button尺寸 - -```ts -export type IButtonSize = 'lg' | 'md' | 'sm' | 'xs'; -``` - -### IButtonGroupSize -默认值为'md',表示button-group尺寸 - -```ts -export type IButtonGroupSize = 'lg' | 'md' | 'sm' | 'xs'; -``` diff --git a/devui/button/doc/api-en.md b/devui/button/doc/api-en.md deleted file mode 100644 index a47f96cafe8682f3218ef2e02019927a4a4b101d..0000000000000000000000000000000000000000 --- a/devui/button/doc/api-en.md +++ /dev/null @@ -1,82 +0,0 @@ -# How to use - -Import into module: - -```ts -import { ButtonModule } from 'ng-devui/button'; -``` - -In the page: - -```xml - -``` -# d-button -## d-button Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | -| id | `string` | -- | Optional. button ID | [Primary Buttons](demo#button-primary)| -| type | [`IButtonType`](#ibuttontype) | 'button' | Optional. The type is `'button' \| 'submit' \| 'reset'` |[Danger Buttons](demo#button-danger) | -| bsStyle | [`IButtonStyle`](#ibuttonstyle) | 'primary' | Optional. The style is `'primary' \| 'common' \| 'text' \| 'text-dark' \| 'danger'` | [Common Buttons](demo#button-common) | -| bsSize | [`IButtonSize`](#ibuttonsize) | 'md' | Optional. The size is `'lg' \| 'md' \| 'sm' \| 'xs'` | [Button Size](demo#button-size) | -| bsPosition |[`IButtonPosition`](#ibuttonposition) |'default'| Optional. The button position is `'default' \| 'left' \| 'right'` | [Left & Right Buttons](demo#button-left-right) | -| bordered | `boolean` | false | Optional. Indicating whether a border exists | [Auto-focus Buttons](demo#button-auto-focus)| -| icon | `string` | -- | Optional. Customized button icon | [Icon Buttons](demo#button-icon) | -| showLoading | `boolean` | false | Optional. Indicating whether to display the loading prompt | [Loading Buttons](demo#button-loading) | -| width | `number` | -- | Optional. Button width |[Combinations of Primary & Common Buttons](demo#button-primary-and-common) | -| disabled | `boolean` | false | Optional. Indicating whether to disable the button | [Primary Buttons](demo#button-primary) | -| autofocus | `boolean` | false | Optional. Indicating whether to automatically obtain the focus during button loading | [Auto-focus Buttons](demo#button-auto-focus) | - -## d-button Event - -| Parameter | Type | Description | Jump to Demo | -| :------: | :-----------------: | :-------------------------------------------------------------------------------------- | ---------------------------------------------- | -| btnClick | `EventEmitter` | Optional. Solve the click event is triggered when button is disabled. After the mouse is clicked, the mouse event object is returned | [Loading Buttons](demo#button-loading)| - -# d-button-group - -## d-button-group parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :------------: | :-----: | :--------------------------------------------------------------------------- | | -| size | [`IButtonGroupSize`](#ibuttongroupsize) | 'md' | Optional. The size is `'lg' \| 'md' \| 'sm' \| 'xs'` | [Button Group](demo#button-groups) | - -# Interface & Type Definition -### IButtonType - -The default value is 'button', indicating the button type. - -```ts -export type IButtonType = 'button' | 'submit' | 'reset'; -``` - -### IButtonStyle - -The default value is 'primary', indicating the button style. - -```ts -export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; -``` - -### IButtonPosition - -The default value is 'default', indicating the button position. - -```ts -export type IButtonPosition = 'left' | 'right' | 'default'; -``` - -### IButtonSize -The default value is 'md', indicating the button size. - -```ts -export type IButtonSize = 'lg' | 'md' | 'sm' | 'xs'; -``` - -### IButtonGroupSize -The default value is 'md', indicating the button-group size. - -```ts -export type IButtonGroupSize = 'lg' | 'md' | 'sm' | 'xs'; -``` diff --git a/devui/button/index.ts b/devui/button/index.ts deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/devui/card/card.tsx b/devui/card/card.tsx deleted file mode 100644 index 2c415e66f7737dc9163c9a9c5177b84192e69a49..0000000000000000000000000000000000000000 --- a/devui/card/card.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-card', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-card
- } - } -}) \ No newline at end of file diff --git a/devui/card/demo/card-demo.tsx b/devui/card/demo/card-demo.tsx deleted file mode 100644 index b7991a97c2a65ae2dd0ea4720c32296d5920f4db..0000000000000000000000000000000000000000 --- a/devui/card/demo/card-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-card-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-card-demo
- } - } -}) \ No newline at end of file diff --git a/devui/card/demo/card.route.ts b/devui/card/demo/card.route.ts deleted file mode 100644 index 86ce97c259154656e7315733696230037e052a38..0000000000000000000000000000000000000000 --- a/devui/card/demo/card.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import CardDemoComponent from './card-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: CardDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/card/doc/api-cn.md b/devui/card/doc/api-cn.md deleted file mode 100644 index c514fc1bb71a4954af2977ce1f318e29f374368c..0000000000000000000000000000000000000000 --- a/devui/card/doc/api-cn.md +++ /dev/null @@ -1,43 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { CardModule } from 'ng-devui/card'; -``` - -在页面中使用: - -```xml - - - - - - - - -``` -# d-card -## d-card 区块划分 - -| 标签 | 描述 | -| :------------: | :--------------------------------------------------------------------------------------------: | -| d-card-header | 标题区域,作为概览使用,通常包含标题`d-card-title`,副标题`d-card-subtitle`,头像`dAvatar`等元素 | -| [dCardMeta] | 媒体信息区域,可放置多种媒体,包括图片、图形、视频。 | -| d-card-content | 辅助信息区,分析和支撑标题作用,可以包含摘要或者说明。 | -| d-card-actions | 决策作用,可以包含操作文本或者操作图标。 | - -## d-card-header 区块划分 - -| 标签 | 描述 | -| :-------------: | :------------------------------------: | -| d-card-title | 卡片的主要内容描述,一般定义为卡片名称 | -| [dCardAvatar] | 头像区域,用作头像等图片展示 | -| d-card-subtitle | 对标题的补充,可包含标签等信息 | - -## d-card-actions 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---: | :------: | :---: | :-------------: | --------- | -| align | `'start' \| 'end' \|'spaceBetween'` | 'start' | 可选,操作区域对齐方式,分别对应起始对齐,尾部对齐,拉伸对齐 | [基本用法](demo#card-basic) | diff --git a/devui/card/doc/api-en.md b/devui/card/doc/api-en.md deleted file mode 100644 index ecd8229048db8d5a3e28e87fa5e3c1f7cc8894bb..0000000000000000000000000000000000000000 --- a/devui/card/doc/api-en.md +++ /dev/null @@ -1,43 +0,0 @@ -# How to use - -Import into module: - -```ts -import { CardModule } from 'ng-devui/card'; -``` - -In the page: - -```xml - - - - - - - - -``` -# d-card -## d-card Block Division - -| Tag | Description | -| :------------: | :--------------------------------------------------------------------------------------------: | -| d-card-header | Title area, which is used as an overview. It usually contains elements such as title `d-card-title`, subtitle `d-card-subtitle`, and avatar `dAvatar` | -| [dCardMeta] | Media information area, which can store multiple media, including pictures, graphics, and videos | -| d-card-content | Auxiliary information area, which analyzes and supports the title function. It can contain abstracts or descriptions | -| d-card-actions | Decision-making function, which can contain operation text or operation icons | - -## d-card-header Block Division - -| Tag | Description | -| :-------------: | :------------------------------------: | -| d-card-title | Card content description, which is generally defined as the card name | -| [dCardAvatar] | Avatar area, which is used to display images such as avatars | -| d-card-subtitle | Supplement to the title, including tag information | - -## d-card-actions Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---: | :------: | :---: | :-------------: | --------- | -| align | `'start'\|'end'\|'spaceBetween'` | 'start' | Optional. Operation area alignment mode, which corresponds to start alignment, tail alignment, and stretch alignment | [Basic usage](demo#card-basic) | diff --git a/devui/carousel/carousel.tsx b/devui/carousel/carousel.tsx deleted file mode 100644 index 9c1640c26cf48970292eae55dcffbfea81eca000..0000000000000000000000000000000000000000 --- a/devui/carousel/carousel.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-carousel', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-carousel
- } - } -}) \ No newline at end of file diff --git a/devui/carousel/demo/carousel-demo.tsx b/devui/carousel/demo/carousel-demo.tsx deleted file mode 100644 index 4bb23c7ecce97b6cfd0beee80fd56d76e5b60b38..0000000000000000000000000000000000000000 --- a/devui/carousel/demo/carousel-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-carousel-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-carousel-demo
- } - } -}) \ No newline at end of file diff --git a/devui/carousel/demo/carousel.route.ts b/devui/carousel/demo/carousel.route.ts deleted file mode 100644 index d82a897450de2717de2f63b4dd30e69c6907c99b..0000000000000000000000000000000000000000 --- a/devui/carousel/demo/carousel.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import CarouselDemoComponent from './carousel-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: CarouselDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/carousel/doc/api-cn.md b/devui/carousel/doc/api-cn.md deleted file mode 100644 index 05132f505c917dcf2073fa263a70029ecc6cbf70..0000000000000000000000000000000000000000 --- a/devui/carousel/doc/api-cn.md +++ /dev/null @@ -1,40 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { CarouselModule } from 'ng-devui/carousel'; -``` -在页面中使用: -```html - - - -``` - -# d-carousel - -## d-carousel 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----------: | :--------------------------: | :------: | :---------------------------------------------- | ------------------------------------------------ | -| arrowTrigger | `'hover'\|'never'\|'always'` | 'hover' | 可选,指定切换箭头显示方式 | [指示器&切换箭头](demo#trigger-usage) | -| autoplay | `boolean` | false | 可选,是否自动轮播 | [自动轮播](demo#autoplay-usage) | -| autoplaySpeed | `number` | 3000 | 可选,配合`autoplay`使用,自动轮播速度,单位 ms | [自动轮播](demo#autoplay-usage) | -| height | `string` | '100%' | 可选,轮播容器高度 | [基本用法](demo#basic-usage) | -| showDots | `boolean` | true | 可选,是否显示面板指示器 | [自动轮播](demo#autoplay-usage) | -| dotPosition | `'top'\|'bottom'` | 'bottom' | 可选,面板指示器位置 | [指示器&切换箭头](demo#trigger-usage) | -| dotTrigger | `'click'\|'hover'` | 'click' | 可选,指示器触发轮播方式 | [指示器&切换箭头](demo#trigger-usage) | -| activeIndex | `number` | 0 | 可选,初始化激活卡片索引,从 0 开始,支持`[(activeIndex)]`双向绑定 | [基本用法](demo#basic-usage) | - -## d-carousel 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| activeIndexChange | `EventEmitter` | 卡片切换时,返回当前卡片的索引,从0开始 | [基本用法](demo#basic-usage) | - -## d-carousel 方法 - -| 方法 | 描述 | 跳转 Demo | -| :---------: | :---------------------------------- | :----------------------------- | -| prev() | 切换到上一张卡片 | [自定义操作](demo#custom-usage) | -| next() | 切换到下一张卡片 | [自定义操作](demo#custom-usage) | -| goTo(index) | 切换到指定索引的卡片,索引从 0 开始 | [自定义操作](demo#custom-usage) | diff --git a/devui/carousel/doc/api-en.md b/devui/carousel/doc/api-en.md deleted file mode 100644 index f9a539ccfa8b446296921b46e1c733a44f129a48..0000000000000000000000000000000000000000 --- a/devui/carousel/doc/api-en.md +++ /dev/null @@ -1,40 +0,0 @@ -# How To Use -Import in module: -```ts -import { CarouselModule } from 'ng-devui/carousel'; -``` -In the page: -```html - - - -``` - -# d-carousel - -## d-carousel parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------: | :--------------------------: | :-----: | :---------------------------------------------- | ------------------------------------------------ | -| arrowTrigger | `'hover'\|'never'\|'always'` | 'hover' | Optional. Specifying the display mode of the switching arrow | [Indicator & Toggle Arrow](demo#trigger-usage) | -| autoplay | `boolean` | false | Optional. Indicating whether to enable automatic NVOD. | [Automatic NVOD](demo#autoplay-usage) | -| autoplaySpeed | `number` | 3000 | Optional. Automatic NVOD speed, in ms. This parameter is used together with `autoplay'. | [Automatic NVOD](demo#autoplay-usage) | -| height | `string` | '100%' | Optional. NVOD container height | [Basic usage](demo#basic-usage) | -| showDots | `boolean` | true | Optional. Indicating whether to display the panel indicator | [Automatic NVOD](demo#autoplay-usage) | -| dotPosition | `'top'\|'bottom'` |'bottom' | Optional. Indicator position on the panel | [Indicator & Toggle Arrow](demo#trigger-usage) | -| dotTrigger | `click'\|'hover'` | 'click' | Optional. The indicator triggers the NVOD mode | [Indicator & Toggle Arrow](demo#trigger-usage) | -| activeIndex | `number` | 0 | Optional. Initializes the activation card index, starting from 0. `[(activeIndex)]` bidirectional binding is supported. | [Basic usage](demo#basic-usage) | - -## d-carousel event - -| Event | Type | Description | Jump to Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| activeIndexChange | `EventEmitter` | Returns the index of the current card when the card is switched. The index starts from 0. | [Basic usage](demo#basic-usage) | - -## d-carousel method - -| Method | Description | Jump to Demo | -| :---------: | :---------------------------------- | :----------------------------- | -| prev() | Switch to the previous card | [Custom Operations](demo#custom-usage) | -| next() | Switch to the next card | [Custom Operations](demo#custom-usage) | -| goTo(index) | Switch to the card with a specified index. The index starts from 0. | [Custom Operations](demo#custom-usage) | diff --git a/devui/cascader/cascader.tsx b/devui/cascader/cascader.tsx deleted file mode 100644 index 9d6eb2805b215290411b6ec8bf03de3a8670554f..0000000000000000000000000000000000000000 --- a/devui/cascader/cascader.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-cascader', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-cascader
- } - } -}) \ No newline at end of file diff --git a/devui/cascader/demo/cascader-demo.tsx b/devui/cascader/demo/cascader-demo.tsx deleted file mode 100644 index 7e7bd98c574308f4a2d9ca5c6d407be34cae753e..0000000000000000000000000000000000000000 --- a/devui/cascader/demo/cascader-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-cascader-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-cascader-demo
- } - } -}) \ No newline at end of file diff --git a/devui/cascader/demo/cascader.route.ts b/devui/cascader/demo/cascader.route.ts deleted file mode 100644 index 06c313d8c2b394905d252546515f2eeeeae2ec8d..0000000000000000000000000000000000000000 --- a/devui/cascader/demo/cascader.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import CascaderDemoComponent from './cascader-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: CascaderDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/cascader/doc/api-cn.md b/devui/cascader/doc/api-cn.md deleted file mode 100644 index ba6ce9781cdae92dcccaec24104597dcf627caf2..0000000000000000000000000000000000000000 --- a/devui/cascader/doc/api-cn.md +++ /dev/null @@ -1,66 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { CascaderModule } from 'ng-devui/cascader'; -``` - -在页面中使用: - -``` - -``` - -# d-cascader - -## d-cascader 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :------------------------------------------------------------------------------: | :------------------------------: | :---------------------------------------------------------------------------------- | ---------------------------------- | -| trigger | `'hover'\|'click'` | 'hover' | 可选,指定展开次级菜单的方式 | [基本用法](demo#basic-usage) | -| options | [`CascaderItem`](#cascaderitem)`[]` | [] | 必选,级联器的菜单信息 | [基本用法](demo#basic-usage) | -| placeholder | `string` | '' | 可选,没有选择时的输入框展示信息 | [基本用法](demo#basic-usage) | -| width | `number` | 200 | 可选,单位 px,用于控制组件输入框宽度和下拉的宽度 | [基本用法](demo#basic-usage) | -| dropdownWidth | `number` | width | 可选,单位 px,控制下拉列表的宽度,默认和组件输入框 width 相等 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,级联器是否禁用 | [基本用法](demo#basic-usage) | -| showPath | `boolean` | false | 可选,级联器选中项是否显示路径,仅单选模式下生效 | [基本用法](demo#basic-usage) | -| allowClear | `boolean` | false | 可选,是否允许清除 | [基本用法](demo#basic-usage) | -| multiple | `boolean` | false | 可选,级联器是否开启多选模式,开启后为 checkbox 选择 | [多选模式](demo#multiple-cascader) | -| canSelectParent | `boolean` | false | 可选,级联器是否允许选择父级节点 | [父级可选](demo#parent-cascader) | -| checkboxRelation | `{upward: boolean, downward: boolean}` | `{upward: true, downward: true}` | 可选,级联器多选下高级状态配置, upward 为状态向父级更新,downward 为状态向子级更新 | [父级可选](demo#parent-cascader) | -| allowSearch | `boolean` | false | 可选,级联器是否开启搜索模式 | [搜索模式](demo#search-cascader) | -| dropDownItemTemplate | `TemplateRef` | false | 可选,传入一个渲染 dropItem 的固定模板 | [模板类型](demo#template-cascader) | -| loadChildrenFn | `(value: CascaderItem) => Promise \| Observable` | null | 可选,传入懒加载的加载子节点的函数 | [点击加载](demo#lazyload-cascader) | -| dropdownPanelClass | `string` | - | 下拉面板的 class,用于用户选中某个面板 | [基本用法](demo#basic-usage) | - -## d-cascader 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :---------: | :---------------------: | :------------------------------------------- | ---------------------------------- | -| toggleEvent | `EventEmitter` | 可选,下拉开关触发事件,返回是否开启的布尔值 | [多选模式](demo#multiple-cascader) | - -## ngModel - -ngModel 在单选模式绑定为选中项的路径值数组'Array',例如[1,2]。 - -ngModel 在多选模式下绑定为所有选中项的路径数组的数组'Array[]', 例如[[1,2], [1,3], [1,4,5]]。 - -ngModelChange 可监听其变化。 - -# 接口 & 类型定义 - -### CascaderItem - -``` -interface CascaderItem { - label: string; - value: number | string; - isLeaf?: boolean; - children?: CascaderItem[]; - disabled?: boolean; - icon?: string; - // 用户可以传入自定义属性,并在dropDownItemTemplate中使用 - [prop: string]: any; -} -``` diff --git a/devui/cascader/doc/api-en.md b/devui/cascader/doc/api-en.md deleted file mode 100644 index 479940f2848a8791e67173fcd993d087a81c1f7d..0000000000000000000000000000000000000000 --- a/devui/cascader/doc/api-en.md +++ /dev/null @@ -1,66 +0,0 @@ -# How to use - -Import into module: - -```ts -import { CascaderModule } from ' ng-devui/cascader'; -``` - -In the page: - -``` - -``` - -# d-cascader - -## d-cascader parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :------------------------------------------------------------------------------: | :------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| trigger | `hover'\|'click'` | 'hover' | Optional, specifying the mode for expanding submenu | [Basic usage](demo#basic-usage) | -| options | [`CascaderItem`](#cascaderitem)`[]` | [] | Mandatory: indicates the menu information of the cascader. | [Basic usage](demo#basic-usage) | -| placeholder | `string` | '' | Optional, This parameter is used to display information in the text box if no value is selected. | [Basic usage](demo#basic-usage) | -| width | `number` | 200 | Optional, The unit is px. It is used to control the width of the widget input box and the width of the drop-down list box. | [Basic usage](demo#basic-usage) | -| dropdownWidth | `number` | width | Optional, The unit is px. Width of the drop-down list box. The default value is the same as the width of the gadget input box. | [Basic usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional, indicating whether the cascader is disabled. | [Basic usage](demo#basic-usage) | -| showPath | `boolean` | false | Optional, Specifies whether to display the path for a selected item in the concatenation. This parameter is valid only in single-choice mode. | [Basic usage](demo#basic-usage) | -| allowClear | `boolean` | false | Optional, This parameter specifies whether to clear the alarm. | [Basic usage](demo#basic-usage) | -| multiple | `boolean` | false | Optional, Whether to enable the multi-selection mode of the cascader. If the multi-selection mode is enabled, the checkbox is selected. | [Multi-selection mode](demo#multiple-cascader) | -| canSelectParent | `boolean` | false | Optional, indicates whether a cascade node can be selected. | [Parent node is optional](demo#parent-cascader) | -| checkboxRelation | `{upward: boolean, downward: boolean}` | `{upward: true, downward: true}` | Optional, Advanced status configuration when multiple cascaders are selected. The value up indicates that the status is updated to the parent level, and the value down indicates that the status is updated to the child level. | [Parent optional](demo#parent-cascader) | -| allowSearch | `boolean` | false | Optional, Whether to enable the search mode for the cascader. | [Search mode](demo#search-cascader) | -| dropDownItemTemplate | `TemplateRef` | false | Optional, Transfer a fixed template for rendering drop items. | [Template type](demo#template-cascader) | -| loadChildrenFn | `(value: CascaderItem) => Promise \| Observable` | null | Optional, Transfer the function for loading subnodes in lazy loading | [Click to load](demo#lazyload-cascader) | -| dropdownPanelClass | `string` | - | Class of the drop-down panel, which is used to select a panel. | [Basic usage](demo#basic-usage) | - -## d-cascader event - -| Parameter | Type | Description | Jump to Demo | -| :---------: | :---------------------: | :------------------------------------------------------------------------------------------------- | ------------------------------------------- | -| toggleEvent | `EventEmitter` | : optional. This parameter is used to trigger a drop-down list box. The Boolean value is returned. | [Multi-choice mode](demo#multiple-cascader) | - -## ngModel - -In radio mode, ngModel is bound to the path value array of the selected item'Array', for example, [1,2]. - -In multi-select mode, ngModel is bound to the array 'Array[]' of the path array of all selected items, for example, [[1,2], [1,3], [1,4,5]]. - -ngModelChange can listen to the change. - -# Interface & Type Definition - -### CascaderItem - -``` -interface CascaderItem { -label: string; -value: number | string; -isLeaf? : boolean; -children? : CascaderItem[]; -disabled? : boolean; -icon? : string; -// Users can transfer customized attributes and use them in dropDownItemTemplate. -[prop: string]: any; -} -``` diff --git a/devui/checkbox/checkbox.tsx b/devui/checkbox/checkbox.tsx deleted file mode 100644 index 1b4bd6cd1784f79286a0b61ca880bf8607271997..0000000000000000000000000000000000000000 --- a/devui/checkbox/checkbox.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-checkbox', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-checkbox
- } - } -}) \ No newline at end of file diff --git a/devui/checkbox/demo/checkbox-demo.tsx b/devui/checkbox/demo/checkbox-demo.tsx deleted file mode 100644 index 39d7fc2ed645e54e45b075ccb41ed7e66188601f..0000000000000000000000000000000000000000 --- a/devui/checkbox/demo/checkbox-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-checkbox-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-checkbox-demo
- } - } -}) \ No newline at end of file diff --git a/devui/checkbox/demo/checkbox.route.ts b/devui/checkbox/demo/checkbox.route.ts deleted file mode 100644 index 5843a54436c401dd6b69de6c9e24413009627713..0000000000000000000000000000000000000000 --- a/devui/checkbox/demo/checkbox.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import CheckboxDemoComponent from './checkbox-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: CheckboxDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/checkbox/doc/api-cn.md b/devui/checkbox/doc/api-cn.md deleted file mode 100644 index de907f71a45ead07e91e76a8957681935b1f3231..0000000000000000000000000000000000000000 --- a/devui/checkbox/doc/api-cn.md +++ /dev/null @@ -1,62 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { CheckBoxModule } from 'ng-devui'; -``` - -在页面中使用: - -```html - - -``` - -# d-checkbox - -## d-checkbox 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :-----------------------------: | :---: | :-----------------------------------------------------------------------------------: | --------------------------------- | -| name | `string` | -- | 可选,表单域名,input 原生 name 属性 | [基本用法](demo#checkbox-basic) | -| label | `string` | -- | 可选,显示标签 | [基本用法](demo#checkbox-basic) | -| isShowTitle | `boolean` | true | 可选,是否显示 title 提示,默认显示参数`label`的值 | [基本用法](demo#checkbox-basic) | -| title | `string` | -- | 可选,显示自定义 title 提示内容 | [基本用法](demo#checkbox-basic) | -| disabled | `boolean` | false | 可选,是否禁用 | [基本用法](demo#checkbox-basic) | -| labelTemplate | `TemplateRef` | -- | 可选,标签的自定义模板 | [基本用法](demo#checkbox-basic) | -| halfchecked | `boolean` | false | 可选,半选状态 | [基本用法](demo#checkbox-basic) | -| color | `string` | -- | 可选,复选框颜色 | [基本用法](demo#checkbox-basic) | -| showAnimation | `boolean` | true | 可选,控制是否显示动画 | [基本用法](demo#checkbox-basic) | -| beforeChange | `Function\|Promise\|Observable` | -- | 可选,checkbox 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 checkbox 切换 | [回调切换](demo#condition-change) | - -## d-checkbox 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----: | :---------------------: | :--------------------------------------: | ------------------------------- | -| change | `EventEmitter` | 复选框的值改变时发出的事件,值是当前状态 | [基本用法](demo#checkbox-basic) | - -# d-checkbox-group - -## d-checkbox-group 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :-----------------------------: | :------: | :-----------------------------------------------------------------------------------------: | ------------------------------------- | -| name | `string` | -- | 可选,表单域名,input 原生 name 属性 | [使用 CheckBoxGroup](demo#tabs-group) | -| direction | `'row'\|'column'` | 'column' | 可选,显示方向 | [使用 CheckBoxGroup](demo#tabs-group) | -| itemWidth | `number` | -- | 可选,表示每一项 checkbox 的宽度(`px`) | [使用 CheckBoxGroup](demo#tabs-group) | -| isShowTitle | `boolean` | true | 可选,是否显示 title 提示 | [使用 CheckBoxGroup](demo#tabs-group) | -| options | `Array` | [] | 可选,复选框选项数组 | [使用 CheckBoxGroup](demo#tabs-group) | -| filterKey | `string` | -- | 可选,options 为对象数组时,标识选项唯一 id 的键值 | [使用 CheckBoxGroup](demo#tabs-group) | -| labelTemplate | `TemplateRef` | -- | 可选,标签的自定义模板 | [使用 CheckBoxGroup](demo#tabs-group) | -| halfchecked | `boolean` | false | 可选,半选状态 | | -| color | `string` | -- | 可选,复选框颜色 | [使用 CheckBoxGroup](demo#tabs-group) | -| showAnimation | `boolean` | true | 可选,控制是否显示动画 | [使用 CheckBoxGroup](demo#tabs-group) | -| beforeChange | `Function\|Promise\|Observable` | -- | 可选,checkbox 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 checkbox-group 切换 | [回调切换](demo#condition-change) | -| disabled | `boolean` | false | 可选,是否禁用整个按钮组 | [使用 CheckBoxGroup](demo#tabs-group) | - -## d-checkbox-group 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----: | :---------------------: | :-----------------: | ------------------------------------- | -| change | `EventEmitter` | checkbox 值改变事件 | [使用 CheckBoxGroup](demo#tabs-group) | diff --git a/devui/checkbox/doc/api-en.md b/devui/checkbox/doc/api-en.md deleted file mode 100644 index cb09d23d9181bcc5658073190d9b62cab64d314b..0000000000000000000000000000000000000000 --- a/devui/checkbox/doc/api-en.md +++ /dev/null @@ -1,62 +0,0 @@ -# How to use - -Import into module: - -```ts -import { CheckBoxModule } from 'ng-devui'; -``` - -In the page: - -```html - - -``` - -# d-checkbox - -## d-checkbox Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------: | :-----------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------- | -| name | `string` | -- | Optional. Form domain name. The native name attribute is input. | [Basic usage](demo#checkbox-basic) | -| label | `string` | -- | Optional. Display labels. | [Basic usage](demo#checkbox-basic) | -| isShowTitle | `boolean` | true | Optional. Indicates whether to display the title prompt. The value of the `label` parameter is displayed by default. | [Basic usage](demo#checkbox-basic) | -| title | `string` | -- | Optional. Display the customized title prompt content. | [Basic usage](demo#checkbox-basic) | -| disabled | `boolean` | false | Optional. Indicating whether to disable it. | [Basic usage](demo#checkbox-basic) | -| labelTemplate Template | `TemplateRef` | -- | Optional. Custom template of the label | [Basic usage](demo#checkbox-basic) | -| halfchecked | `boolean` | false | Optional. Half-selected state | [Basic usage](demo#checkbox-basic) | -| color | `string` | -- | Optional. Check box color | [Basic usage](demo#checkbox-basic) | -| showAnimation | `boolean` | true | Optional. Controls whether to display animations. | [Basic usage](demo#checkbox-basic) | -| beforeChange | `Function\|Promise\|Observable` | -- | Callback function before checkbox switching, which returns the boolean type. If false is returned, checkbox switching is prevented. | [Stop Checkbox Switching](demo#condition-change) | - -## d-checkbox Event - -| Event | Type | Description | Jump to Demo | -| :----: | :---------------------: | :-------------------------------------------------------------------------------------------: | ---------------------------------- | -| change | `EventEmitter` | Event that is raised when the value of the check box changes. The value is the current state. | [Basic usage](demo#checkbox-basic) | - -# d-checkbox-group - -## d-checkbox-group Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------: | :-----------------------------: | :------: | :-------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------- | -| name | `string` | -- | Optional. Form domain name. The native name attribute is input. | [Checkbox Group](demo#tabs-group) | -| direction | `'row'\|'column'` | 'column' | Optional. Display direction | [Checkbox Group](demo#tabs-group) | -| itemWidth | `number` | -- | Optional. Indicating the width of each checkbox (`px`). | [Checkbox Group](demo#tabs-group) | -| isShowTitle | `boolean` | true | Optional. Whether to display the title prompt | [Checkbox Group](demo#tabs-group) | -| options | `Array` | [] | Optional. Check box option array | [Checkbox Group](demo#tabs-group) | -| filterKey | `string` | -- | Optional. When options is an object array, this parameter identifies the key value of the unique ID of the option. | [Checkbox Group](demo#tabs-group) | -| labelTemplate | `TemplateRef` | -- | Optional. Custom template of the label | [Checkbox Group](demo#tabs-group) | -| halfchecked | `boolean` | false | Optional. Half-selected | | -| color | `string` | -- | Optional. Check box color | [Checkbox Group](demo#tabs-group) | -| showAnimation | `boolean` | true | Optional. Controls whether to display animations. | [Checkbox Group](demo#tabs-group) | -| beforeChange | `Function\|Promise\|Observable` | -- | Callback function before checkbox switching, which returns the boolean type. If false is returned, checkbox-group switching is prevented. | [Stop Checkbox Switching](demo#condition-change) | -| disabled | `boolean` | false | Optional. Whether to disable the entire button group. | [Checkbox Group](demo#tabs-group) | - -## d-checkbox-group Event - -| Event | Type | Description | Jump to Demo | -| :----: | :---------------------: | :-------------------------: | -------------------------------------- | -| change | `EventEmitter` | Checkbox value change event | [Checkbox Group](demo#tabs-group) | diff --git a/devui/data-table/data-table.tsx b/devui/data-table/data-table.tsx deleted file mode 100644 index 8fd19dfe4f2a9ba6a143462cfa56a1a5ea8cd977..0000000000000000000000000000000000000000 --- a/devui/data-table/data-table.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-data-table', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-data-table
- } - } -}) \ No newline at end of file diff --git a/devui/data-table/demo/data-table-demo.tsx b/devui/data-table/demo/data-table-demo.tsx deleted file mode 100644 index 4a43bbc75b37db91dbe9db5ecaf4ac0e1d0153cd..0000000000000000000000000000000000000000 --- a/devui/data-table/demo/data-table-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-data-table-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-data-table-demo
- } - } -}) \ No newline at end of file diff --git a/devui/data-table/demo/data-table.route.ts b/devui/data-table/demo/data-table.route.ts deleted file mode 100644 index 856ac5416f271fd09bfe5323562168b091c22f6b..0000000000000000000000000000000000000000 --- a/devui/data-table/demo/data-table.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import DataTableDemoComponent from './data-table-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: DataTableDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/data-table/doc/api-cn.md b/devui/data-table/doc/api-cn.md deleted file mode 100644 index 5eeea1827806f94f4fb341e4ea8b714a70d2b54a..0000000000000000000000000000000000000000 --- a/devui/data-table/doc/api-cn.md +++ /dev/null @@ -1,442 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { DataTableModule } from 'ng-devui/data-table'; -``` - -在页面中使用: - -```html - -``` - -## d-data-table - -### d-data-table 参数 -| 参数名 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------------: | :---------------------------: | :----- | :----------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------- | -| dataSource | `any[]` | -- | 必选,数据源,用于渲染表格数据 | [基本用法](demo#basic-usage) | -| lazy | `boolean` | -- | 可选,是否懒加载数据 | [列表数据懒加载](demo#lazy-loading-of-list-data) | -| scrollable | `boolean` | -- | 可选,表格在超出容器时,是否可以通过滚动查看表格内容 | [表格交互](demo#table-interaction) | -| maxWidth | `string px` | -- | 可选,限制表格最大宽度,默认撑满父容器 | -| maxHeight | `string px` | -- | 可选,限制最大高度,默认 | [表头固定](demo#table-fixing) | -| size | `'sm'\|'md'\|'lg'` | 'sm' | 可选,表格大小,分别对应行高40px,48px,56px |[表格样式](demo#mutil-styles) | -| rowHoveredHighlight | `boolean` | true | 可选,鼠标悬浮行时是否高亮,默认高亮认 | -| generalRowHoveredData | `boolean` | false | 可选,使用配置column方式实现table,鼠标悬浮行时$hovered是否记录到rowItem中,默认不记录 | -| cssClass | `string` | -- | 可选,自定义表格样式 | -| tableWidth | `string` | 100% | 可选,表格宽度 | -| tableHeight | `string` | -- | 可选,表格高度,取值'100%'时依赖table父容器的高度 | [虚拟滚动](demo#virtual-scroll) | -| containFixHeaderHeight | `boolean` | false | 可选,固定表头指定的高度是否包含表头高度,`tableHeight`设置的高度默认是表格body的高度 | [固定表头虚拟滚动](demo#fixed-virtual-scroll) | -| checkableRelation | [`CheckableRelation`](#checkablerelation) | -- | 可选,配置树形表格的父子选中是否互相关联 | [树形表格](demo#tree-form) | -| loadChildrenTable | `Promise` | -- | 可选,展开子表格的回调,用于异步加载子表格 | [树形表格](demo#tree-form) | -| loadAllChildrenTable | `Promise` | -- | 可选,表头展开所有子表格的回调,用于异步加载所有子表格 | [树形表格](demo#tree-form) | -| colDraggable | `boolean` | false | 可选,表格列是否可拖动排序 | [列拖拽](demo#column-dragging) | -| colDropFreezeTo | `number` | 0 | 可选,表格列可拖动排序时配置前n列不可拖动 | [列拖拽](demo#column-dragging) | -| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动 | [虚拟滚动](demo#virtual-scroll) | -| virtualItemSize | `number` | 40 | 可选,虚拟滚动时每一行的高度,默认为表格默认行高40`px` | [虚拟滚动](demo#virtual-scroll) | -| virtualMinBufferPx | `number` | 80 | 可选,虚拟滚动时缓冲区最小像素高度,低于该值时将加载新结构 | [虚拟滚动](demo#virtual-scroll) | -| virtualMaxBufferPx | `number` | 200 | 可选,虚拟滚动时缓冲区最大像素高度 | [虚拟滚动](demo#virtual-scroll) | -| tableWidthConfig | [`TableWidthConfig[]`](#tablewidthconfig) | [] | 可选,配置表格的列宽 | [基本用法](demo#basic-usage) | -| checkable | `boolean` | -- | 可选,Datatable是否提供勾选行的功能 | [表格交互](demo#table-interaction) | -| checkOptions | [`TableCheckOptions[]`](#tablecheckoptions) | -- | 可选,表头选中的下拉项及操作 | [自定义表格选中操作](demo#table-check-options) | -| headerCheckDisabled | `boolean` | -- | 可选,表头checkbox是否disabled | -| headerCheckVisible | `boolean` | true | 可选,表头checkbox是否可见 | -| showExpandToggle | `boolean` | -- | 可选,是否提供显示扩展行的功能,为true则在配置了扩展行的行前面生成操作按钮 | [扩展行](demo#expand-row) | -| showSortIcon | `boolean` | true | 可选,是否显示排序未激活图标,默认显示 | [表格交互](demo#table-interaction) | -| showOperationArea | `boolean` | false | 可选,配置表头操作未激活状态下是否显示操作区域,默认不显示 | [表格交互](demo#table-interaction) | -| hideColumn | `string[]` | -- | 可选,用于隐藏列 | -| pageAllChecked | `boolean` | -- | 可选,选中当前页所有row | -| onlyOneColumnSort | `boolean` | -- | 可选,是否限制多列排序的输出限制为一项 | [表格交互](demo#table-interaction) | -| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | 可选,多列选择数组,用来指导那几列会被排序 | [表格交互](demo#table-interaction) | -| resizeable | `boolean` | -- | 可选,是否可以拖拽调整列宽 | [表格交互](demo#table-interaction) | -| timeout | `number` | 300 | 可选,同时绑定单击、双击事件时,用于区分点击的时间间隔, 默认300`ms`,两个事件不同时使用可以指定为0 | -| headerExpandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | 可选,配置header下的额外内容 | [扩展行](demo#expand-row) | -| beforeCellEdit | `Promise` | -- | 可选,单元格编辑前的拦截方法,
resolve(extraOptions)将更新该列的extraOptions | [编辑单元格](demo#edit-cell) | -| headerBg | `boolean` | false | 可选,表头是否显示背景色 | [表格样式](demo#mutil-styles) | -| tableLayout | `'fixed'\|'auto'` | 'fixed' | 可选,表格布局 | [表格样式](demo#mutil-styles) | -| borderType | `''\|'bordered'\|'borderless'` | '' | 可选,表格边框类型,默认有行边框,bordered:全边框,borderless:无边框 | [表格样式](demo#mutil-styles) | -| striped | `boolean` | false | 可选,表格是否展示为斑马纹间隔 | [表格样式](demo#mutil-styles) | - -### d-data-table 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :-------------------: | :------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | -| rowCheckChange | `EventEmitter` | 某一行的勾选状态变化事件 | -| checkAllChange | `EventEmitter` | 当前页码全勾选状态变化事件 | -| resize | `EventEmitter` | 列宽变化事件,返回单元格信息 | [表格交互](demo#table-interaction) | -| childrenTableClose | `EventEmitter` | 子列表关闭事件,返回列表行信息 | -| allChildrenTableClose | `EventEmitter` | 全部子列表关闭事件 | -| multiSortChange | `EventEmitter` | 多列选择Change事件,用来更新多列选择数组,返回单元格信息 | [表格交互](demo#table-interaction) | -| cellClick | `EventEmitter` | 表格单元格点击事件,返回单元格信息 | [表格交互](demo#table-interaction) | -| cellDBClick | `EventEmitter` | 表格单元格双击事件,返回单元格信息 | [表格交互](demo#table-interaction) | -| rowClick | `EventEmitter` | 表格行点击事件,返回行信息 | [表格交互](demo#table-interaction) | -| rowDBClick | `EventEmitter` | 表格行双击事件,返回行信息 | [表格交互](demo#table-interaction) | -| detialToggle | `EventEmitter` | 使用配置column方式时扩展行展开收起事件,返回行状态信息 | [扩展行](demo#expand-row)| -| cellEditStart | `EventEmitter` | 表格单元格开始编辑事件,返回单元格信息 | -| cellEditEnd | `EventEmitter` | 表格单元格结束编辑事件,返回单元格信息 | [编辑单元格](demo#edit-cell) | -| tableScrollEvent | `EventEmitter` | 表格内部滚动事件 | - - -### d-data-table 公共方法 - -| 方法名 | 参数 | 默认值 | 描述 | 跳转 Demo | -| :--------------------------: | :-----------------------: | :----- | :------------------------------------------------------------------: | :------------------------------------------------------: | -| getCheckedRows | -- | -- | 获取当前选中的行数据 | [表格交互](demo#table-interaction) | -| setRowCheckStatus | [`RowCheckChangeEventArg`](#rowcheckchangeeventarg) | -- | 设置某一行的选中状态,可以处理表头、父子表格的选中关系 | [表格交互](demo#table-interaction) | -| setTableCheckStatus | [`TableCheckStatusArg`](#tablecheckstatusarg) | -- | 设置当前表格的全选、半选状态 | -| setRowChildToggleStatus | [`RowToggleStatusEventArg`](#RowToggleStatusEventArg) | -- | 设置某一行的子表格展开、收起状态,处理异步加载子表格的选中状态时调用 | [树形表格](demo#tree-form) | -| setTableChildrenToggleStatus | `open: boolean` | -- | 设置当前表格的所有子表格展开、收起状态 | [树形表格](demo#tree-form) | -| cancelEditingStatus | -- | -- | 取消正在编辑单元格的编辑状态 | [编辑单元格](demo#edit-cell) | - -### rowItem参数(行数据rowItem为dataSource的数组元素,可以初始化行数据的以下字段配置表格的行为) - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------: | :-------: | :----- | :--------------------------: | :------------------------------------------------------: | -| $checked | `boolean` | false | 可选,该行是否选中 | [表格交互](demo#table-interaction) | -| $halfChecked | `boolean` | false | 可选,该行是否半选 | [表格交互](demo#table-interaction) | -| $isChildTableOpen | `boolean` | false | 可选,该行下的子表格是否展开 | [树形表格](demo#tree-form) | -| children | array | -- | 配置该行的子table数据 | [树形表格](demo#tree-form) | -| $checkDisabled | `boolean` | false | 可选,该行是否禁止选中 | [表格交互](demo#table-interaction) | -| $checkBoxTips | `string` | -- | 可选,配置该行checkbox的提示 | [表格交互](demo#table-interaction) | - -# dTableHead - -## dTableHead 参数 - -| 参数名 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-----------: | :-------------------: | :----- | :------------------------------------------------------------------: | :------------------------------------------------------------------- | -| checkable | `boolean` | -- | 可选,在表头第一列显示checkbox,用于全选,可以跟行数据的选中状态联动 | [表格交互](demo#table-interaction) | -| checkOptions | `TableCheckOptions[]` | -- | 可选,表头选中的下拉项及操作 | [自定义表格选中操作](demo#table-check-options) | -| checkDisabled | `boolean` | -- | 可选,表头checkbox是否disabled | - - -## dHeadCell 参数 - -| 参数名 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------------: | :----------------------------------------: | :----- | :-----------------------------------------------------------: | :------------------------------------------------------- | -| resizeEnabled | `boolean` | -- | 可选,该列宽度是否可调整 | [表格交互](demo#table-interaction) | -| maxWidth | `string` | -- | 可选,调整宽度时的最大宽度,单位`px` | -| minWidth | `string` | -- | 可选,调整宽度时的最小宽度,单位`px` | -| filterable | `boolean` | -- | 可选,该列宽度是否可过滤 | [表格交互](demo#table-interaction) | -| closeFilterWhenScroll | `boolean` | -- | 可选,表格或者body滚动时是否关闭过滤框 | [表格交互](demo#table-interaction) | -| customFilterTemplate | `TemplateRef` | -- | 可选,过滤弹出框的自定义模板 | [表格交互](demo#table-interaction) | -| extraFilterTemplate | `TemplateRef` | -- | 可选,过滤弹出框扩展区域自定义模板 | [表格交互](demo#table-interaction) | -| searchFn | `(term: string) => Observable>` | | 可选,过滤时输入关键字的匹配方法 | -| filterList | `array` | -- | 过滤列表,当filterable为true时必选 | [表格交互](demo#table-interaction) | -| filterMultiple | `boolean` | -- | 可选,设置该列为多选或单选, true为多选,false为单选 | [表格交互](demo#table-interaction) | -| filterBoxWidth | `string` | -- | 过滤弹出框的宽度,如:‘300px’ | -| filterBoxHeight | `string` | -- | 过滤弹出框的高度,如:‘400px’ | -| beforeFilter | `function\|Promise\|Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | -| sortable | `boolean` | -- | 可选,该列是否可排序 | [表格交互](demo#table-interaction) | -| sortDirection | `SortDirection` | -- | 可选,设置该列的已排序状态 | [表格交互](demo#table-interaction) | -| nestedColumn | `boolean` | -- | 可选,是否展示树形表格的表头展开\折叠图标 | [树形表格](demo#tree-form) | -| iconFoldTable | `DOMString` | -- | 可选,自定义树形表格的折叠图标 | [树形表格](demo#tree-form) | -| iconUnFoldTable | `DOMString` | -- | 可选,自定义树形表格的展开图标 | [树形表格](demo#tree-form) | -| fixedLeft | `string` | -- | 可选,该列固定到左侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | -| fixedRight | `string` | -- | 可选,该列固定到右侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | - -## dHeadCell 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :----------------------: | :-----------------: | :-------------------------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | 确认筛选回调事件,返回选中的筛选数组 | [表格交互](demo#table-interaction) | -| sortChange | `SortEventArg` | 排序回调事件,返回该列排序信息 | [表格交互](demo#table-interaction) | -| resizeStartEvent | `MouseEvent` | 该列宽度调整开始时的事件 | -| resizingEvent | `{ width: string }` | 该列宽度调整进行中的事件 | -| resizeEndEvent | `{ width: string }` | 该列宽度调整结束时的事件 | [表格交互](demo#table-interaction) | -| toggleChildrenTableEvent | `boolean` | 所有子表格展开收起事件,true表示展开,false表示收起 | - -# dTableCell - -## dTableCell 参数 - -| 参数名 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------: | :-----------------------------: | :----- | :------------------------------------------------------------: | :------------------------------------------------- | -| editable | `boolean` | -- | 可选,单元格是否可编辑 | [编辑单元格](demo#edit-cell) | -| editableTip | `'hover'\|'btn'` | -- | 可选,编辑提示,hover背景变色,btn展示编辑按钮 | [编辑单元格](demo#edit-cell) | -| nestedColumn | `boolean` | -- | 可选,树形表格下该行有子表格时展示展开、折叠图标 | [树形表格](demo#tree-form) | -| nestedLayer | `number` | | 树形表格下的层级,nestedColumn为true时必选 | [树形表格](demo#tree-form) | -| rowItem | `array` | -- | 行数据,nestedColumn为true时必选,也可作为单元格编辑的回调参数 | [树形表格](demo#tree-form) | -| beforeEditStart | `function\|Promise\|Observable` | -- | 可选,单元格开始编辑前回调,返回false阻止单元格开始编辑 | [编辑单元格](demo#edit-cell) | -| beforeEditEnd | `function\|Promise\|Observable` | -- | 可选,单元格结束编辑前的回调,返回false阻止单元格结束编辑 | [编辑单元格](demo#edit-cell) | -| iconFoldTable | `DOMString` | -- | 可选,自定义树形表格的折叠图标 | [树形表格](demo#tree-form) | -| iconUnFoldTable | `DOMString` | -- | 可选,自定义树形表格的展开图标 | [树形表格](demo#tree-form) | -| fixedLeft | `string` | -- | 可选,该列固定到左侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | -| fixedRight | `string` | -- | 可选,该列固定到右侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | -| editing | `boolean` | -- | 可选,使用[(editing)]获取和控制单元格编辑状态 | [编辑单元格](demo#edit-cell) | -| field | `string` | -- | 单元格所属列的字段,作为beforeEditStart、beforeEditEnd的参数 | [编辑单元格](demo#edit-cell) | - -## dTableCell 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :-------------------: | :-------: | :-----------------------------------------------------: | :------------------------------------------------- | -| editStatusEvent | `boolean` | 单元格编辑状态事件 | [编辑单元格](demo#edit-cell) | -| toggleChildTableEvent | `boolean` | 当前行的子表格展开收起事件,true表示展开,false表示收起 | [树形表格](demo#tree-form) | - -#### 使用自定义模板方式时配置dTableBody的行模板 - -实现参考**[树形表格](demo#tree-form)** - -``` html - - - -// rowItem: 行数据 -// rowIndex: 行序号 -// nestedLayer: 树形表格下该行所属表格的层级,由组件生成,最外层表格为0,自增长 -// nestedIndex: 树形表格下的行索引,由组件生成 -``` - -#### 配置数据为空的时候的提示模板 - -表格接受 `#noResultTemplateRef` 模板,实现参考**[异步加载数据](demo#async-loading)** - -#### 自定义过滤弹出框 - -实现参考**[表格交互](demo#table-interaction)** - -``` html - - - - -// filterListDisplay: 传入的filterList的值 -// dropdown: 获取dropdown的引用,主要用于控制弹出框的打开和关闭 -// column: 使用配置column实现的,当前列的元信息,对应DataTableColumnTmplComponent类 -``` - -## CheckableRelation - -``` ts -export interface CheckableRelation { - upward: boolean; // 选中子关联父 - downward: boolean; // 选中父关联子 -} -``` - -## TableWidthConfig - -```ts -export interface TableWidthConfig { - field: string; // 列名 - width: string; // 宽度,单位px -} -``` - -## TableCheckOptions - -```ts -export interface TableCheckOptions { - label: string; - onChecked: Function; -} -``` - -## SortEventArg - -```ts -export interface SortEventArg { - field?: string; // 列名 - direction: SortDirection; // 顺序 -} -``` - -## TableExpandConfig - -```ts -export interface TableExpandConfig { - expand ? : boolean, // 是否展开 - expandTemplateRef ? : ElementRef, //自定义模板 - description ? : string // 简单描述文字 -} -``` - -## RowCheckChangeEventArg - -```ts -export interface RowCheckChangeEventArg { - rowIndex: number; // 行序号 - nestedIndex: string; // 树形表格下的行索引,由组件生成 - rowItem: any; // 行数据 - checked: boolean; // 是否选中 -} -``` - -## TableCheckStatusArg - -```ts -export interface TableCheckStatusArg { - pageAllChecked?: boolean; // 全选 - pageHalfChecked?: boolean; // 半选 -} -``` - -## RowToggleStatusEventArg - -```ts -export interface RowToggleStatusEventArg { - rowItem: any; // 行数据 - open: boolean; // 子表格是否展开 -} -``` - -## FilterConfig - -```ts -export interface FilterConfig { - id: number | string; - name: string; - value: any; - checked?: boolean; -} -``` - -## SortDirection - -```ts -export enum SortDirection { - ASC = 'ASC', - DESC = 'DESC', - default = '' -} -``` - -# 以下为通过配置column来实现table时的才有的参数和方法 - -## d-column 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------------------------: | :-----------------------------: | :---------------- | :-------------------------------------------------------------------------------------: | :------------------------------------------------------- | -| editable | `boolean` | false | 可选,在d-column上指定该列是否可编辑 | [编辑单元格](demo#edit-cell) | -| maxWidth | `string px` | -- | 可选,最大宽度 | -| minWidth | `string px` | -- | 可选,最小宽度 | -| field | `string` | -- | 该列字段 | [基本用法](demo#basic-usage) | -| header | `string` | -- | 该列表头文字 | [基本用法](demo#basic-usage) | -| sortable | `boolean` | -- | 可选,是否可排序 | [表格交互](demo#table-interaction) | -| editable | `boolean` | -- | 可选,是否可编辑 | [表格交互](demo#table-interaction) | -| width | `string px、%` | -- | 宽度 | [基本用法](demo#basic-usage) | -| nestedColumn | `Boolean` | false | 可选,指定该列作为树形表格的操作列,即有展开\折叠按钮和内容缩进表明层级关系 | [树形表格](demo#tree-form) | -| extraOptions.editableTip | `'btn'、''` | -- | 可选,可编辑提示,'btn'表示鼠标悬浮单元格出现编辑按钮,未配置时鼠标悬浮单元格背景色变化 | [编辑单元格](demo#edit-cell) | -| extraOptions.iconFoldTable | `Template` | -- | 可选,自动定义树形表格的折叠图标 | [树形表格](demo#tree-form) | -| extraOptions.iconUnFoldTable | `Template` | -- | 可选,自动定义树形表格的展开图标 | [树形表格](demo#tree-form) | -| extraOptions.showHeadTableToggler | `boolean` | false | 可选,树形表格是否在header出现展开\折叠图标 | [树形表格](demo#tree-form) | -| order | `number` | Number. MAX_VALUE | 可选,列序号 | [基本用法](demo#basic-usage) | -| filterable | `boolean` | -- | 可选,是否可筛选 | [表格交互](demo#table-interaction) | -| closeFilterWhenScroll | `boolean` | -- | 可选,表格或者body滚动时是否关闭过滤框 | [表格交互](demo#table-interaction) | -| filterList | `array` | -- | 传入需要操作的筛选列表,当filterable为true时必选 | [表格交互](demo#table-interaction) | -| filterMultiple | `boolean` | true | 可选,选择筛选列表为多选或单选, true为多选,false为单选 | [表格交互](demo#table-interaction) | -| customFilterTemplate | `TemplateRef` | -- | 可选,表格过滤弹出框的自定义模板,参考DOC下‘自定义过滤弹出框’使用 | [表格交互](demo#table-interaction) | -| extraFilterTemplate | `TemplateRef` | -- | 可选,表格过滤弹出框扩展区域自定义模板 | [表格交互](demo#table-interaction) | -| beforeFilter | `function、Promise、Observable` | -- | 可选,表格过滤弹出框弹出前的回调函数,返回false可阻止弹框弹出 | [表格交互](demo#table-interaction) | -| cellClass | `string` | -- | 该列单元格自定义class | -| fixedLeft | `string` | -- | 该列固定到左侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | -| fixedRight | `string` | -- | 该列固定到右侧的距离,如:‘100px’ | [固定列](demo#fixed-column) | -| filterBoxWidth | `any` | -- | 过滤弹出框的宽度,如:‘300px’ | -| filterBoxHeight | `any` | -- | 过滤弹出框的高度,如:‘400px’ | - -## d-column 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :----------: | :--------------: | :----------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | 确认筛选回调事件,返回选中的筛选数组 | [表格交互](demo#table-interaction) | - -## rowItem参数 -| 参数 | 类型 | 默认值 | 描述 | -| :---------------: | :-----------------: | :----- | :-------------------------------------------------------------------------------------------------------: | -| $editDeniedConfig | `array` | -- | 可选,与column配合配置该行的某些单元格的编辑权限,
例如: 配置为['age'],表示field为age的单元格不可编辑 | -| $expandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | 可选,配置该行下的额外内容 | -| $rowClass | `string` | -- | 可选,配置该行的自定义class | -| $hovered | `boolean` | false | 鼠标悬浮该行元素时该值为true,
离开该行时该值为false | - -#### 自定义单元格 - -单元格数据(cellItem, 通过rowItem[column.field]取值)为string类型时,组件可直接展示,当单元格数据为object类型,或者想定义该列单元格的特殊行为时,需要自定义单元格来进行展示; -例如:我们想 `Gender` 这一列的数据大写展示, 并在鼠标移动上去展示一个提示,相关节选代码如下 - -``` - - - - - {{cellItem.toUpperCase()}} - - - - -``` - -#### 自定义单元格编辑模板 - -Datatable支持通过模板自定义单元格编辑功能 - -``` - - - - - - - -``` - -自定义单元格和配置单元格编辑时的完整template如下 - -``` xml - - - - -// rowIndex: 行序号 -// colIndex: 列序号 -// rowItem: 当前行的数据,对应 filed 和 cellItem的键值对 -// column: 当前列的元信息,对应DataTableColumnTmplComponent类 -// cellItem: 当前单元格的值, 通过rowItem[column.field]取值 -// tableLevel: 树形表格下所属表格的层级,最外层为0,自增长 -``` - -#### 自定义表头单元格 - -如果需要表头单元格,列入想展示效果为鼠标移动在表格上方会提示 `Gender is a head cell template` . - -``` xml - - - - - {{column.header}} - - - - - -// column: 为column输入值,对应 `DataTableColumnTmplComponent` 类 -``` - -#### 多行表头和表头合并单元格 - -* 需要在d-column使用时候,增加 - -``` javascript -advancedHeader: Array < { - header: string; - rowspan: number; - colspan: number; -} -``` - -注意: 空单元格也需要表示,并根据内容把rowspan/colspan置为0,如果同时使用列宽拖拽和多行表头,请为列内容附上宽度width,如果第一行的列宽度不正确,请手动为advancedHeader[rowNumber]增加一个属性$width diff --git a/devui/data-table/doc/api-en.md b/devui/data-table/doc/api-en.md deleted file mode 100644 index f402f8669728f0ae847dcbb5c5bfc47d2ca1800c..0000000000000000000000000000000000000000 --- a/devui/data-table/doc/api-en.md +++ /dev/null @@ -1,426 +0,0 @@ -# How to use - -Import the following information into the module: - -```ts -import {DataTableModule} from' ng-devui/data-table'; -``` - -On the page: - -```html - -``` - -# d-data-table - -## d-data-table parameter -| Parameter name | Type | Default value | Description | Jump to Demo | -| :-------------------: | :---------------------------: | :----- | :----------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------- | -| dataSource | `any[]` | -- | Required. Data source, used to render table data | [Basic usage](demo#basic-usage) | -| lazy | `boolean` | -- | Optional. Indicating whether to lazy load data | [Low load list data](demo#lazy-loading-of-list-data) | -| scrollable | `boolean` | -- | Optional. Whether the table content can be viewed by scrolling when the table exceeds the container. | [Table interaction](demo#table-interaction) | -| maxWidth | `string px` | -- | Optional. Limit the maximum table width. By default, the parent container is full. | -| maxHeight | `string px` | -- | Optional. The maximum height is limited. The default value is | [fixed table header](demo#table-fixing) | -| size | `'sm'\|'md'\|'lg'`| 'sm' | Optional. Specifies the table size, which corresponds to 40 px, 48 px, and 56 px respectively | [Table style](demo#mutil-styles) | -| rowHoveredHighlight | `boolean` | true | Optional. Indicating whether to highlight a line when the cursor is hovering. The default value is highlighted. | -| generalRowHoveredData | `boolean` | false | Optional. It is used to configure columns to implement the table. When the cursor is moved to a row, $hovered is recorded to the row item. By default, $hovered is not recorded. | -| cssClass | `string` | -- | Optional. Customize the table style | -| tableWidth | `string` | 100% | Optional. Table width | -| tableHeight | `string` | -- | Optional. Table height. The value 100% depends on the height of the table parent container. | [Virtual scrolling](demo#virtual-scroll) | -| containFixHeaderHeight | `boolean` | false | Optional. whether the height specified by the fixed header includes the height of the header, the height set by tableHeight is the height of the table body by default | [Fixed table header virtual scrolling](demo#fixed-virtual-scroll) | -| checkableRelation | [`CheckableRelation`](#checkablerelation) | -- | Optional. This parameter specifies whether the parent and child selections in the tree table are associated. | [Tree table](demo#tree-form) | -| loadChildrenTable | `Promise` | -- | Optional. It is the callback of subtable expansion, which is used to asynchronously load subtables. | [Tree table](demo#tree-form) | -| loadAllChildrenTable | `Promise` | -- | Optional. It is the callback for expanding all subtables in the table header. It is used to asynchronously load all subtables. | [Tree table](demo#tree-form) | -| colDraggable | `boolean` | false | Optional. Whether columns can be dragged or sorted | [Column dragging](demo#column-dragging) | -| colDropFreezeTo | `number` | 0 | Optional. The first n columns cannot be dragged when the table columns can be sorted. | [Column dragging](demo#column-dragging) | -| virtualScroll | `boolean` | false | Optional. Specifies whether to enable virtual scrolling. | [Virtual scrolling](demo#virtual-scroll) | -| virtualItemSize | `number` | 40 | Optional. Height of each row during virtual scrolling. The default value is 40`px`. | [Virtual scrolling](demo#virtual-scroll) | -| virtualMinBufferPx | `number` | 80 | Optional. Minimum pixel height of the buffer during virtual scrolling. If the pixel height is less than this value, the new structure is loaded. | [Virtual scrolling](demo#virtual-scroll) | -| virtualMaxBufferPx | `number` | 200 | Optional. Maximum pixel height of the buffer during virtual scrolling | [virtual scrolling](demo#virtual-scroll) | -| tableWidthConfig | [`TableWidthConfig[]`](#tablewidthconfig) | [] | Optional. It is used to configure the column width of the table. | [Basic usage](demo#basic-usage) | -| checkable | `boolean` | -- | Optional. Whether the Datatable provides the function of selecting rows. | [Table interaction](demo#table-interaction) | -| checkOptions | [`TableCheckOptions[]`](#tablecheckoptions) | -- | Optional. drop-down list box in the table header and operations | [Customized table selection](demo#table-check-options) | -| headerCheckDisabled | `boolean` | -- | Optional. Indicates whether the header checkbox is disabled. | -| headerCheckVisible | `boolean` | true | Optional. Indicates whether the checkbox in the header is visible. | -| showExpandToggle | `boolean` | -- |: Indicates whether to display extended rows. If the value is true, an operation button is generated before the row where extended rows are configured. | [Extended row](demo#expand-row) | -| showSortIcon | `boolean` | true | Optional. Indicates whether to display the inactive sorting icon. The icon is displayed by default. | [Table interaction](demo#table-interaction) | -| showOperationArea | `boolean` | false | Optional. Indicates whether to display the operation area when the table header operation is not activated. Not displayed by default. | [Table interaction](demo#table-interaction) | -| hideColumn | `string[]` | -- | Optional. Used to hide columns | -| pageAllChecked | `boolean` | -- | Optional. Select all rows on the current page. | -| onlyOneColumnSort | `boolean` | -- | Optional. Whether to restrict the output of multi-column sorting to one item | [Table interaction](demo#table-interaction) | -| multiSort | [`SortEventArg[]`](#sorteventarg) | [] | Optional. It is a multi-column selection array, which is used to guide the columns to be sorted. | [Table interaction](demo#table-interaction) | -| resizeable | `boolean` | -- | Optional. Whether the column width can be adjusted by dragging. | [Table interaction](demo#table-interaction) | -| timeout | `number` | 300 | Optional. This parameter is used to distinguish the click interval when the click and double-click events are bound at the same time. The default value is 300`ms`. You can set this parameter to 0 when the two events are used at the same time. | -| headerExpandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | Optional. Extra content under the header | [Extended line](demo#expand-row) | -| beforeCellEdit | `Promise` | -- | Optional. Interception method before cell editing.
resolve(extraOptions) updates extraOptions of the column. | [edit cell](demo#edit-cell) | -| headerBg | `boolean` | false | Optional. Indicating whether to display the background color in the table header | [Table style](demo#mutil-styles) | -| tableLayout | `'fixed'\|'auto'` | 'fixed' | Optional. Table layout | [Table style](demo#mutil-styles) | -| borderType | `''\|'bordered'\|'borderless'` | '' | Optional. Table border type. The default value is row border. The options are bordered (full border) and borderless (no border). | [Table style](demo#mutil-styles) | -| striped | `boolean` | false | Optional. Whether to display the table with zebra stripes. | [Table style](demo#mutil-styles) | - -## d-data-table event - -| Event | Type | Description | Jump to Demo | -| :-------------------: | :------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | -| rowCheckChange | `EventEmitter` | Selected status change event of a line | -| checkAllChange | `EventEmitter` | Event of Selecting All Current Pages | -| resize | `EventEmitter` | Column Width Change Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | -| childrenTableClose | `EventEmitter` | Event for closing a sublist. The list row information is returned. | -| allChildrenTableClose | `EventEmitter` | All Sublist Close Event | -| multiSortChange | `EventEmitter` | Change event, which is used to update the multi-column selection array and return cell information. | [Table interaction](demo#table-interaction) | -| cellClick | `EventEmitter` | Cell Click Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | -| cellDBClick | `EventEmitter` | Cell Double-click Event, Returning Cell Information | [Table Interaction](demo#table-interaction) | -| rowClick | `EventEmitter` | Table row click event, which returns row information | [Table interaction](demo#table-interaction) | -| rowDBClick | `EventEmitter` | Double-clicking a table row. Row information is returned. | [Table interaction](demo#table-interaction) | -| detialToggle | `EventEmitter` | Extended row expansion/collapse event. The row status information is returned. | -| cellEditStart | `EventEmitter` | Cell Editing Start Event, Returning Cell Information | -| cellEditEnd | `EventEmitter` | Table cell editing end event. Cell information is returned. | [Edit cell](demo#edit-cell) | -| tableScrollEvent | `EventEmitter` | Table Internal Rolling Event | - -## d-data-table public method - -| Method name | Parameter | Default value | Description | Jump to Demo | -| :--------------------------: | :-----------------------: | :----- | :------------------------------------------------------------------: | :------------------------------------------------------: | -| getCheckedRows | -- | -- | Obtain the data of the selected row. | [Table interaction](demo#table-interaction) | -| setRowCheckStatus | [`RowCheckChangeEventArg`](#rowcheckchangeeventarg) | -- | Sets the selection status of a row, and can process the selection relationship between table headers and parent-child tables. | [Table interaction](demo#table-interaction) | -| setTableCheckStatus | [`TableCheckStatusArg`](#tablecheckstatusarg) | -- | Sets the status of all or half selection of the current table. | -| setRowChildToggleStatus | [`RowToggleStatusEventArg`](#RowToggleStatusEventArg) | -- | Sets the expanded or collapsed status of a subtable in a row. This command is invoked to process the selected status of the subtable in asynchronous loading mode. | [Tree table](demo#tree-form) | -| setTableChildrenToggleStatus | `open: boolean` | -- | Sets the expansion and collapse status of all subtables in the current table. | [Tree table](demo#tree-form) | -| cancelEditingStatus | -- | -- | Cancel the editing status of the cell being edited. | [Editing cell](demo#edit-cell) | - -## rowItem parameter (rowItem is the array element of dataSource. You can initialize the following fields to configure the table behavior.) - -| Parameter | Type | Default value | Description | Jump to Demo | -| :---------------: | :-------: | :----- | :--------------------------: | :------------------------------------------------------: | -| $checked | `boolean` | false | Optional. Whether the row is selected. | [Table interaction](demo#table-interaction) | -| $halfChecked | `boolean` | false | Optional. Whether to select half of the row | [Table interaction](demo#table-interaction) | -| $isChildTableOpen | `boolean` | false | Optional. Whether to expand the subtable in the row | [Tree table](demo#tree-form) | -| children | array | -- | Optional. Configure the subtable data of the row. | [Tree table](demo#tree-form) | -| $checkDisabled | `boolean` | false | Optional. Whether to disable this row | [Table interaction](demo#table-interaction) | -| $checkBoxTips | `string` | -- | Optional. Configure the checkbox prompt for this row. | [Table interaction](demo#table-interaction) | - -# dTableHead - -## dTableHead Parameter - -| Parameter name | Type | Default value | Description | Jump to Demo | -| :-----------: | :-------------------: | :----- | :------------------------------------------------------------------: | :------------------------------------------------------------------- | -| checkable | `boolean` | -- | Optional. The checkbox is displayed in the first column of the table header for selecting all data. The checkbox can be associated with the selection status of the row data. | [Table interaction](demo#table-interaction) | -| checkOptions | `TableCheckOptions[]` | -- | Optional. Drop-down list box in the table header and operations | [Customized table selection](demo#table-check-options) | -| checkDisabled | `boolean` | -- | Optional. Indicates whether the header checkbox is disabled. | - -## dHeadCell Parameter - -| Parameter name | Type | Default value | Description | Jump to Demo | -| :------------------: | :----------------------------------------: | :----- | :-----------------------------------------------------------: | :------------------------------------------------------- | -| resizeEnabled | `boolean` | -- | Optional. Whether the column width can be adjusted | [Table interaction](demo#table-interaction) | -| maxWidth | `string` | -- | Optional. Maximum width during width adjustment. Unit: `px`| -| minWidth | `string` | -- | Optional. Minimum width for adjusting the width. Unit: `px`| -| filterable | `boolean` | -- | Optional. Whether the column width can be filtered. | [Table interaction](demo#table-interaction) | -| closeFilterWhenScroll | `boolean` | -- | Optional. Specifies whether to close the filter box when a table or body is scrolled. | [Table interaction](demo#table-interaction) | -| customFilterTemplate | `TemplateRef` | -- | Optional. This parameter specifies the customized template for filtering pop-up boxes. | [Table interaction](demo#table-interaction) | -| extraFilterTemplate | `TemplateRef` | -- | Optional. This parameter specifies the extra template for filtering pop-up boxes. | [Table interaction](demo#table-interaction) | -| searchFn | `(term: string) => Observable>` | | Optional. The matching method of input keywords when filtering | -| filterList | `array` | -- | Optional. Filter list. This parameter is mandatory when filterable is set to true. | [Table interaction](demo#table-interaction) | -| filterMultiple | `boolean` | -- | Optional. Sets the column to be selected. true indicates that multiple choices are selected, and false indicates that only one choice is selected. | [Table interaction](demo#table-interaction) | -| filterBoxWidth | `string` | -- | Optional. Width of the filter dialog box, for example, 300px. | -| filterBoxHeight | `string` | -- | Optional. Height of the filter dialog box, for example, 400px. | -| beforeFilter | `function\|Promise\|Observable` | -- | Optional. Callback function before the table filtering dialog box is displayed. If false is returned, the dialog box is blocked. | [Table interaction](demo#table-interaction) | -| sortable | `boolean` | -- | Optional. Whether the column can be sorted | [Table interaction](demo#table-interaction) | -| sortDirection | `SortDirection` | -- | Optional. Sets the sorting status of the column. | [Table interaction](demo#table-interaction) | -| nestedColumn | `boolean` | -- | Optional. Indicates whether to display the expand or collapse icon of the table header in the tree table. | [Tree table](demo#tree-form) | -| iconFoldTable | `DOMString` | -- | Optional. Customize the collapse icon of the tree table | [Tree table](demo#tree-form) | -| iconUnFoldTable | `DOMString` | -- | Optional. Customize the expansion icon of the tree table | [Tree table](demo#tree-form) | -| fixedLeft | `string` | -- | Optional. The value is fixed to the left of the column, for example, 100px. | [Fixed column](demo#fixed-column) | -| fixedRight | `string` | -- | Optional. The value is fixed to the right of the column, for example, 100px | [fixed column](demo#fixed-column) | - -## dHeadCell Event - -| Event | Type | Description | Jump to Demo | -| :----------------------: | :-----------------: | :-------------------------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | Callback event for confirming the filtering and returning the selected filtering array. | [Table interaction](demo#table-interaction) | -| sortChange | `SortEventArg` | Sorting callback event, which returns the sorting information of the column. | [Table interaction](demo#table-interaction) | -| resizeStartEvent | `MouseEvent` | Event when the column width adjustment starts | -| resizingEvent | `{width: string}` | Event that the column width is being adjusted | -| resizeEndEvent | `{width: string}` | Event when the column width adjustment ends | [Table interaction](demo#table-interaction) | -| toggleChildrenTableEvent | `boolean` | Event for expanding and collapsing all subtables. The value true indicates expanding, and the value false indicates collapse. | - -# dTableCell - -## dTableCell Parameter - -| Parameter name | Type | Default value | Description | Jump to Demo | -| :-------------: | :-----------------------------: | :----- | :------------------------------------------------------------: | :------------------------------------------------- | -| editable | `boolean` | -- | Optional. Whether a cell can be edited | [edit cell](demo#edit-cell) | -| editableTip | `'hover'\|'btn'` | -- | Optional. This parameter indicates the editing prompt. The background color of the hover changes. The edit button is displayed in the btn. | [edit cell](demo#edit-cell) | -| nestedColumn | `boolean` | -- | Optional. Display the expansion and collapse icons when the row in the tree table contains subtables. | [Tree table](demo#tree-form) | -| nestedLayer | `number` | | Layer in a tree table. This parameter is mandatory when nestedColumn is set to true. | [Tree table](demo#tree-form) | -| rowItem | `array` | -- | Row data. This parameter is mandatory when nestedColumn is set to true and can also be used as the callback parameter for cell editing. | [Tree table](demo#tree-form) | -| beforeEditStart | `function\|Promise\|Observable` | -- | Optional. Callback before the cell starts editing. If false is returned, the cell starts editing. | [Edit cell](demo#edit-cell) | -| beforeEditEnd | `function\|Promise\|Observable` | -- | Optional. Callback function before the cell edit ends. If false is returned, the cell edit stops. | [Edit cell](demo#edit-cell) | -| iconFoldTable | `DOMString` | -- | Optional. Customize the collapse icon of the tree table | [Tree table](demo#tree-form) | -| iconUnFoldTable | `DOMString` | -- | Optional. Customize the expansion icon of the tree table | [Tree table](demo#tree-form) | -| fixedLeft | `string` | -- | Optional. The value is fixed to the left of the column, for example, 100px. | [Fixed column](demo#fixed-column) | -| fixedRight | `string` | -- | Optional. The value is fixed to the right of the column, for example, 100px | [fixed column](demo#fixed-column) | -| editing | `boolean` | -- | Optional. Use [(editing)] to obtain and control the cell editing status. | [editing cell](demo#edit-cell) | -| field | `string` | -- | Field in the column to which the cell belongs, which is used as the parameter beforeEditStart and beforeEditEnd. | [Edit cell](demo#edit-cell) | - -## dTableCell Event - -| Event | Type | Description | Jump to Demo | -| :-------------------: | :-------: | :-----------------------------------------------------: | :------------------------------------------------- | -| editStatusEvent | `boolean` | Cell editing status event | [edit cell](demo#edit-cell) | -| toggleChildTableEvent | `boolean` | Event for expanding and collapsing the subtable in the current row. The options are true and false. | [Tree table](demo#tree-form) | - -#### Configure the row template of the dTableBody when the user-defined template is used. - -For details, see (demo#tree-form)**. - -``` html - - - -// rowItem: row data -// rowIndex: row number. -// nestedLayer: level of the table to which the row belongs in the tree table, which is generated by the component. The outermost table is 0 and increases ascending order. -// nestedIndex: row index in the tree table, which is generated by the component. -``` - -#### Template for prompting that the configuration data is empty - -The table accepts the `#noResultTemplateRef` template. For details, see **[Asynchronous data loading](demo#async-loading)**. - -#### Custom Filter dialog box - -For details, see (demo#table-interaction)**. - -``` html - - - -// filterListDisplay: value of the input filterList. -// dropdown: Obtains the dropdown reference, which is used to control whether to enable or disable the pop-up dialog box. -// column: metadata of the current column, which is implemented using the column configuration, corresponding to the DataTableColumnTmplComponent class. -``` - -## CheckableRelation - -``` ts -export interface CheckableRelation { - upward: boolean; // Select the child association parent. - downward: boolean; // Select the parent associated child. -} -``` - -## TableWidthConfig - -```ts -export interface TableWidthConfig { - field: string; // Column name - width: string; // Width, in px. -} -``` - -## TableCheckOptions - -```ts -export interface TableCheckOptions { - label: string; - onChecked: Function; -} -``` - -## SortEventArg - -```ts -export interface SortEventArg { - field?: string; // Column name - direction: SortDirection; // Sequence -} -``` - -## TableExpandConfig - -```ts -export interface TableExpandConfig { - expand ? : boolean, // Whether to expand - expandTemplateRef ? : ElementRef, // Custom template - description ? : string // Simple description -} -``` - -## RowCheckChangeEventArg - -```ts -export interface RowCheckChangeEventArg { - rowIndex: number; // Row No. - nestedIndex: string; // Row index in the tree table, which is generated by the component. - rowItem: any; // Row data - checked: boolean; // Indicates whether to select the check box. -} -``` - -## TableCheckStatusArg - -```ts -export interface TableCheckStatusArg { - pageAllChecked?: boolean; // Select all. - pageHalfChecked?: boolean; // Partially selected -} -``` - -## RowToggleStatusEventArg - -```ts -export interface RowToggleStatusEventArg { - rowItem: any; // Row data - open: boolean; // Indicates whether to expand the subtable. -} -``` - -## FilterConfig - -```ts -export interface FilterConfig { - id: number | string; - name: string; - value: any; - checked?: boolean; -} -``` - -## SortDirection - -```ts -export enum SortDirection { - ASC = 'ASC', - DESC = 'DESC', - default = '' -} -``` - -# The following table describes the parameters and methods that are available only when a table is implemented by configuring columns. - -## d-column parameter -| Parameter | Type | Default value | Description | Jump to Demo | -| :-------------------------------: | :-----------------------------: | :---------------- | :-------------------------------------------------------------------------------------: | :------------------------------------------------------- | -| editable | `boolean` | false | Optional. Specifies whether the column can be edited on the d-column. | [edit cell](demo#edit-cell) | -| maxWidth | `string px` | -- | Optional. Maximum width | -| minWidth | `string px` | -- | Optional. Minimum width | -| field | `string` | -- | Required. Fields in this column | [Basic usage](demo#basic-usage) | -| header | `string` | -- | Text in the column header | [Basic usage](demo#basic-usage) | -| sortable | `boolean` | -- | Optional. indicating whether to sort data | [Table interaction](demo#table-interaction) | -| editable | `boolean` | -- | Optional. Whether the table can be edited | [Table interaction](demo#table-interaction) | -| width | `string px,%` | -- | width | [basic usage](demo#basic-usage) | -| nestedColumn | `Boolean` | false | Optional. Specifies the column as the operation column of the tree table. That is, the expand/collapse button and the content indentation button are available to indicate the hierarchy. | [Tree table](demo#tree-form) | -| extraOptions.editableTip | `btn', ''` | -- | Optional. This parameter is optional and can be edited. 'btn' indicates that the edit button is displayed when you move the mouse pointer over a cell. When this parameter is not configured, the background color of the cell changes. | [Edit cell](demo#edit-cell) | -| extraOptions.iconFoldTable | `Template` | -- | Optional. The collapse icon of the tree table is automatically defined. | [Tree table](demo#tree-form) | -| extraOptions.iconUnFoldTable | `Template` | -- | Optional. The expansion icon of the tree table is automatically defined. | [Tree table](demo#tree-form) | -| extraOptions.showHeadTableToggler | `boolean` | false | Optional. Indicates whether to display the expand/collapse icon in the header of the tree table. | [Tree table](demo#tree-form) | -| order | `number` | Number. MAX_VALUE | Optional. Column number | [Basic usage](demo#basic-usage) | -| filterable | `boolean` | -- | Optional. indicating whether to filter. | [Table interaction](demo#table-interaction) | -| closeFilterWhenScroll | `boolean` | -- | Optional. Specifies whether to close the filter box when a table or body is scrolled. | [Table interaction](demo#table-interaction) | -| filterList | `array` | -- | Optional. Transfer the filtering list to be operated. This parameter is mandatory when filterable is set to true. | [Table interaction](demo#table-interaction) | -| filterMultiple | `boolean` | true | Optional. The options are as follows: true: multi-choice; false: single-choice. | [Table interaction](demo#table-interaction) | -| customFilterTemplate | `TemplateRef` | -- | Optional. This parameter specifies the customized template of the table filtering dialog box. For details, see the "Customized Filtering Dialog Box" in the DOC. | [Table Interaction](demo#table-interaction) | -| extraFilterTemplate | `TemplateRef` | -- | Optional. This parameter specifies the extra template of the table filtering dialog box. | [Table Interaction](demo#table-interaction) | -| beforeFilter | `function, Promise, Observable` | -- | Optional. Callback function before the table filtering dialog box is displayed. If false is returned, the dialog box is blocked. | [Table interaction](demo#table-interaction) | -| cellClass | `string` | -- | Optional. Custom class of the cell in the column | -| fixedLeft | `string` | -- | Optional. Fixed distance from the column to the left, for example, '100px' | [Fixed column](demo#fixed-column) | -| fixedRight | `string` | -- | Optional. Fixed distance from the column to the right, for example, '100px' | [Fixed column](demo#fixed-column) | -| filterBoxWidth | `any` | -- | Optional. Width of the filter dialog box, for example, 300px. | -| filterBoxHeight | `any` | -- | Optional. Height of the filter dialog box, for example, 400px. | - -## d-column event - -| Event | Type | Description | Jump to Demo | -| :----------: | :--------------: | :----------------------------------: | :------------------------------------------------------- | -| filterChange | `FilterConfig[]` | Callback event for confirming the filtering and returning the selected filtering array. | [Table interaction](demo#table-interaction) | - -## rowItem parameter - -| Parameter | Type | Default value | Description | -| :---------------: | :-----------------: | :----- | :-------------------------------------------------------------------------------------------------------: | -| $editDeniedConfig | `array` | -- | Optional. This parameter is used with column to configure the edit permission on some cells in the row. For example, if this parameter is set to ['age'], the cell whose field is age cannot be edited. | -| $expandConfig | [`TableExpandConfig`](#tableexpandconfig) | -- | Optional. Configure additional content in this line. | -| $rowClass | `string` | -- | Optional. Configure the user-defined class of the line. | -| $hovered | `boolean` | false | The value is true when the cursor moves over the element in the row, and false when
leaves the row. | - -#### Custom Cells - -When the cell data (cellItem, which is obtained by rowItem[column.field]) is of the string type, the widget can be directly displayed. When the cell data is of the object type or the special behavior of the cell needs to be defined, the cell needs to be customized for display. -For example, we want to capitalize the data in the `Gender' column and display a prompt when you move the mouse. The relevant code is as follows: -``` - - - - -{{cellItem.toUpperCase()}} - - - - -``` - -#### Customizing a Cell Editing Template - -The Datatable allows users to customize cell editing using a template. -``` - - - - - - - -``` -The complete template for editing customized cells and configuration cells is as follows: -``` xml - - - -// rowIndex: row number. -// colIndex: column sequence number -// rowItem: data in the current row, corresponding to the key-value pair of filed and cellItem. -// column: metadata of the current column, corresponding to the DataTableColumnTmplComponent class -// cellItem: value of the current cell. The value is obtained from rowItem[column.field]. -// tableLevel: indicates the level of the table in the tree table. The outermost value is 0. The value increases automatically. -``` -#### Customizing a Table Header Cell -If a table header cell is required, the system displays the message "Gender is a head cell template" when you move the mouse over the table. -``` xml - - - - -{{column.header}} - - - - -// column: Enter a column value, corresponding to the `DataTableColumnTmplComponent` class. -``` -#### Multi-row Header and Table Header Combine Cells -* Add this parameter when the d-column is used. -``` javascript -advancedHeader: Array < { -header: string; -rowspan: number; -colspan: number; -} -``` -Note: Empty cells also need to be indicated. Set rowspan/colspan to 0 based on the content. If column width dragging and multi-row headers are used at the same time, attach the width to the column content. If the column width of the first row is incorrect, manually add the $width attribute for advancedHeader[rowNumber]. diff --git a/devui/datepicker/datepicker.tsx b/devui/datepicker/datepicker.tsx deleted file mode 100644 index 1b01bbc08caf0c3220a958347bb9b49c924010e6..0000000000000000000000000000000000000000 --- a/devui/datepicker/datepicker.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-datepicker', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-datepicker
- } - } -}) \ No newline at end of file diff --git a/devui/datepicker/demo/datepicker-demo.tsx b/devui/datepicker/demo/datepicker-demo.tsx deleted file mode 100644 index 995d9cdaafb96b1162276f7bad158fe70ead3d15..0000000000000000000000000000000000000000 --- a/devui/datepicker/demo/datepicker-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-datepicker-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-datepicker-demo
- } - } -}) \ No newline at end of file diff --git a/devui/datepicker/demo/datepicker.route.ts b/devui/datepicker/demo/datepicker.route.ts deleted file mode 100644 index d8cb903977efdd2b2714144a9c7ac02a3e391e2f..0000000000000000000000000000000000000000 --- a/devui/datepicker/demo/datepicker.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import DatepickerDemoComponent from './datepicker-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: DatepickerDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/datepicker/doc/api-cn.md b/devui/datepicker/doc/api-cn.md deleted file mode 100644 index a3d06c7d94b324c9c07d88c5408a73e93d0ccb8b..0000000000000000000000000000000000000000 --- a/devui/datepicker/doc/api-cn.md +++ /dev/null @@ -1,217 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { DatepickerModule } from 'ng-devui/datepicker'; -``` - -在页面中使用: - -``` - -``` - -# dDatepicker - -## dDatepicker 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-------------------------------------------------------------------------------: | :-----------------------------: | :-----------------------------------------------------: | ------------------------------------------------ | -| cssClass | `string` | -- | 可选,自定义 class | [基本用法](demo#datepicker-default) | -| mode | `'year' \| 'month' \| 'date'` | 'date' | 可选,类型,根据 `dateFormat`参数设置不同的格式化 | [设置日期选择器的类型](demo#datepicker-set-mode) | -| locale(国际化后暂无作用) | `string` | 'zh-cn' | 可选,时区 | -| showTime | `boolean` | false | 可选,是否显示时分秒 | [格式化](demo#datepicker-format) | -| disabled | `boolean` | false | 可选,禁用选择 | [基本用法](demo#datepicker-default) | -| direction | `'up' \| 'down'` | 'down' | 可选,日期弹出方向 | [格式化](demo#datepicker-format) | -| dateConverter | `function` | DefaultDateConverter | 可选,日期格式化、解析函数 | -| dateConfig | `DateConfig` | 见下方介绍 | 可选,配置参数 | [基本用法](demo#datepicker-default) | -| dateFormat | [ng 自定义日期格式](https://angular.cn/api/common/DatePipe#custom-format-options) | 'y/MM/dd' \| 'y/MM/dd HH:mm' | 可选,传入格式化,根据是否 showTime 区别不同默认值 | [格式化](demo#datepicker-format) | -| minDate | `Date` | new Date('01/01/1900 00:00:00') | 可选,限制最小可选日期 | [限制最大最小日期](demo#datepicker-min-max) | -| maxDate | `Date` | new Date('11/31/2099 23:59:59') | 可选,限制最大可选日期 | [限制最大最小日期](demo#datepicker-min-max) | -| autoOpen | `boolean` | false | 可选,初始化是否直接展开 | [限制最大最小日期](demo#datepicker-min-max) | -| customViewTemplate | `template` | -- | 可选,自定义快捷设置日期或自定义操作区内容,用法见 demo | [自定义操作区](demo#custom-view-template) | - -## dDatepicker 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----------------: | :--------------------: | :------------------------------------------: | ----------------------------------- | -| selectedDateChange | `EventEmitter` | 可选,子项切换的时候会发出新激活的子项的数据 | [基本用法](demo#datepicker-default) | - -## appendToBody(dDatepicker 附加指令组件) - -搭配 dDatepicker 使用该指令后,会被附加到 body,可以防止 datepicker 在滚动条内被遮挡。 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------------: | :-------------------------------------------------: | :----------------------------------------------: | :------------------------------: | ------------------------------------------------ | -| appendToBodyDirections | `Array` | `['rightDown', 'leftDown', 'rightUp', 'leftUp']` | 方向数组优先采用数组里靠前的位置 | [附着在 body 上](demo#datepicker-append-to-body) | - -注意: 使用 appendToBody 后需要在有滚动条的地方使用`cdkScrollable` - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import { ScrollDispatchModule } from '@angular/cdk/scrolling'; - -@NgModule({ - imports: [ - // ... - ScrollDispatchModule, - // ... - ] -}) -``` - -```html -
- -
-``` - -## ConnectedPosition 类型定义 - -引用自`@angular/cdk/overlay` - -```TypeScript -export interface ConnectedPosition { - originX: 'start' | 'center' | 'end'; - originY: 'top' | 'center' | 'bottom'; - - overlayX: 'start' | 'center' | 'end'; - overlayY: 'top' | 'center' | 'bottom'; - - weight?: number; - offsetX?: number; - offsetY?: number; - panelClass?: string | string[]; -} -``` - -## AppendToBodyDirection 类型定义 - -```typescript -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -简化的几个基础的方向为名字 - -| 简化名 | 意义 | -| :--------: | :-------------------------------------------------------------------------: | -| rightDown | 相对于对齐对象显示在`右下`方向, 即左对齐,显示在下方(注意右下是左对齐的) | -| rightUp | 相对于对齐对象显示在`右上`方向, 即左对齐,显示在上方 | -| leftUp | 相对于对齐对象显示在`左上`方向, 即右对齐,显示在上方 | -| leftDown | 相对于对齐对象显示在`左下`方向, 即右对齐,显示在下方 | -| centerDown | 相对于对齐对象显示在`居中下`方向, 即居中对齐,显示在下方 | -| centerUp | 相对于对齐对象显示在`居中上`方向, 即居中对齐,显示在上方 | - -简化了 6 个方向的命名,其余方向可以通过 angular/cdk/overlay 的 ConnectedPosition 进行使用。 - -appendToBodyDirections 默认的显示顺序为 ['rightDown', 'leftDown', 'rightUp', 'leftUp'], -会尝试第一个位置,第一个位置放不下会尝试第二个位置,依此类推。 - -## DateConfig - -``` -interface DateConfig{ - timePicker: boolean, // 默认false - dateConverter: any, - min: number, // 默认1900 - max: number, // 默认 2099 - format: { - date: string, // 默认 'y/MM/dd' - time: string // 默认 'y/MM/dd HH:mm' - } -} -``` - -# dDateRangePicker - -## dDateRangePicker 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-------------------------------------------------------------------------------: | :-------------------------------: | :------------------------------------------------------ | ----------------------------------------------------------------- | -| cssClass | `string` | -- | 可选,自定义 class | [范围日期选择器 集成模式](demo#datepicker-range-basic) | -| locale(国际化后暂无作用) | `string` | 'zh-cn' | 可选,时区 | -| showTime | `boolean` | false | 可选,是否显示时分秒 | [日期范围选择器 选择时间](demo#datepicker-range-time) | -| disabled | `boolean` | false | 可选,禁用选择 | [禁止输入态](demo#datepicker-range-disabled) | -| dateConverter | `function` | DefaultDateConverter | 可选,日期格式化、解析函数 | -| dateConfig | `DateConfig` | 见下方介绍 | 可选,配置参数 | [日期范围选择器 格式化](demo#datepicker-range-format) | -| dateFormat | [ng 自定义日期格式](https://angular.cn/api/common/DatePipe#custom-format-options) | `'y/MM/dd' \| 'y/MM/dd HH:mm'` | 可选,传入格式化 | [日期范围选择器 格式化](demo#datepicker-range-format) | -| minDate | `Date` | `new Date('01/01/1900 00:00:00')` | 可选,限制最小可选日期 | [日期范围选择器 可选范围](demo#datepicker-range-restricted-range) | -| maxDate | `Date` | `new Date('11/31/2099 23:59:59')` | 可选,限制最大可选日期 | [日期范围选择器 可选范围](demo#datepicker-range-restricted-range) | -| splitter | `string` | `' - '` | 可选,两日期间的分隔符 | [日期范围选择器 格式化](demo#datepicker-range-format) | -| selectedRange | `[Date, Date]` | `[null, null]` | 可选,时选择的日期 | [范围日期选择器 集成模式](demo#datepicker-range-basic) | -| customViewTemplate | `template` | -- | 可选,自定义快捷设置日期或自定义操作区内容,用法见 demo | [自定义操作区](demo#datepicker-clear-button) | -| hideOnRangeSelected | `boolean` | false | 可选,是否在选择完日期后隐藏面板 | [范围日期选择器 集成模式](demo#datepicker-range-basic) | - -## dDateRangePicker 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :-----------------: | :--------------------: | :--------------- | --------- | -| selectedRangeChange | `EventEmitter` | 日期发生变化回调 | - -## 使用 reason 限制插件 emit 的 reason 导出 - -datepicker 通过 - -```TypeScript -import { SelectDateChangeReason } from 'ng-devui/zh-cn/datepicker'; -``` - -dateRangePicker 通过 - -```TypeScript -import { SelectDateRangeChangeReason } from 'ng-devui/zh-cn/datepicker'; -``` - -来引入 reason 限制插件,如何使用可以自由发挥,清除按钮 demo 就提供了一种方式 - -如下所示,reason 是枚举类型,所以需要根据`selectedDateChange`(dateRangePicker 为`selectedRangeChange`)返回的`reason`字段的数字进行判断,reason 当前可选值: - -```TypeScript -enum SelectDateChangeReason { - date, // 返回值为`reason:0`,代表选择日期时触发的reason - time, // 返回值为`reason:1`,代表showTime时修改时间触发的reason - button, // 返回值为`reason:2`,代表自带的按钮(例如清除和确定)触发时的reason - format, // 返回值为`reason:3`,代表改变格式化时触发的reason - custom // 返回值为`reason:4`,代表用户传入的变更触发的reason -} -``` - -SelectDateRangeChangeReason 与上述用法相同 - -# dTwoDatePicker - -## dTwoDatePicker 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-------------------------------------------------------------------------------: | :-------------------------------: | :------------------------------- | -------------------------------------------------- | -| cssClass | `string` | -- | 可选,自定义 class | [双日期选择器](demo#two-date-picker-basic) | -| locale(国际化后暂无作用) | `string` | 'zh-cn' | 可选,时区 | -| disabled | `boolean` | false | 可选,禁用选择 | [双日期选择器](demo#two-date-picker-basic) | -| dateConverter | `function` | DefaultDateConverter | 可选,日期格式化、解析函数 | -| dateConfig | `DateConfig` | 见下方介绍 | 可选,配置参数 | [双日期选择器 格式化](demo#two-date-picker-format) | -| dateFormat | [ng 自定义日期格式](https://angular.cn/api/common/DatePipe#custom-format-options) | `'y/MM/dd' \| 'y/MM/dd HH:mm'` | 可选,传入格式化 | [双日期选择器 格式化](demo#two-date-picker-format) | -| minDate | `Date` | `new Date('01/01/1900 00:00:00')` | 可选,限制最小可选日期 | [双日期选择器 格式化](demo#two-date-picker-format) | -| maxDate | `Date` | `new Date('11/31/2099 23:59:59')` | 可选,限制最大可选日期 | [双日期选择器 格式化](demo#two-date-picker-format) | -| hideOnRangeSelected | `boolean` | true | 可选,是否在选择完日期后隐藏面板 | [双日期选择器](demo#two-date-picker-basic) | - -## dTwoDatePicker 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :-----------------: | :--------------------: | :--------------- | ------------------------------------------ | -| selectedRangeChange | `EventEmitter` | 日期发生变化回调 | [双日期选择器](demo#two-date-picker-basic) | - -## dTwoDatePickerStart 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :---------: | :--------------------: | :--------------- | ------------------------------------------ | -| selectStart | `EventEmitter` | 日期发生变化回调 | [双日期选择器](demo#two-date-picker-basic) | - -## dTwoDatePickerEnd 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :-------: | :--------------------: | :--------------- | ------------------------------------------ | -| selectEnd | `EventEmitter` | 日期发生变化回调 | [双日期选择器](demo#two-date-picker-basic) | diff --git a/devui/datepicker/doc/api-en.md b/devui/datepicker/doc/api-en.md deleted file mode 100644 index 1aa3b2d7a1eef32ee0b451b28d41b7d878c5a9ab..0000000000000000000000000000000000000000 --- a/devui/datepicker/doc/api-en.md +++ /dev/null @@ -1,217 +0,0 @@ -# How to use - -Import into module: - -```ts -import { DatepickerModule } from 'ng-devui/datepicker'; -``` - -In the page: - -``` - -``` - -# dDatepicker - -## dDatepicker parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :-----------------------------: | :-----------------------------------------------------------------------------------------------------: | ------------------------------------------------------ | -| cssClass | `string` | -- | Optional, user-defined class | [Basic usage](demo#datepicker-default) | -| mode | `'year' \| 'month' \| 'date'` | 'date' | Optional, Mode, Formatting based on the value of the `dateFormat` parameter | [Set Mode](demo#datepicker-set-mode) | -| locale (This parameter is invalid after internationalization.) | `string` | 'zh-cn' | Optional, Time zone | -| showTime | `boolean` | false | Optional, indicating whether to display hour, minute, and second. | [Format](demo#datepicker-format) | -| disabled | `boolean` | false | Optional, Disable selection. | [Basic usage](demo#datepicker-default) | -| direction | `'up '\|'down'` | 'down' | Optional, date pop-up direction | [formatting](demo#datepicker-format) | -| dateConverter | `function` | DefaultDateConverter | Optional, formatting and parsing functions. | -| dateConfig | `DateConfig` | See the following description. | Optional, It is a configuration parameter. | [Basic usage](demo#datepicker-default) | -| dateFormat | [ng cunstom date format](https://angular.cn/api/common/DatePipe#custom-format-options) | 'y/MM/dd'\| 'y/MM/dd HH:mm' | Optional, Formatting is supported. The default value varies depending on whether showTime is specified. | [Format](demo#datepicker-format) | -| minDate | `Date` | new Date('01/01/1900 00:00:00') | Optional, The minimum date can be selected. | [Maximum and minimum dates](demo#datepicker-min-max) | -| maxDate | `Date` | new Date('11/31/2099 23:59:59') | Optional, The maximum number of available dates is limited. | [Maximum and minimum dates](demo#datepicker-min-max) | -| autoOpen | `boolean` | false | Optional, indicating whether to expand during initialization. | [Maximum and minimum dates](demo#datepicker-min-max) | -| customViewTemplate | `template` | -- | Optional, Customize the date or content in the operation area. For details, see demo | [Customized operation area](demo#custom-view-template) | - -## dDatepicker Event - -| Event | Type | Description | Jump to Demo | -| :----------------: | :--------------------: | :--------------------------------------------------------------------------------------: | -------------------------------------- | -| selectedDateChange | `EventEmitter` | Optional, When a sub-item is switched, the data of the newly activated sub-item is sent. | [Basic usage](demo#datepicker-default) | - -## appendToBody (dDatepicker additional instruction component) - -When this command is used together with dDatepicker, it is attached to the body to prevent datepicker from being blocked in the scroll bar. - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------: | :-------------------------------------------------: | :--------------------------------------------: | :-------------------------------------------------------------------: | ----------------------------------------------------------------------------------- | -| appendToBodyDirections | `Array` | ` ['rightDown','leftDown','rightUp','leftUp']` | The first position in the array is preferred for the direction array. | [Attached to the body](/componentsen-us//datepicker/demo#datepicker-append-to-body) | - -Note: After appendToBody is used, use `cdkScrollable` where the scroll bar exists. - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import {ScrollDispatchModule} from '@angular/cdk/scrolling'; - -@NgModule({ -imports: [ -//... -ScrollDispatchModule, -//... -] -}) -``` - -```html -
- -
-``` - -## ConnectedPosition Type Definition - -Quoted from `@angular/cdk/overlay` - -```TypeScript -export interface ConnectedPosition { -originX: 'start' | 'center' | 'end'; -originY: 'top' | 'center' | 'bottom'; - -overlayX: 'start' | 'center' | 'end'; -overlayY: 'top' | 'center' | 'bottom'; - -weight? : number; -offsetX? : number; -offsetY? : number; -panelClass? : string | string[]; -} -``` - -## AppendToBodyDirection Type Definition - -```typescript -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -Simplify several basic directions for the name. - -| Simplified name | Meaning | -| :-------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------: | -| rightDown | Display in the lower right direction relative to the aligned object, that is, the object is left aligned. (Note that the lower right is left aligned.) | -| rightUp | Display in the upper right direction relative to the aligned object. That is, the object is left aligned and displayed at the top. | -| leftUp | Display in the `up-left' direction relative to the aligned object, that is, right-aligned and displayed above. | -| leftDown | Display in the lower-left direction relative to the aligned object, that is, right-aligned and displayed below. | -| centerDown | Display in the `center-bottom' direction relative to the aligned object. That is, the object is center-aligned and displayed below. | -| centerUp | Display in the "center-up" direction relative to the aligned object, that is, display in the center-aligned direction. | - -The naming of six directions is simplified. Other directions can be used by using the ConnectedPosition of angular/cdk/overlay. - -appendToBodyDirections: The default display sequence is ['rightDown','leftDown','rightUp','leftUp']. -Try the first position, try the second position, and so on. - -## DateConfig - -``` -interface DateConfig{ - timePicker: boolean, // default false - dateConverter: any, - min: number, // default 1900 - max: number, // default 2099 - format: { - date: string, // default 'y/MM/dd' - time: string // default 'y/MM/dd HH:mm' - } -} -``` - -# dDateRangePicker - -## dDateRangePicker Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :-------------------------------: | :----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| cssClass | `string` | -- | Optional, customized class | [Integration mode of the range date selector](demo#datepicker-range-basic) | -| locale (This parameter is invalid after internationalization.) | `string` | 'zh-cn' | Optional, Time zone | -| showTime | `boolean` | false | Optional, indicating whether to display the hour, minute, and second. | [Time selected by the date range selector](demo#datepicker-range-time) | -| disabled | `boolean` | false | Optional, Disable selection. | [Forbidden input](demo#datepicker-range-disabled) | -| dateConverter | `function` | DefaultDateConverter | Optional, date formatting and parsing functions. | -| dateConfig | `DateConfig` | See the following description. | Optional, It is a configuration parameter. | [Date range selector formatting](demo#datepicker-range-format) | -| dateFormat | [ng cunstom date format](https://angular.cn/api/common/DatePipe#custom-format-options) | `'y/MM/dd'\|'y/MM/dd HH:mm'` | Optional, Formatting the input data | [Date range selector formatting](demo#datepicker-range-format) | -| minDate | `Date` | `new Date('01/01/1900 00:00:00')` | Optional, The minimum available date is restricted. | [The date range selector can be selected](demo#datepicker-range-restricted-range) | -| maxDate | `Date` | `new Date('11/31/2099 23:59:59')` | Optional, The maximum date can be selected is restricted. | [The date range selector can be selected](demo#datepicker-range-restricted-range) | -| splitter | `string` | `' - '` | Optional, separator of two days | [Date range selector formatting](demo#datepicker-range-format) | -| selectedRange | `[Date, Date]` | `[null, null]` | Optional, Date selected when | [Integration mode of the range date selector](demo#datepicker-range-basic) | -| customViewTemplate | `template` | -- | Optional, Customize the date or content in the operation area. For details, see demo | [Customized operation area](demo#datepicker-clear-button) | -| hideOnRangeSelected | `boolean` | false | Optional, Whether to hide the panel after selecting a date | [Integration mode of the range date selector](demo#datepicker-range-basic) | - -## dDateRangePicker Event - -| Event | Type | Description | Jump to Demo | -| :-----------------: | :--------------------: | :------------------- | ------------ | -| selectedRangeChange | `EventEmitter` | Date Change Callback | - -## Use reason to restrict the reason export of the plug-in emit. - -The datepicker passes the test. - -```TypeScript -import {SelectDateChangeReason} from' ng-devui/datepicker'; -``` - -dateRangePicker Pass - -```TypeScript -import {SelectDateRangeChangeReason} from' ng-devui/datepicker'; -``` - -To introduce the reason limit plug-in, how can be used freely, the clear button demo provides a way. - -As shown in the following figure, reason is of the enumerated type. Therefore, the value of reason must be determined based on the value of reason returned by `selectedDateChange` (dateRangePicker is `selectedRangeChange`). The value of reason is available. - -```TypeScript -enum SelectDateChangeReason { -date, // The return value is `reason:0`, which indicates the reason triggered when a date is selected. -time, // The return value is `reason:1`, which indicates the reason triggered by time modification during showTime. -button, // The return value is `reason:2`, indicating the reason when the built-in button (such as clear and OK) is triggered. -format, // The return value is `reason:3`, indicating that the reason triggered during formatting is changed. -custom // The return value is `reason:4`, which indicates the change-triggered reason transferred by the user. -} -``` - -SelectDateRangeChangeReason is used in the same way as above - -# dTwoDatePicker - -## dTwoDatePicker Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :-------------------------------: | :------------------------------------------------------------- | ------------------------------------------------------------ | -| cssClass | `string` | -- | Optional, custom class | [Dual date selector](demo#two-date-picker-basic) | -| locale (This parameter is invalid after internationalization.) | `string` | 'zh-cn' | Optional, Time zone | -| disabled | `boolean` | false | Optional, The selection is disabled. | [Dual date selector](demo#two-date-picker-basic) | -| dateConverter | `function` | DefaultDateConverter | Optional, formatting and parsing functions. | -| dateConfig | `DateConfig` | See the following description. | Optional, It is a configuration parameter. | [Dual date selector formatting](demo#two-date-picker-format) | -| dateFormat | [ng cunstom date format](https://angular.cn/api/common/DatePipe#custom-format-options) | `'y/MM/dd'\|'y/MM/dd HH:mm'` | Optional, Formatting the input data | [Dual-date selector formatting](demo#two-date-picker-format) | -| minDate | `Date` | `new Date('01/01/1900 00:00:00')` | Optional, The minimum date can be selected. | [Dual-date selector formatting](demo#two-date-picker-format) | -| maxDate | `Date` | `new Date('11/31/2099 23:59:59')` | Optional, The maximum date that can be selected is restricted. | [Dual-date selector formatting](demo#two-date-picker-format) | -| hideOnRangeSelected | `boolean` | true | Optional, Whether to hide the panel after a date is selected. | [Dual-date selector](demo#two-date-picker-basic) | - -## dTwoDatePicker Event - -| Event | Type | Description | Jump to Demo | -| :-----------------: | :--------------------: | :------------------- | ------------------------------------------------ | -| selectedRangeChange | `EventEmitter` | Date Change Callback | [Dual Date Selector](demo#two-date-picker-basic) | - -## dTwoDatePickerStart Event - -| Event | Type | Description | Jump to Demo | -| :---------: | :--------------------: | :------------------- | ------------------------------------------------ | -| selectStart | `EventEmitter` | Date Change Callback | [Dual Date Selector](demo#two-date-picker-basic) | - -## dTwoDatePickerEnd Event - -| Event | Type | Description | Jump to Demo | -| :-------: | :--------------------: | :------------------- | ------------------------------------------------ | -| selectEnd | `EventEmitter` | Date Change Callback | [Dual Date Selector](demo#two-date-picker-basic) | diff --git a/devui/dragdrop/demo/dragdrop-demo.tsx b/devui/dragdrop/demo/dragdrop-demo.tsx deleted file mode 100644 index 76a4853d5d465334888f68655eb3a1254b15c1c3..0000000000000000000000000000000000000000 --- a/devui/dragdrop/demo/dragdrop-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-dragdrop-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
devui-dragdrop-demo
- } - } -}) \ No newline at end of file diff --git a/devui/dragdrop/demo/dragdrop.route.ts b/devui/dragdrop/demo/dragdrop.route.ts deleted file mode 100644 index 2edce0c7575ef73ae9a61b6677c7d2955a279224..0000000000000000000000000000000000000000 --- a/devui/dragdrop/demo/dragdrop.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import DragDropDemoComponent from './dragdrop-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: DragDropDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': '', - 'en-us': '' - }} -] - -export default routes diff --git a/devui/dragdrop/doc/api-cn.md b/devui/dragdrop/doc/api-cn.md deleted file mode 100644 index 2121f5e1847dd0cf461f3a1a6f73fe3084dae772..0000000000000000000000000000000000000000 --- a/devui/dragdrop/doc/api-cn.md +++ /dev/null @@ -1,383 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```typescript -import { DragDropModule } from' ng-devui/dragdrop'; -``` - -## Dragdrop - -提供 dDraggable 和 dDroppable(dSortable)指令 - -## dDraggable 指令 - -### dDraggable 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------------------- | :--------------------------------------------------------------------------------------------------------------- | :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------ | -| dragData | `any` | -- | 可选,转递给 `DropEvent`事件的数据. | [基本用法](demo#basic-usage) | -| dragScope | `string \| Array` | 'default' | 可选,限制 drop 的位置,必须匹配对应的 `dropScope` | [基本用法](demo#basic-usage) | -| dragOverClass | `string` | -- | 可选,拖动时被拖动元素的 css | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| dragHandleClass | `string` | -- | 可选,拖动句柄,css 选择器,只有被选中的元素才能响应拖动事件 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,控制当前元素是否可拖动 false 为可以,true 为不可以 | [基本用法](demo#basic-usage) | -| enableDragFollow | `boolean` | false | 可选,是否启用实体元素跟随(可以添加更多特效,如阴影等) | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| dragFollowOption | `{appendToBody?: boolean}` | -- | 可选,用于控制实体拖拽的一些配置 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| dragFollowOption.appendToBody | `boolean` | false | 可选,用于控制实体拖拽的克隆元素插入的位置。默认 false 会插入到源元素父元素所有子的最后,设置为 true 会附着到。见说明 1 | [拖拽实体元素跟随](demo#drag-entity-elements-to-follow) | -| originPlaceholder | `{show?: boolean; tag?: string; style?: {cssProperties: string]: string}; text?: string; removeDelay?: number;}` | -- | 可选,设置源占位符号,用于被拖拽元素原始位置占位 | [源占位符](demo#source-placeholder) | -| originPlaceholder.show | `boolean` | true | 可选,是否显示,默认 originPlaceholder 有 Input 则显示,特殊情况可以关闭 | -| originPlaceholder.tag | `string` | 'div' | 可选,使用 tag 名,默认 originPlaceholder 使用'div',特殊情况可以置换 | -| originPlaceholder.style | `Object` | -- | 可选,传 style 对象,key 为样式属性,value 为样式值 | [源占位符](demo#source-placeholder) | -| originPlaceholder.text | `string` | -- | 可选,placeholder 内的文字 | [源占位符](demo#source-placeholder) | -| originPlaceholder.removeDelay | `number` | -- | 可选,用于希望源占位符在拖拽之后的延时里再删除,方便做动画,单位为 ms 毫秒 | [源占位符](demo#source-placeholder) | -| dragIdentity | `any` | -- | 可选,用于虚拟滚动的恢复,虚拟滚动过程中会删除元素(溢出画面)然后又重新生成来恢复元素(回到画面),需要唯一识别值来恢复原始事件拖拽事件监听和源占位符等 | -| dragItemParentName | `string` | -- | 可选,选择器名,和 dragItemChildrenName 搭配用于拖拽截断看不见的列表内元素以提高性能, 从 dragItemParentName 匹配的选择器里边查询匹配 dragItemChildrenName 的元素,通常是列表里查找条目,把超出可视范围的条目克隆的时候剔除 | 暂无 | -| dragItemChildrenName | `string` | -- | 可选,选择器名,和 dragItemParentName 搭配用于拖拽截断看不见的列表内元素以提高性能,功能见 dragItemParentName 的描述 | 暂无 | - -说明 1:dragFollowOptions 的 appendToBody 的使用场景:当拖拽离开后源位置的父对象会被销毁的话,需要把克隆体附着到 body 上防止被销毁。默认会通过复制样式保证克隆到 body 的实体的样式是正确的,但部分深度依赖 DOM 节点位置的样式和属性可能会失败,需要手动调整部分样式。 - -### dDraggable 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :------------- | :------------------------ | :------------------------ | :--------------------------- | -| dragStartEvent | `EventEmitter` | 开始拖动的 DragStart 事件 | [基本用法](demo#basic-usage) | -| dragEndEvent | `EventEmitter` | 拖动结束的 DragEnd 事件 | [基本用法](demo#basic-usage) | -| dropEndEvent | `EventEmitter` | 放置结束的 Drop 事件 | [基本用法](demo#basic-usage) | - -Drag DOM Events 详情: [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent) - -### batchDrag 附加指令 - -使用方法 dDraggable batchDrag - -#### dDraggable batchDrag 属性 - -| 名字 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------------------------- | :------------------------ | :----------------- | :--------------------------------------------------------------------------------------------- | :----------------------------------- | -| batchDragGroup | `string` | 'default' | 可选,批量拖拽分组组名,不同组名 | -| batchDragActive | `boolean` | false | 可选,是否把元素加入到批量拖拽组. 见说明 1。 | [批量拖拽](demo#batch-drag-and-drop) | -| batchDragLastOneAutoActiveEventKeys | `Array` | ['ctrlKey'] | 可选,通过过拖拽可以激活批量选中的拖拽事件判断。见说明 2。 | -| batchDragStyle | `Array` | ['badge', 'stack'] | 可选,批量拖拽的效果,badge 代表右上角有统计数字,stack 代表有堆叠效果,数组里有该字符串则有效 | [批量拖拽](demo#batch-drag-and-drop) | - -说明 1: `batchDragActive`为`true`的时候会把元素加入组里,加入顺序为变为 true 的顺序,先加入的在数组前面。第一个元素会确认批量的组名,如果后加入的组名和先加入的组名不一致,则后者无法加入。 -说明 2: `batchDragLastOneAutoActiveEventKeys`的默认值为['ctrlKey'], 即可以通过按住 ctrl 键拖动最后一个元素, 该元素自动加入批量拖拽的组,判断条件是 dragStart 事件里的 ctrlKey 事件为 true。目前仅支持判断 true/false。该参数为数组,可以判断任意一个属性值为 true 则生效,可用于不同操作系统的按键申明。 - -#### dDraggable batchDrag 事件 - -| 名字 | 类型 | 描述 | 跳转 Demo | -| :------------------- | :--------------------------------------- | :------------------------------------------------- | :----------------------------------- | -| batchDragActiveEvent | `EventEmitter<{el: Element, data: any}>` | 通过拖拽把元素加入了批量拖拽组,通知外部选中该元素 | [批量拖拽](demo#batch-drag-and-drop) | - -## dDroppable 指令 - -### dDroppable 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------------------- | :--------------------------------------------- | :------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | -| dropScope | `string \| Array` | 'default' | 可选,限制 drop 的区域,对应 dragScope | [基本用法](demo#basic-usage) | -| dragOverClass | `string` | -- | 可选,dragover 时 drop 元素上应用的 css | -| placeholderStyle | `Object` | {backgroundColor: '#6A98E3', opacity: '.4'} | 可选,允许 sort 时,用于占位显示 | [源占位符](demo#source-placeholder) | -| placeholderText | `string` | '' | 可选,允许 sort 时,用于占位显示内部的文字 | -| allowDropOnItem | `boolean` | false | 可选,允许 sort 时,用于允许拖动到元素上,方便树形结构的拖动可以成为元素的子节点 | [多层树状拖拽](demo#multi-level-tree-drag) | -| dragOverItemClass | `string` | -- | 可选,`allowDropOnItem`为`true`时,才有效,用于允许拖动到元素上后,被命中的元素增加样式 | [多层树状拖拽](demo#multi-level-tree-drag) | -| nestingTargetRect | `{height?: number, width?: number}` | -- | 可选,用于修正有内嵌列表后,父项高度被撑大,此处 height,width 为父项自己的高度(用于纵向拖动),宽度(用于横向拖动) | [多层树状拖拽](demo#multi-level-tree-drag) | -| defaultDropPosition | `'closest' \| 'before' \| 'after'` | 'closest' | 可选,设置拖拽到可放置区域但不在列表区域的放置位置,`'closest'` 为就近放下, `'before'`为加到列表头部, `'after'`为加到列表尾部 | [外部放置位置](demo#external-location) | -| dropSortCountSelector | `string` | -- | 可选,带有 sortable 的容器的情况下排序,计数的内容的选择器名称,可以用于过滤掉不应该被计数的元素 | -| dropSortVirtualScrollOption | `{totalLength?: number; startIndex?: number;}` | -- | 可选,用于虚拟滚动列表中返回正确的 dropIndex 需要接收 totalLength 为列表的真实总长度, startIndex 为当前排序区域显示的第一个 dom 的在列表内的 index 值 | - -### dDroppable 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :------------- | :------------------------------------------ | :------------------------------------------------------------------------------ | :--------------------------- | -| dragEnterEvent | `EventEmitter` | drag 元素进入的 dragenter 事件 | [基本用法](demo#basic-usage) | -| dragOverEvent | `EventEmitter` | drag 元素在 drop 区域上的 dragover 事件 | [基本用法](demo#basic-usage) | -| dragLeaveEvent | `EventEmitter` | drag 元素离开的 dragleave 事件 | [基本用法](demo#basic-usage) | -| dropEvent | `EventEmitter<`[`DropEvent`](#dropevent)`>` | 放置一个元素, 接收的事件,其中 nativeEvent 表示原生的 drop 事件,其他见定义注释 | [基本用法](demo#basic-usage) | - -### DropEvent - -```typescript -type DropEvent = { - nativeEvent: any; // 原生的drop事件 - dragData: any; // drag元素的dragData数据 - dropSubject: Subject; //drop事件的Subject - dropIndex?: number; // drop的位置在列表的index - dragFromIndex?: number; // drag元素在原来的列表的index,注意使用虚拟滚动数据无效 - dropOnItem?: boolean; // 是否drop到了元素的上面,搭配allowDropOnItem使用 -``` - -## dSortable 指令 - -指定需要参与排序的 Dom 父容器(因为 drop 只是限定可拖拽区域,具体渲染由使用者控制) - -### dSortable 参数 - -| 名字 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------- | :----------- | :----- | :------------------------------ | :-------- | -| dSortDirection | `'v' \| 'h'` | 'v' | 'v'垂直排序,'h'水平排序 | -| dSortableZMode | `boolean` | false | 是否是 z 模式折回排序,见说明 1 | - -说明 1: z 自行排序最后是以大方向为准的,如果从左到右排遇到行末换行,需要使用的垂直排序+z 模式,因为最后数据是从上到下的只是局部的数据是从左到右。 - -### dDropScrollEnhanced 参数 - -| 名字 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----------------- | :---------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | -| direction | [`DropScrollDirection`](#dropscrolldirection)即`'v'\|'h'` | 'v' | 滚动方向,垂直滚动`'v'`, 水平滚动 `'h'` | [拖拽滚动容器增强](demo#drag-and-roll-container-enhancement) | -| responseEdgeWidth | `string \| ((total: number) => string)` | '100px' | 响应自动滚动边缘宽度, 函数的情况传入的为列表容器同个方向相对宽度 | [拖拽滚动容器增强](demo#drag-and-roll-container-enhancement) | -| speedFn | [`DropScrollSpeedFunction`](#dropscrolldirection) | 内置函数 | 速率函数,见备注 | -| minSpeed | `DropScrollSpeed`即`number` | 50 | 响应最小速度 ,函数计算小于这个速度的时候,以最小速度为准 | -| maxSpeed | `DropScrollSpeed`即`number` | 1000 | 响应最大速度 ,函数计算大于这个速度的时候,以最大速度为准 | -| viewOffset | {forward?: [`DropScrollAreaOffset`](#dropScrollAreaOffset); backward?: `DropScrollAreaOffset`;} | -- | 设置拖拽区域的偏移,用于某些位置修正 | -| dropScrollScope | `string\| Array` | -- | 允许触发滚动 scope,不配置为默认接收所有 scope,配置情况下,draggable 的`dragScope`和`dropScrollScope`匹配得上才能触发滚动 | [拖拽滚动容器增强](demo#drag-and-roll-container-enhancement) | -| backSpaceDroppable | `boolean` | true | 是否允许在滚动面板上同时触发放置到滚动面板的下边的具体可以放置元素,默认为 true,设置为 false 则不能边滚动边放置 | - -备注: speedFn 默认函数为`(x: number) => Math.ceil((1 - x) * 18) * 100`,传入数字`x`是 鼠标位置距离边缘的距离占全响应宽度的百分比, -最终速度将会是 speedFn(x),但不会小于最小速度`minSpeed`或者大于最大速度`maxSpeed`。 - -相关类型定义: - -#### DropScrollDirection - -```typescript -export type DropScrollDirection = 'h' | 'v'; -``` - -#### DropScrollSpeed - -```typescript -export type DropScrollEdgeDistancePercent = number; // unit: 1 -export type DropScrollSpeed = number; // Unit: px/s -export type DropScrollSpeedFunction = (x: DropScrollEdgeDistancePercent) => DropScrollSpeed; -``` - -#### DropScrollAreaOffset - -```typescript -export type DropScrollAreaOffset = { - left?: number; - right?: number; - top?: number; - bottom?: number; - widthOffset?: number; - heightOffset?: number; -}; - -export enum DropScrollOrientation { - forward, // Forward, right/bottom - backward, // Backward, left/up -} -export type DropScrollTriggerEdge = 'left' | 'right' | 'top' | 'bottom'; -``` - -`DropScrollAreaOffset` 仅重要和次要定位边有效, forward 代表后右或者往下滚动,backward 表示往左或者往上滚动 - -| direction | `v` 上下滚动 | `h` 左右滚动 | -| :------------------ | :--------------- | :------------- | -| forward 往下或往右 | `left` ,`bottom` | `top` ,`right` | -| backward 往左或网上 | `left`,`top` | `top`,`left` | - -### dDropScrollEnhancedSide 附属指令 - -如果需要同时两个方向都有滚动条,则需要使用 dDropScrollEnhanced 的同时使用 dDropScrollEnhancedSide,参数列表同 dDropScrollEnhanced 指令,唯一不同是 direction,如果为`'v'`则 side 附属指令的实际方向为`'h'`。 - -| 名字 | 类型 | 默认值 | 描述 | -| :----------------- | :--------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------- | -| direction | `DropScrollSpeed`即`'v'\|'h'` | 'v' | 滚动方向,垂直滚动`'v'`, 水平滚动 `'h'` | -| responseEdgeWidth | `string \| ((total: number) => string)` | '100px' | 响应自动滚动边缘宽度, 函数的情况传入的为列表容器同个方向相对宽度 | -| speedFn | `DropScrollSpeedFunction` | 内置函数 | 速率函数,见备注 | -| minSpeed | `DropScrollSpeed`即`number` | 50 | 响应最小速度 ,函数计算小于这个速度的时候,以最小速度为准 | -| maxSpeed | `DropScrollSpeed`即`number` | 1000 | 响应最大速度 ,函数计算大于这个速度的时候,以最大速度为准 | -| viewOffset | {forward?: `DropScrollAreaOffset`; backward?: `DropScrollAreaOffset`;} | -- | 设置拖拽区域的偏移,用于某些位置修正 | -| dropScrollScope | `string\| Array` | -- | 允许触发滚动 scope,不配置为默认接收所有 scope,配置情况下,draggable 的`dragScope`和`dropScrollScope`匹配得上才能触发滚动 | -| backSpaceDroppable | `boolean` | true | 是否允许在滚动面板上同时触发放置到滚动面板的下边的具体可以放置元素,默认为 true,设置为 false 则不能边滚动边放置 | - -## 使用 `dDraggable` & `dDroppable` 指令 - -```html -
    -
  • Coffee
  • -
  • Tea
  • -
  • Milk
  • -
-``` - -```html -
-

Drop items here

-
-``` - -## CSS - -`dDraggable` & `dDroppable` 指令都有`[dragOverClass]`作为输入. - 提供 drag 和 drop 时的 hover 样式,注意是`字符串` - -```html -
-

Drop items here

-
-``` - -## 限制 Drop 区域 - -用[dragScope]和[dropScope]限制拖动区域,可以是字符串或数组,只有 drag 和 drop 的区域对应上才能放进去 - -```html -
    -
  • Coffee
  • -
  • Tea
  • -
  • Biryani
  • -
  • Kebab
  • - ... -
-``` - -```html -
-

只有 Drinks 可以放在这个container里

-
- -
-

Meal 和 Drinks 可以放在这个container里

-
-``` - -## 传递数据 - -`dDraggable`可以用[dragData]向`droppable`传递数据 -`dDroppable`用`(dropEvent)`事件接收数据 - -```html -
    -
  • {{item.name}}
  • -
- -
-
Drop Items here
-
-
  • {{item.name}}
  • -
    -
    -``` - -```typescript -export class Component { - items = [ - { name: 'Apple', type: 'fruit' }, - { name: 'Carrot', type: 'vegetable' }, - { name: 'Orange', type: 'fruit' }, - ]; - - onItemDrop(e: any) { - // Get the dropped data here - this.droppedItems.push(e.dragData); - } - constructor() {} -} -``` - -## Drag Handle - -Drag 句柄可以指定实际响应 draggable 事件的元素,而不是 draggable 本身 -这个参数必须是一个字符串,实际上是一个 css 选择器 - -```html -
  • - 只有.drag-handle可以响应拖动事件来拖起li -
    -
  • -``` - -## 异步 DropEnd,通知 Drag 元素 - -`dDraggable`有一个`dropEndEvent`事件,此事件非浏览器默认事件而是自定义事件,非组件自动触发触发方式是在`dDroppable`的`dropEvent`事件的参数中有一个 dropSubject,当需要触发 drag 元素上的 dropEndEvent 事件的时候调用 dropSubject.next(params) 一般是在接口返回之后 例如: - -```html -
      -
    • {{item.name}}
    • -
    - -
    -
    Drop Items here
    -
    -
  • {{item.name}}
  • -
    -
    -``` - -```js -export class Component { - onItemDrop(e: any) { - ajax.onSuccess(() => { - e.dropSubject.next(params); //此时才触发dragComponent的dropEnd 并且params对应onDropEnd的$event; - }); - } - constructor() {} -} -export class dragComponent { - onDropEnd($event, i) {} -} -``` - -# 协同拖拽, 用于二维拖拽,跨纬度拖拽场景 - -## 协同拖 dDragSync - -用于 dDraggle 对象和同时会被拖走的对象。 - -### dDragSync 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------- | :------- | :----- | :--------------------------------------------------------------- | :-------------------------------------------------- | -| dDragSync | `string` | '' | 必选,拖同步的组名,为空或者空字符串的时候无效,不与其他内容同步 | [二维拖拽和拖拽预览](demo#2D-drag-and-drop-preview) | - -## 协同放 dDropSortSync - -用于 dDroppable 对象和与 droppable 内 sortable 结构相同的 sortable 区域, 注意 dDroppable 对象里是与 dDroppable 对象同个对象上注册 dDropSortSync,其他不带 dDroppable 的与放置在排序区域。 - -### dDropSortSync 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----------------- | :---------- | :----- | :--------------------------------------------------------------- | :-------------------------------------------------- | -| dDropSortSync | `string` | '' | 必选,放同步的组名,为空或者空字符串的时候无效,不与其他内容同步 | [二维拖拽和拖拽预览](demo#2D-drag-and-drop-preview) | -| dDropSyncDirection | `'v'\| 'h'` | 'v' | 可选,与 dSortable 的方向正交 | - -## 协同监听盒子 dDragDropSyncBox - -用于统计 dDragSync 和 dDropSortSync 的公共父祖先。 -无参数,放置在公共统计区域则可。 - -# 拖拽预览, 用于需要替换拖拽预览的场景 - -## 拖拽预览 dDragPreview - -需要和 dDraggable 搭配使用, 用于拖起的时候拖动对象的模板 - -### dDragPreview 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------------------------- | :------------------------------ | :----- | :--------------------------------------------------------------------------------- | :-------------------------------------------------- | -| dDragPreview | `TemplateRef` | -- | 必选,预览的模板引用 | [二维拖拽和拖拽预览](demo#2D-drag-and-drop-preview) | -| dragPreviewData | `any` | -- | 可选,自定义数据,将由模板变量获得 | -| dragPreviewOptions | `{ skipBatchPreview : boolean}` | -- | 可选,预览选项 | -| dragPreviewOptions.skipBatchPreview | `boolean` | false | 可选,预览选项, 是否跳过批量预览的样式处理。建议自行处理批量拖拽预览模板的可以跳过 | - -### dDragPreview 模板可用变量 - -| 变量 | 类型 | 变量含义说明 | -| :-----------------: | :------------------: | :-----------------------------------------------------------------------------------------: | -| data | `any` | 从拖拽预览传入的 dragPreviewData 数据 | -| draggedEl | `HTMLElement` | 被拖拽的 DOM 元素 | -| dragData | `any` | 被拖拽元素携带的 dragData 数据 | -| batchDragData | `Array` | 被批量拖拽的对象的 dragData 数据的数组, 含被拖拽元素的 dragData, 并且 dragData 处于第一位 | -| dragSyncDOMElements | `Array` | 被协同拖拽的 DOM 元素, 不包括 draggedEl 指向的 DOM 元素 | - -## 拖拽预览辅助克隆节点 - -可以从节点的引用中恢复 DOM 的克隆对象作为预览 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------- | :------------ | :----- | :----------------------------------------- | :-------- | -| domRef | `HTMLElement` | -- | 必选,否则无意义,克隆节点的 DOM 引用 | -| copyStyle | `boolean` | true | 可选,是否克隆节点的时候对节点依次克隆样式 | diff --git a/devui/dragdrop/doc/api-en.md b/devui/dragdrop/doc/api-en.md deleted file mode 100644 index 51c074ebceb34e40c9ce36f0fec1edd9309eebe6..0000000000000000000000000000000000000000 --- a/devui/dragdrop/doc/api-en.md +++ /dev/null @@ -1,378 +0,0 @@ -# How to use - -Import into module: - -```typescript -import { DragDropModule } from' ng-devui/dragdrop'; -``` - -## Dragdrop - -Provides the dDraggable and dDroppable(dSortable) instructions. - -## dDraggable directive - -### dDraggable Parameter - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :---------------------------- | :--------------------------------------------------------------------------------------------------------------- | :------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------- | -| dragData | `any` | -- | Optional. Data transmitted to the `DropEvent` event. | [Basic Usage](demo#basic-usage) | -| dragScope | `string \| Array` | 'default ' | Optional. Restricts the drop position. It must match the corresponding `dropScope`. | [Basic Usage](demo#basic-usage) | -| dragOverClass | `string` | -- | Optional. CSS of the dragged element. | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| dragHandleClass | `string` | -- | Optional. Drag handle. CSS selector. Only selected elements can respond to drag events. | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Specifies whether the current element can be dragged. false: yes; true: no. | [Basic Usage](demo#basic-usage) | -| enableDragFollow | `boolean` | false | Optional. Whether to enable entity element follow (more special effects such as shadow can be added) | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| dragFollowOption | `{appendToBody?: boolean}` | -- | Optional. It is used to control some configuration of entity dragging. | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| dragFollowOption.appendToBody | `boolean` | false | Optional. controls the position of the clone element to be inserted in entity dragging. The default value false is inserted at the end of all children of the source element's parent element, and the value true is attached to. See Note 1 | [Drag Entity Element to Follow](demo#drag-entity-elements-to-follow) | -| originPlaceholder | `{show?: boolean; tag?: string; style?: {cssProperties: string]: string}; text?: string; removeDelay?: number;}` | -- | Optional. Sets the Source Placeholder for the original position of the dragged element. | [Source Placeholder](demo#source-placeholder) | -| originPlaceholder.show | `boolean` | true | Optional. It indicates whether to display the Source Placeholder. By default, the Source Placeholder is displayed if there is an input. You can disable the Source Placeholder in special cases. | -| originPlaceholder.tag | `string` | 'div' | Optional. Whether to display originPlaceholder. By default, originPlaceholder is displayed if there is an input. This parameter can be disabled in special cases. | -| originPlaceholder.style | `Object` | -- | Optional. The style object is transferred. The key indicates the style attribute, and the value indicates the style value. | [Source Placeholder](demo#source-placeholder) | -| originPlaceholder.text | `string` | -- | Optional. text in placeholder | [Source Placeholder](demo#source-placeholder) | -| originPlaceholder.removeDelay | `number` | -- | Optional. It is used to delete the Source Placeholder in the delay after dragging to facilitate animation. The unit is ms. | [Source Placeholder](demo#source-placeholder) | -| dragIdentity | `any` | -- | Optional. This parameter is used to restore virtual scrolling. During virtual scrolling, the element is deleted (overflow) and then regenerated to restore the element (back to the image). A unique identifier is required to restore the original event drag event listening and Source Placeholder. | -| dragItemParentName | `string` | -- | Optional. Selector name. This parameter is used with dragItemChildrenName to truncate invisible elements in the list to improve performance, query elements matching dragItemChildrenName from the selector matching dragItemParentName. Generally, search for items in the list and delete items beyond the visible scope when cloning. | None | -| dragItemChildrenName | `string` | -- | Optional. Selector name, used with dragItemParentName to drag and truncate the invisible elements in the list to improve performance, see the description of dragItemParentName for the function. | None. | - -Note 1: AppendToBody of dragFollowOptions is used as follows: If the parent object in the source position is destroyed after dragFollowOptions is dragged away, the clone must be attached to the body to prevent it from being destroyed. By default, the style of the entity to be cloned is copied to ensure that the style of the entity to be cloned is correct. However, some styles and attributes that depend on the DOM node location may fail. You need to manually adjust some styles. - -### dDraggable Event - -| Event | Type | Description | Jump to Demo | -| :------------- | :------------------------ | :---------------------------------------- | :------------------------------ | -| dragStartEvent | `EventEmitter` | DragStart event that starts to be dragged | [Basic Usage](demo#basic-usage) | -| dragEndEvent | `EventEmitter` | DragEnd event for ending dragging | [Basic Usage](demo#basic-usage) | -| dropEndEvent | `EventEmitter` | Drop event when the placement ends | [Basic Usage](demo#basic-usage) | - -Drag DOM Events Details: [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent) - -### batchDrag Additional Instructions - -Usage: dDraggable batchDrag - -#### dDraggable batchDrag Attribute - -| Name | Type | Default value | Description | Jump to Demo | -| :---------------------------------- | :------------------------ | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | -| batchDragGroup | `string` | 'default' | Optional. This parameter indicates the name of a group in which a group is dragged in batches. The group name varies according to the group name. | -| batchDragActive | `boolean` | false | Optional. indicates whether to add elements to the batch dragging group. For details, see Note 1. | [Batch dragging](demo#batch-drag-and-drop) | -| batchDragLastOneAutoActiveEventKeys | `Array` | ['ctrlKey'] | Optional. You can activate the judgment of drag events selected in batches by dragging. See Note 2. | -| batchDragStyle | `Array` | ['badge','stack'] | Optional. This parameter indicates the effect of dragging data in batches. Badge indicates that statistics are displayed in the upper right corner, and stack indicates that stacking is displayed. This parameter is valid only when the string exists in the array. | [Batch dragging](demo#batch-drag-and-drop) | - -Note 1: When `batchDragActive` is set to `true`, elements are added to the group in the sequence of changing to true. The elements added first are in front of the array. The first element confirms the names of the groups to be added in batches. If the name of the group to be added later is different from that of the group to be added earlier, the group cannot be added later. -Note 2: The default value of `batchDragLastOneAutoActiveEventKeys` is ['ctrlKey']. That is, you can hold down Ctrl and drag the last element. The element is automatically added to the group to be dragged in batches. The judgment condition is that the ctrlKey event in the dragStart event is true. Currently, only true or false is supported. This parameter is an array. This parameter is valid only when any attribute value is true and can be used for key declarations in different operating systems. - -#### dDraggable batchDrag Event - -| Name | Type | Description | Jump to Demo | -| :------------------- | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :----------------------------------------- | -| batchDragActiveEvent | `EventEmitter<{el: Element, data: any}>` | Adds an element to a batch dragging group through dragging and instructs the external system to select the element. | [Batch dragging](demo#batch-drag-and-drop) | - -## dDropable Instruction - -### dDroppable Parameter - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :-------------------------- | :--------------------------------------------- | :------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------ | -| dropScope | `string \| Array` | 'default' | Optional. restricting the drop area, corresponding to dragScope. | [Basic Usage](demo#basic-usage) | -| dragOverClass | `string` | -- | Optional. CSS applied on the drop element during dragover | -| placeholderStyle | `Object` | {backgroundColor: '#6A98E3', opacity: '.4'} | Optional. It is used for placeholder display when sort is allowed. | [Source Placeholder](demo#source-placeholder) | -| placeholderText | `string` | '' | Optional. This parameter is used to display internal text when sorting is allowed. | -| allowDropOnItem | `boolean` | false | Optional. When sorting is allowed, this parameter can be dragged to an element so that the tree structure can be dragged as a subnode of an element. | [Multi-layer tree dragging](demo#multi-level-tree-drag) | -| dragOverItemClass | `string` | -- | Optional. This parameter is valid only when `allowDropOnItem` is set to `true` and is used to add styles to hit elements after dragging to elements. | [Multi-layer tree dragging](demo#multi-level-tree-drag) | -| nestingTargetRect | `{height?: number, width?: number}` | -- | Optional. It is used to increase the height of the parent item after the embedded list is corrected. Here, height and width are the height of the parent item (for dragging vertically) and width (for dragging horizontally) | [Multi-layer tree dragging](demo#multi-level-tree-drag) | -| defaultDropPosition | `'closest' \| 'before' \| 'after'` | `'closest'` | Optional. Sets the position where a device can be dragged to a place that is not in the list area, `closest'` indicates the nearest place, `before'` indicates the place to be added to the list header, and `after'` indicates the place to be added to the list tail. | [External Placement Position](demo#external-location) | -| dropSortCountSelector | `string` | -- | Optional. This parameter specifies the name of the selector for counting content in the case of sortable containers. It can be used to filter out elements that should not be counted. | -| dropSortVirtualScrollOption | `{totalLength?: number; startIndex?: number;}` | -- | Optional. It is used to return a correct dropIndex in the virtual scrolling list. The value of totalLength is the actual total length of the list, and the value of startIndex is the index value of the first dom displayed in the current sorting area in the list. | - -### dDroppable Event - -| Event | Type | Description | Jump to Demo | -| :------------- | :---------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :------------------------------ | -| dragEnterEvent | `EventEmitter` | dragenter event entered by the drag element | [Basic Usage](demo#basic-usage) | -| dragOverEvent | `EventEmitter` | The dragover event of the drag element on the drop area | [Basic Usage](demo#basic-usage) | -| dragLeaveEvent | `EventEmitter` | dragleave event when the drag element leaves | [Basic Usage](demo#basic-usage) | -| dropEvent | `EventEmitter`(See definition below) | Place an element and receive the event, where nativeEvent represents the native drop event, see definition notes for others | [Basic Usage](demo#basic-usage) | - -### DropEventModel Definition - -```typescript -type DropEvent = { -nativeEvent: any; // Native drop event -dragData: any; // dragData of the drag element -dropSubject: Subject; //Subject of the drop event -dropIndex?: number; // The drop position is in the index of the list. -dragFromIndex?: number; // Index of the drag element in the original list. The virtual scrolling data is invalid. -dropOnItem?: boolean; // Indicates whether to drop the element. This parameter is used with allowDropOnItem. -``` - -## dSortable instruction - -Specifies the parent Dom container that needs to be sorted. (The drop parameter specifies only the dragable area, and the rendering is controlled by the user.) - -### dSortable Parameter - -| Name | Type | Default value | Description | Jump to Demo | -| :------------- | :--------- | :------------ | :------------------------------------- | :----------- | -| dSortDirection | `v'\| 'h'` | 'v' | 'v' vertical sort, 'h' horizontal sort | -| dSortableZMode | `boolean` | false | is in Z mode. For details, see Note 1. | - -Note 1: Z is used to sort data based on the larger direction. If a line break occurs at the end of a row from left to right, use the vertical sorting +z mode because only partial data is from left to right. - -### dDropScrollEnhanced Parameter - -| Name | Type | Default value | Description | Jump to Demo | -| :----------------- | :---------------------------------------------------------------------------------------------- | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------- | -| direction | [`DropScrollDirection`](#dropscrolldirection), that is, `'v'\|'h'` | 'v' | scrolling direction. Vertical scrolling `'v'` and horizontal scrolling `'h'` | [Drag and scroll container enhancement](demo#drag-and-roll-container-enhancement) | -| responseEdgeWidth | `string \| ((total: number) => string)` | '100px' | Edge width of the response to automatic scrolling. The value of this parameter is the relative width of the list container in the same direction. | [Drag and scroll container enhancement](demo#drag-and-roll-container-enhancement) | -| speedFn | [`DropScrollSpeedFunction`](#dropscrolldirection) | built-in function | Rate function. For details, see Remarks. | -| minSpeed | `DropScrollSpeed` indicates `number` | 50 | Minimum response speed. If the value is less than the value, the minimum response speed prevails. | -| maxSpeed | `DropScrollSpeed` indicates `number` | 1000 | Maximum response speed. If the value is greater than this value, the maximum response speed prevails. | -| viewOffset | {forward?: [`DropScrollAreaOffset`](#dropscrollareaOffset); backward?: `DropScrollAreaOffset`;} | -- | Sets the offset of the dragged area, which is used to correct some positions. | -| dropScrollScope | `string\| Array` | -- | allows scrolling. If this parameter is not configured, all scopes are received by default. If this parameter is configured, scrolling can be triggered only when `dragScope` and `dropScrollScope` of dragable match. | [Drag and scroll container enhancement](demo#drag-and-roll-container-enhancement) | -| backSpaceDroppable | `boolean` | true | : whether to trigger elements that can be placed under the scroll panel. The default value is true. If the value is false, elements cannot be placed while scrolling. | - -Note: The default speedFn function is `(x: number) => Math.ceil((1 - x) * 18) * 100`. The input digit `x` indicates the percentage of the distance between the mouse position and the edge to the full response width, -The final speed will be speedFn(x), but will not be less than the minimum speed `minSpeed` or greater than the maximum speed `maxSpeed`. -Definition of related types: - -#### DropScrollDirection - -```typescript -export type DropScrollDirection = 'h' | 'v'; -``` - -#### DropScrollSpeed - -```typescript -export type DropScrollEdgeDistancePercent = number; // unit: 1 -export type DropScrollSpeed = number; // Unit: px/s -export type DropScrollSpeedFunction = (x: DropScrollEdgeDistancePercent) => DropScrollSpeed; -``` - -#### DropScrollAreaOffset - -```typescript -export type DropScrollAreaOffset = { - left?: number; - right?: number; - top?: number; - bottom?: number; - widthOffset?: number; - heightOffset?: number; -}; - -export enum DropScrollOrientation { - forward, // Forward, right/bottom - backward, // Backward, left/up -} -export type DropScrollTriggerEdge = 'left' | 'right' | 'top' | 'bottom'; -``` - -`DropScrollAreaOffset` is valid only for the major and minor positioning edges. forward indicates scrolling to the right or downward, and backward indicates scrolling to the left or upward. - -| direction | `v` Scroll up or down | `h` Scroll right or left | -| :------------------------------ | :-------------------- | :----------------------- | -| forward Down or right | `left` ,`bottom` | `top` ,`right` | -| backward to the left or network | `left`,`top` | `top`,`left` | - -### dDropScrollEnhancedSide Subsidiary Instructions - -If scroll bars are required in both directions, you need to use both dDropScrollEnhanced and dDropScrollEnhancedSide. The parameter list is the same as that of the dDropScrollEnhanced command. The only difference is direction, if `v'`, the actual direction of the side subsidiary directive is `'h'`. - -| Name | Type | Default value | Description | -| :----------------- | :--------------------------------------------------------------------- | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| direction | `DropScrollSpeed`, that is, `v'\|'h'` | 'v' | Scrolling direction, vertical scrolling `'v'`, horizontal scrolling `'h'` | -| responseEdgeWidth | `string \| ((total: number) => string)` | '100px' | Edge width of the response to automatic scrolling. The value is the relative width of the list container in the same direction. | -| speedFn | `DropScrollSpeedFunction` | built-in function | Rate function. For details, see Remarks. | -| minSpeed | `DropScrollSpeed` indicates `number` | 50 | Minimum response speed. If the value is less than the value, the minimum response speed prevails. | -| maxSpeed | `DropScrollSpeed` indicates `number` | 1000 | Maximum response speed. If the value is greater than this value, the maximum response speed prevails. | -| viewOffset | {forward?: `DropScrollAreaOffset`; backward?: `DropScrollAreaOffset`;} | -- | Sets the offset of the dragged area, which is used to correct certain positions. | -| dropScrollScope | `string\| Array` | -- | allows the scrolling scope to be triggered. If this parameter is not configured, all scopes are received by default. If this parameter is configured, the scrolling scope can be triggered only when `dragScope` and `dropScrollScope` of dragable match. | -| backSpaceDroppable | `boolean` | true | whether to trigger elements that can be placed under the scroll panel. The default value is true. If the value is false, elements cannot be placed while scrolling. | - -## Using the `dDraggable` & `dDroppable` Directive - -```html -
      -
    • Coffee
    • -
    • Tea
    • -
    • Milk
    • -
    -``` - -```html -
    -

    Drop items here

    -
    -``` - -## CSS - -The `dDraggable` & `dDroppable` instruction has `[dragOverClass]` as the input. -Hover styles for drag and drop are provided. Note that the value is `string'. - -```html -
    -

    Drop items here

    -
    -``` - -## Restrict the Drop area. - -Use [dragScope] and [dropScope] to restrict the drag area. The drag area can be a string or an array. Only the drag area and drop area can be placed. - -```html -
      -
    • Coffee
    • -
    • Tea
    • -
    • Biryani
    • -
    • Kebab
    • - ... -
    -``` - -```html -
    -

    Only Drinks can be placed in this container.

    -
    -
    -

    Meal and Drinks can be placed in this container.

    -
    -``` - -## Transfer data. - -`dDraggable` can use [dragData] to transfer data to `droppable` -`dDropable` uses the `(dropEvent)` event to receive data. - -```html -
      -
    • {{item.name}}
    • -
    -
    -
    Drop Items here
    -
    -
  • {{item.name}}
  • -
    -
    -``` - -```typescript -export class Component { - items = [ - { name: 'Apple', type: 'fruit' }, - { name: 'Carrot', type: 'vegetable' }, - { name: 'Orange', type: 'fruit' }, - ]; - onItemDrop(e: any) { - // Get the dropped data here - this.droppedItems.push(e.dragData); - } - constructor() {} -} -``` - -## Drag Handle - -The drag handle can specify the element that actually responds to the dragable event, not the dragable itself. -This parameter must be a string, and is actually a css selector. - -```html -
  • - Only .drag-handle can respond to drag events to drag li. -
    -
  • -``` - -## Asynchronous DropEnd, notifying the Drag element - -The `dDraggable` event has a `dropEndEvent` event, which is not a default event of the browser but a user-defined event. The non-component automatic triggering mode is that the `dropEvent` event of the `dDropgable` contains a dropSubject, when the dropEndEvent event on the drag element needs to be triggered, call dropSubject.next(params) after the interface returns. For example: - -```html -
      -
    • {{item.name}}
    • -
    -
    -
    Drop Items here
    -
    -
  • {{item.name}}
  • -
    -
    -``` - -```js -export class Component { - onItemDrop(e: any) { - ajax.onSuccess(() => { - e.dropSubject.next(params); //The dropEnd of dragComponent is triggered and params corresponds to $event of onDropEnd. - }); - } - constructor() {} -} -export class dragComponent { - onDropEnd($event, i) {} -} -``` - -# Collaborative dragging, used in two-dimensional dragging and cross-dimension dragging scenarios - -## Collaborative drag dDragSync - -Used for dDraggle objects and objects that can be dragged at the same time. - -### dDragSync Parameter - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :-------- | :------- | :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------- | -| dDragSync | `string` | '' | Mandatory, Name of the group to be synchronized. This parameter is invalid when the parameter is left blank or an empty string and is not synchronized with other content. | [Two-dimensional drag and preview](demo#2D-drag-and-drop-preview) | - -## Collaborative distribution dDropSortSync - -Used for the dDropable object and the sortable area with the same structure as the sortable area in the dropable object. Note that dDropSortSync is registered on the same object as the dDropable object, the AND without dDropable is placed in the sorting area. - -### dDropSortSync Parameter - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :----------------- | :-------- | :------------ | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------- | -| dDropSortSync | `string` | '' | Mandatory, Name of the group to be synchronized. This parameter is invalid when the value is empty or an empty string. The value | [Two-dimensional drag and preview](demo#2D-drag-and-drop-preview) | is not synchronized to other content. | -| dDropSyncDirection | `v'\|'h'` | 'v' | Optional. orthogonal to the direction of dSortable | - -## Collaborative listening box dDragDropSyncBox - -Used to collect statistics on the common parent ancestors of dDragSync and dDropSortSync. -No parameter is available. You can place the parameter in the public statistical area. - -# Drag and preview, which is used in the scenario where drag and preview need to be replaced. - -## Drag and preview dDragPreview - -This parameter is used together with dDraggable to drag an object template. - -### dDragPreview Parameter - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :---------------------------------- | :---------------------------- | :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------- | -| dDragPreview | `TemplateRef` | -- | Required. The preview profile references | [Two-dimensional drag and preview](demo#2D-drag-and-drop-preview) | -| dragPreviewData | `any` | -- | Optional. Customized data, which is obtained from template variables. | -| dragPreviewOptions | `{skipBatchPreview: boolean}` | -- | Optional. preview option | -| dragPreviewOptions.skipBatchPreview | `boolean` | false | Optional. preview option, whether to skip the batch preview style processing. It is recommended that you can skip the batch drag and drop preview template by yourself. | - -### Available variables in the dDragPreview template - -| Variable | Type | Variable Description | -| :-----------------: | :------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------: | -| data | `any` | dragPreviewData data transferred from drag preview | -| draggedEl | `HTMLElement` | Dragged DOM element | -| dragData | `any` | DragData carried by the drag element | -| batchDragData | `Array` | An array of dragData data of the objects being dragged in batches, including dragData of the dragged element, and dragData is in the first place. | -| dragSyncDOMElements | `Array` | DOM elements that are dragged collaboratively, excluding the DOM elements pointed to by draggedEl | - -## Dragging and previewing the auxiliary clone node - -You can restore the cloned object of the DOM from the node's reference as a preview. - -| Parameter | Type | Default Value | Description | Jump to Demo | -| :-------- | :------------ | :------------ | :--------------------------------------------------------------------- | :----------- | -| domRef | `HTMLElement` | -- | Mandatory, Otherwise meaningless, clone the DOM reference of the node. | -| copyStyle | `boolean` | true | Optional. whether to clone nodes in sequence when cloning nodes. | diff --git a/devui/dragdrop/dragdrop.tsx b/devui/dragdrop/dragdrop.tsx deleted file mode 100644 index a2e25f330aa6c7eed93b3cf3ad3f47f9aad7d431..0000000000000000000000000000000000000000 --- a/devui/dragdrop/dragdrop.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-dragdrop', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-dragdrop
    - } - } -}) \ No newline at end of file diff --git a/devui/drawer/demo/drawer-demo.tsx b/devui/drawer/demo/drawer-demo.tsx deleted file mode 100644 index 7df9498f8bca9e56d2ed02a0c5e35a18d7112da8..0000000000000000000000000000000000000000 --- a/devui/drawer/demo/drawer-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-drawer-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-drawer-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/drawer/demo/drawer.route.ts b/devui/drawer/demo/drawer.route.ts deleted file mode 100644 index 2a7b3de733305a8f6ccda0933140c0ad8147eb32..0000000000000000000000000000000000000000 --- a/devui/drawer/demo/drawer.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import DrawerDemoComponent from './drawer-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: DrawerDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/drawer/doc/api-cn.md b/devui/drawer/doc/api-cn.md deleted file mode 100644 index d6879a339149cc95bcd5bb1aa94fdd40d680e614..0000000000000000000000000000000000000000 --- a/devui/drawer/doc/api-cn.md +++ /dev/null @@ -1,82 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { DrawerModule } from 'ng-devui/drawer'; -``` - -在页面中使用: - -```html -click me! 通过openDrawer函数中调用drawerService.open()打开抽屉板 -``` - -**打开 Drawer 层**:drawerService.**open** ( ~ : **IDrawerOptions** ) : **IDrawerOpenResult** - -```ts -openDrawer() { - this.results = this.drawerService.open({ - drawerContentComponent: DrawerContentComponent, - width: '50%', - zIndex: 1000, - isCover: true, - fullScreen: true, - backdropCloseable: true, - escKeyCloseable: true, - position: 'left', - onClose: () => { - console.log('on drawer closed'); - }, - data: { - text: 'hello', - name: 'tom1' - } - }); - } -``` - -注意:传递给 API 中 drawerContentComponent 的组件需要在当前 Module 的\`declarations\`和\`entryComponents\`属性中注册。 - -# Drawer - -## IDrawerOptions 参数 - -| 属性 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-------------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------------- | -| drawerContentComponent | `Type` | -- | 必要参数,传入自定义的 component | [基本用法](demo#basic-usage) | -| componentFactoryResolver | `ComponentFactoryResolver` | 内置 | 可选,一般不需要设置 | -| injector | `Injector` | -- | 可选,一般不需要设置 | -| width | `string` | '300px' | 可选,设置 drawer 的宽度 | [基本用法](demo#basic-usage) | -| zIndex | `number` | 1000 | 可选,设置 drawer 的 z-index 值 | [基本用法](demo#basic-usage) | -| isCover | `boolean` | true | 可选,是否有遮罩层 | [基本用法](demo#basic-usage) | -| data | `any` | -- | 可选,可以传入任意对象给 drawerContentComponent 使用 | [基本用法](demo#basic-usage) | -| backdropCloseable | `boolean` | true | 可选,设置可否通过点击背景来关闭 drawer 层 | [基本用法](demo#basic-usage) | -| escKeyCloseable | `boolean` | true | 可选,设置可否通过 esc 按键来关闭 drawer 层 | [基本用法](demo#basic-usage) | -| onClose | `Function` | -- | 可选,关闭 drawer 时候调用 | [基本用法](demo#basic-usage) | -| afterOpened | `Function` | -- | \可选,打开 drawer 后时候调用 | -| beforeHidden | `Function\|Promise\|()=> Observable` | -- | 可选, 关闭 drawer 前调用,返回 boolean 类型,返回 false 可以阻止关闭 drawer 层 | [基本用法](demo#basic-usage) | -| clickDoms | `array` | [] | 可选,isCover 为 false 的情况下,点击 Dom 关闭侧滑栏 | [关闭后不销毁](demo#do-not-destroy-after-closing) | -| destroyOnHide | `boolean` | true | 可选,关闭 drawer 时是否销毁 DrawerComponent,默认销毁 | [关闭后不销毁](demo#do-not-destroy-after-closing) | -| position | `string` | 'right' | 可选,抽屉板出现的位置,'left'或者'right' | [基本用法](demo#basic-usage) | -| bodyScrollable | `boolean` | true | 可选,drawer 打开后,body 是否可滚动,默认为可滚动,false 时隐藏滚动,隐藏滚动条可能会产生抖动,可以通过设置外层 fixed 来同时避免滚动与抖动,可参考 modal 的解决方案 | [解决抖动滚动问题](demo#template-fixed) | - -## IDrawerOpenResult 参数 - -| 属性 | 类型 | 说明 | 跳转 Demo | -| :-------------------: | :---------------: | :-------------------------------------------: | ---------------------------- | -| drawerInstance | `DrawerComponent` | 返回 Drawer 对象 | [基本用法](demo#basic-usage) | -| drawerContentInstance | `Type` | 返回 Drawer 的承载内容的对象,包括传入的 data | [基本用法](demo#basic-usage) | - -## drawerInstance API - -- **切换 drawer 的全屏状态**:drawerInstance.**toggleFullScreen**(): void - -- **设置 drawer 的全屏状态**:drawerInstance.**setFullScreen**(fullScreen: boolean): void - -- **触发打开 drawer 层**:drawerInstance.**show**(): void - -- **触发关闭 drawer 层**:drawerInstance.**hide**(): void, 该函数会先检查 beforeHidden,如果返回 true 才关闭 - -- **触发销毁 drawer 层**:drawerInstance.**destroy**(): void, destroyOnHide 为 false 且 drawer 层关闭时可以调用 destroy 方法销毁 -- **设置宽度**:drawerInstance.**setWidth**(width: string): void diff --git a/devui/drawer/doc/api-en.md b/devui/drawer/doc/api-en.md deleted file mode 100644 index 1e48bafe425cef5912b5fdb11e548eb6fb914814..0000000000000000000000000000000000000000 --- a/devui/drawer/doc/api-en.md +++ /dev/null @@ -1,79 +0,0 @@ -# How to use -Import into module: -```ts -import { DrawerModule } from 'ng-devui/drawer'; -``` - -In the page: -```html -click me! -Call drawerService.open() in the openDrawer function to open the drawer board. -``` -**Open the drawer layer**: drawerService.**open** (~: **IDrawerOptions**): **IDrawerOpenResult** - -```ts -openDrawer() { - this.results = this.drawerService.open({ - drawerContentComponent: DrawerContentComponent, - width: '50%', - zIndex: 1000, - isCover: true, - fullScreen: true, - backdropCloseable: true, - escKeyCloseable: true, - position: 'left', - onClose: () => { - console.log('on drawer closed'); - }, - data: { - text: 'hello', - name: 'tom1' - } - }); - } -``` -Note: Components passed to drawerContentComponent in the API need to be registered in the \`declarations\` and \`entryComponents\` properties of the current module. - -# Drawer - - -## IDrawerOptions Parameter - -| Attribute | Type | Default | Description | Jump to Demo | -| :----------------------: | :------------------------: | :------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------------- | -| drawerContentComponent | `Type` | -- | Required. The user-defined component is transferred. | [Basic Usage](demo#basic-usage) | -| componentFactoryResolver | `ComponentFactoryResolver` | Built-in | Optional. Generally this parameter is not required. | -| injector | `Injector` | -- | Optional. You do not need to set this parameter. | -| width | `string` | '300px' | Optional. Sets the width of the drawer. | [Basic Usage](demo#basic-usage) | -| zIndex | `number` | 1000 | Optional. Sets the z-index value of the drawer. | [Basic Usage](demo#basic-usage) | -| isCover | `boolean` | true | Optional. Indicating whether a mask is available. | [Basic Usage](demo#basic-usage) | -| data | `any` | -- | Optional. Any object can be transferred for the drawerContentComponent. | [Basic Usage](demo#basic-usage) | -| backdropCloseable | `boolean` | true | Optional. Specifies whether to close the drawer layer by clicking the background. | [Basic Usage](demo#basic-usage) | -| escKeyCloseable | `boolean` | true | Optional. Sets whether the drawer layer can be closed by pressing the esc key. | [Basic Usage](demo#basic-usage) | -| onClose | `Function` | -- | Optional. This command is invoked when the drawer is disabled. | [Basic Usage](demo#basic-usage) | -| afterOpened | `Function` | -- | This command is optional. It is invoked when the drawer is opened. | -| beforeHidden | `Function\|Promise\|()=> Observable` | -- | Optional. This API is invoked before the drawer is disabled. The value of the boolean type is returned. The value false can prevent the drawer layer from being disabled. | [basic usage](demo#basic-usage) | -| clickDoms | `array` | [] | Optional. When isCover is set to false, click Dom to close the side slide bar. | [Do not destroy after being closed](demo#do-not-destroy-after-closing) | -| destroyOnHide | `boolean` | true | Optional. Whether to destroy the drawer component when the drawer is disabled. The default value is yes. | [Do not destroy after being closed](demo#do-not-destroy-after-closing) | -| position | `string` | 'right' | Optional. The value can be left or right. | [Basic Usage](demo#basic-usage) | -| bodyScrollable | `boolean` | true | Optional. Whether the body can be scrolled when the drawer opens. The default value is false. If the scroll bar is hidden, the scroll bar may jitter. You need to resolve the problem in the page layout. | - -## IDrawerOpenResult Parameter - -| Attribute | Type | Description | Jump to Demo | -| :-------------------: | :---------------: | :-------------------------------------------: | ----------------------------------------------- | -| drawerInstance | `DrawerComponent` | Returns a Drawer object. | [Basic Usage](demo#basic-usage) | -| drawerContentInstance | `Type` | Returns the object that carries the content of the Drawer, including the incoming data. | [Basic Usage](demo#basic-usage) | - -## drawerInstance API - -- **Switch the full screen status of the drawer**: drawerInstance.**toggleFullScreen**(): void - -- **Set the full-screen status of the drawer**: drawerInstance.**setFullScreen**(fullScreen: boolean): void - -- **Trigger opening of the drawer layer**:drawerInstance.**show**(): void - -- **Trigger the drawer layer to be disabled**: drawerInstance.**hide**(): void. This function checks beforeHidden first. If true is returned, the function is disabled. - -- **Trigger the destruction of the drawer layer**: drawerInstance.**destroy**(): void. When destroyOnHide is set to false and the drawer layer is disabled, the destroy method can be invoked to destroy the drawer layer. -- **Set the width**: drawerInstance.**setWidth**(width: string): void diff --git a/devui/drawer/drawer.tsx b/devui/drawer/drawer.tsx deleted file mode 100644 index ad2892bc439c0f65d3d7dd03884bdeaf0ec96080..0000000000000000000000000000000000000000 --- a/devui/drawer/drawer.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-drawer', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-drawer
    - } - } -}) \ No newline at end of file diff --git a/devui/dropdown/demo/dropdown-demo.tsx b/devui/dropdown/demo/dropdown-demo.tsx deleted file mode 100644 index e4139fe985e0796e05f6168ff796d996d61a91c9..0000000000000000000000000000000000000000 --- a/devui/dropdown/demo/dropdown-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-dropdown-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-dropdown-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/dropdown/demo/dropdown.route.ts b/devui/dropdown/demo/dropdown.route.ts deleted file mode 100644 index 8e55c740a86e6b2b50b2e50bdc7cc7a35e900984..0000000000000000000000000000000000000000 --- a/devui/dropdown/demo/dropdown.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import DropdownDemoComponent from './dropdown-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: DropdownDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/dropdown/doc/api-cn.md b/devui/dropdown/doc/api-cn.md deleted file mode 100644 index eb8e23da3e277b3eae4504b7d7f716b686546aa9..0000000000000000000000000000000000000000 --- a/devui/dropdown/doc/api-cn.md +++ /dev/null @@ -1,118 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```typescript -import { DragDropModule } from ' ng-devui/dragdrop'; -``` - -## dDropDown - -> 使用指定的本地变量 #dropdown="d-dropdown" - -### dDropDown 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------------------: | :----------------------------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------ | -| isOpen | `boolean` | false | 可选,可以显示指定 dropdown 是否打开 | [设置 isOpen 控制下拉](demo#dropdown-set-is-open) | -| disabled | `boolean` | false | 可选,设置为 true 禁用 dropdown | -| trigger | `'click'\|'hover'\|'manually'` | 'click' | 可选,dropdown 触发方式, click 为点击,hover 为悬停(也包含点击)、manually 为完全手动控制 | [悬浮下拉](demo#suspension-drop-down) | -| closeScope | `'all'\|'blank'\|'none'` | 'all' | 可选,点击关闭区域,blank 点击非菜单空白才关闭, all 点击菜单内外都关闭,none 菜单内外均不关闭仅下拉按键可以关闭 | [关闭触发点设置](demo#turn-off-trigger-point-settings) | -| closeOnMouseLeaveMenu | `boolean` | false | 可选,是否进入菜单后离开菜单的时候关闭菜单 | [多级下拉菜单](demo#multi-level-drop-down-menu) | - -### dDropDown 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :---------: | :---------------------: | :--------------------------------------------------------------------: | ---------------------------- | -| toggleEvent | `EventEmitter` | dropdown 菜单展开和收起的布尔值,true 表示将要展开,false 表示将要关闭 | [基本用法](demo#basic-usage) | - -## appendToBody(dDropDown 附加指令组件) - -搭配 dDropDown 使用该指令后,dDropDownMenu 会被附加到 body,可以防止 dropdown 在滚动条内被遮挡。 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------------: | :-------------------------------------------------------------------------------------------------------: | :----------------------------------------------: | :-------------------------------------: | ------------------------------------------------ | -| alignOrigin | `HTMLElement` | 可选,dDropDownToggle 所在对象 | 指定对齐的对象 | [设置展开位置处理](demo#when-using-appendtobody) | -| appendToBodyDirections | `Array<`[`AppendToBodyDirection`](#appendtobodydirection)`\|`[`ConnectedPosition`](#connectedposition)`>` | `['rightDown', 'leftDown', 'rightUp', 'leftUp']` | 可选, 方向数组优先采用数组里靠前的位置 | [设置展开位置处理](demo#when-using-appendtobody) | - -注意: 使用 appendToBody 后需要在有滚动条的地方使用`cdkScrollable` - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import { ScrollDispatchModule } from '@angular/cdk/scrolling'; - -@NgModule({ - imports: [ - // ... - ScrollDispatchModule, - // ... - ] -}) -``` - -```html -
    - -
    -``` - -类型定义: - -### ConnectedPosition - -引用自`@angular/cdk/overlay` - -```typescript -export interface ConnectedPosition { - originX: 'start' | 'center' | 'end'; - originY: 'top' | 'center' | 'bottom'; - - overlayX: 'start' | 'center' | 'end'; - overlayY: 'top' | 'center' | 'bottom'; - - weight?: number; - offsetX?: number; - offsetY?: number; - panelClass?: string | string[]; -} -``` - -### AppendToBodyDirection - -```typescript -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -简化的几个基础的方向为名字 - -| 简化名 | 意义 | -| :--------: | :-------------------------------------------------------------------------: | -| rightDown | 相对于对齐对象显示在`右下`方向, 即左对齐,显示在下方(注意右下是左对齐的) | -| rightUp | 相对于对齐对象显示在`右上`方向, 即左对齐,显示在上方 | -| leftUp | 相对于对齐对象显示在`左上`方向, 即右对齐,显示在上方 | -| leftDown | 相对于对齐对象显示在`左下`方向, 即右对齐,显示在下方 | -| centerDown | 相对于对齐对象显示在`居中下`方向, 即居中对齐,显示在下方 | -| centerUp | 相对于对齐对象显示在`居中上`方向, 即居中对齐,显示在上方 | - -简化了 6 个方向的命名,其余方向可以通过 angular/cdk/overlay 的 ConnectedPosition 进行使用。 - -appendToBodyDirections 默认的显示顺序为 ['rightDown', 'leftDown', 'rightUp', 'leftUp'], -会尝试第一个位置,第一个位置放不下会尝试第二个位置,依此类推。 - -## dDropDownToggle - -用在菜单的控制对象上,参考 demo。 - -### dDropDownToggle 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :-------: | :---: | :-------------------------------: | ----------------------------------------------------- | -| toggleOnFocus | `boolean` | false | 可选,通过 Tab 聚焦的时候自动展开 | [自动展开和自动聚焦](demo#auto-expand-and-auto-focus) | -| autoFocus | `boolean` | false | 可选,实例化后自动聚焦 | [自动展开和自动聚焦](demo#auto-expand-and-auto-focus) | - -## dDropDownMenu - -用在需要展开和关闭的菜单内容上,参考 demo。 diff --git a/devui/dropdown/doc/api-en.md b/devui/dropdown/doc/api-en.md deleted file mode 100644 index bba7c6ff8b0c3ed4eb844c622e833e0609c12cdc..0000000000000000000000000000000000000000 --- a/devui/dropdown/doc/api-en.md +++ /dev/null @@ -1,114 +0,0 @@ -# How to use - -Import into module: - -```typescript -import { DropDownModule } from ' ng-devui/dropdown'; -``` - -## dDropDown - -> Use the specified local variable #dropdown="d-dropdown" - -### dDropDown Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------------: | :---------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------------- | -| isOpen | `boolean` | false | Optional. It indicates whether dropdown is enabled. | [Control dropdown meanu with isOpen](demo#dropdown-set-is-open) | -| disabled | `boolean` | false | Optional. Set this parameter to true to disable dropdown. | -| trigger | `click'\|'hover'\|'manually'` | 'click' | Optional. Dropdown trigger mode. Click indicates click, hover indicates hover (including click), and manually indicates manual control. | [Hover dropdown](demo#suspension-drop-down) | -| closeScope | `'all'\|'blank'\|'none'` | 'all' | Optional. Click the blank area to close the blank area. Click all to close the blank area, the none menu can be closed either inside or outside. Only the drop-down button can be closed. | [Close Trigger Point Settings](demo#turn-off-trigger-point-settings) | -| closeOnMouseLeaveMenu | `boolean` | false | Optional. Whether to close the menu when you exit the menu after entering the menu | [Multi-level drop-down menu](demo#multi-level-drop-down-menu) | - -### dDropDown Event - -| Event | Type | Description | Jump to Demo | -| :---------: | :---------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------: | ------------------------------- | -| toggleEvent | `EventEmitter` | dropdown Boolean value for expanding or collapsed menus. true indicates that the menu is to be expanded and false indicates that the menu is to be disabled. | [Basic usage](demo#basic-usage) | - -## appendToBody (dDropDown additional instruction component) - -If this command is used together with dDropDown, dDropDownMenu is attached to the body to prevent dropdown from being blocked in the scroll bar. - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------: | :-------------------------------------------------------------------------------------------------------: | :-----------------------------------------------: | :---------------------------------------------------------------------------------------: | --------------------------------------------------------------------- | -| alignOrigin | `HTMLElement` | dDropDownToggle Element | Optional. Specify the aligned object | [Set the expansion position processing](demo#when-using-appendtobody) | -| appendToBodyDirections | `Array<`[`AppendToBodyDirection`](#appendtobodydirection)`\|`[`ConnectedPosition`](#connectedposition)`>` | ` ['rightDown', 'leftDown', 'rightUp', 'leftUp']` | Optional. The direction array preferentially uses the position in the front of the array. | [Set the expansion position processing](demo#when-using-appendtobody) | - -Note: After appendToBody is used, use `cdkScrollable` where the scroll bar is available. - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import {ScrollDispatchModule} from '@angular/cdk/scrolling'; -@NgModule({ -imports: [ -//... -ScrollDispatchModule, -//... -] -}) -``` - -```html -
    - -
    -``` - -Type Definition: - -### ConnectedPosition - -Quoted from `@angular/cdk/overlay` - -```TypeScript -export interface ConnectedPosition { -originX: 'start' | 'center' | 'end'; -originY: 'top' | 'center' | 'bottom'; -overlayX: 'start' | 'center' | 'end'; -overlayY: 'top' | 'center' | 'bottom'; -weight?: number; -offsetX?: number; -offsetY?: number; -panelClass?: string | string[]; -} -``` - -### AppendToBodyDirection - -```typescript -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -Simplify several basic directions for the name. - -| Simplified name | Meaning | -| :-------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------: | -| rightDown | Display in the lower right direction relative to the aligned object, that is, the object is left aligned. (Note that the lower right is left aligned.) | -| rightUp | Display in the upper right direction relative to the aligned object. That is, the object is left aligned and displayed at the top. | -| leftUp | Display in the `leftUp` direction relative to the aligned object, that is, right-aligned and displayed above. | -| leftDown | Display in the `left bottom` direction relative to the aligned object, that is, right-aligned and displayed below. | -| centerDown | Display in the `center-bottom` direction relative to the aligned object. That is, the object is center-aligned and displayed below. | -| centerUp | Display in the `center-up` direction relative to the aligned object, that is, display in the center-aligned direction. | - -The naming of six directions is simplified. Other directions can be used by using the ConnectedPosition of angular/cdk/overlay. -appendToBodyDirections: The default display sequence is ['rightDown','leftDown','rightUp','leftUp']. -Try the first position, try the second position, and so on. - -## dDropDownToggle - -Used for menu control objects. For details, see demo. - -### dDropDownToggle Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------: | :-------: | :-----: | :-------------------------------------------------------: | -------------------------------------------------------------------- | -| toggleOnFocus | `boolean` | false | Optional. Automatically expands when you focus on the tab | [Auto Expand and Auto Focus](demo#auto-expand-and-auto-focus) | -| autoFocus | `boolean` | false | Optional. Automatic focus after instantiation | [Automatic expansion and autofocus](demo#auto-expand-and-auto-focus) | - -## dDropDownMenu - -Used to expand and close menus. For details, see the demo. diff --git a/devui/dropdown/dropdown.tsx b/devui/dropdown/dropdown.tsx deleted file mode 100644 index 8feb8bd1f4bdcef0fa7d4aee6d854796f158c14b..0000000000000000000000000000000000000000 --- a/devui/dropdown/dropdown.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-dropdown', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-dropdown
    - } - } -}) \ No newline at end of file diff --git a/devui/editable-select/demo/editable-select-demo.tsx b/devui/editable-select/demo/editable-select-demo.tsx deleted file mode 100644 index 227f7f002e2384ed0b68832cc264ad2887ab1d3a..0000000000000000000000000000000000000000 --- a/devui/editable-select/demo/editable-select-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-editable-select-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-editable-select-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/editable-select/demo/editable-select.route.ts b/devui/editable-select/demo/editable-select.route.ts deleted file mode 100644 index 91469c39774b77e75551f82580b301fcbd092908..0000000000000000000000000000000000000000 --- a/devui/editable-select/demo/editable-select.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import EditableSelectDemoComponent from './editable-select-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: EditableSelectDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/editable-select/doc/api-cn.md b/devui/editable-select/doc/api-cn.md deleted file mode 100644 index 266c13e1c728e3130ff390c450f1d8f643096c36..0000000000000000000000000000000000000000 --- a/devui/editable-select/doc/api-cn.md +++ /dev/null @@ -1,42 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { EditableSelectModule } from 'ng-devui/editable-select'; -``` -在页面中使用: -```html - -``` -# d-editable-select -## d-editable-select 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :------------: | :---------------------------------: | :--------------------------------------------- | ------------------------------------------------------------------------- | -| appendToBody | `boolean` | false | 可选,下拉是否 appendToBody | [基本用法](demo#basic-usage) | -| width | `number` | -- | 可选,控制下拉框宽度,搭配 appendToBody 使用(`px`) | -| ngModel | `any` | -- | 可选,绑定选中对象,可双向绑定 | [基本用法](demo#basic-usage) | -| source | `Array` | -- | 必选,数据列表 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,值为 true 禁用下拉框 | -| disabledKey | `string` | -- | 可选,设置禁用选项的 Key 值 | [设置禁用选项](demo#disable-data-with-source) | -| placeholder | `string` | '' | 可选,没有选中项的时候提示文字 | -| itemTemplate | `TemplateRef` | -- | 可选,下拉菜单条目的模板 | -| noResultItemTemplate | `TemplateRef` | -- | 可选,下拉菜单条目搜索后没有结果的模板 | -| maxHeight | `number` | -- | 可选,下拉菜单的最大高度(`px`) | [基本用法](demo#basic-usage) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | 可选,自定义搜索函数 | [自定义匹配方法](demo#with-search-function) | -| enableLazyLoad | `boolean` | false | 可选,是否允许懒加载 | [数据懒加载](demo#lazy-load) | - -## d-editable-select 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :------: | :-----------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------- | -| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [数据懒加载](demo#lazy-load) | - -# 接口 & 类型定义 -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { - return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` -term 为输入的关键字。 diff --git a/devui/editable-select/doc/api-en.md b/devui/editable-select/doc/api-en.md deleted file mode 100644 index 0e513fcc14f7e5447f4074357f3b1e65e21eb6cd..0000000000000000000000000000000000000000 --- a/devui/editable-select/doc/api-en.md +++ /dev/null @@ -1,42 +0,0 @@ -# How to use -Import into module -```ts -import { EditableSelectModule } from' ng-devui/editable-select'; -``` -On the page -```html - -``` -# d-editable-select -## d-editable-select parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :------------: | :---------------------------------: | :--------------------------------------------- | ------------------------------------------------------------------------- | -| appendToBody | `boolean` | false | Optional. Whether to appendToBody in the drop-down list box | [Basic usage](demo#basic-usage) | -| width | `number` | -- | Optional. Controls the width of the drop-down list box. This parameter is used with appendToBody (`px`) | -| ngModel | `any` | -- | Optional. Selected objects can be bound in both directions. | [Basic usage](demo#basic-usage) | -| source | `Array` | -- | Required. Data list | [Basic usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. The value true indicates that the drop-down list box is disabled. | -| disabledKey | `string` | -- | Optional. Sets the key value of the disabled option. | [Set disable options](demo#disable-data-with-source) | -| placeholder | `string` |'' | Optional. This field is displayed when no item is selected. | -| itemTemplate | `TemplateRef` | -- | Optional, Dropdown list item template | -| noResultItemTemplate | `TemplateRef` | -- | Optional. Template for which no result is found after the drop-down list item is searched. | -| maxHeight | `number` | -- | Optional. Maximum height of the drop-down list box (`px`) | [Basic usage](demo#basic-usage) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | Optional. User-defined search function | [Customized data matching method](demo#with-search-function) | -| enableLazyLoad | `boolean` | false | Optional. Whether lazy loading is allowed | [Enable lazy load](demo#lazy-load) | - -## d-editable-select event - -| Event | Type | Description | Jump to Demo | -| :------: | :-----------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------- | -| loadMore | `EventEmitter>` | lazy loading trigger event. This event is used together with `enableLazyLoad' to disable the loading status. \$event indicates the instance of AutoCompletePopupComponent | [Enable lazy load](demo#lazy-load) | - -# Interface & Type Definition -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { -return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` -term indicates the entered keyword. diff --git a/devui/editable-select/editable-select.tsx b/devui/editable-select/editable-select.tsx deleted file mode 100644 index c7c03585a780d9e6ee2236a028b5e8981c482df1..0000000000000000000000000000000000000000 --- a/devui/editable-select/editable-select.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-editable-select', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-editable-select
    - } - } -}) \ No newline at end of file diff --git a/devui/form/demo/form-demo.tsx b/devui/form/demo/form-demo.tsx deleted file mode 100644 index a3a1b427060f8d43ef0cf757c051478b40fa3cac..0000000000000000000000000000000000000000 --- a/devui/form/demo/form-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-form-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-form-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/form/demo/form.route.ts b/devui/form/demo/form.route.ts deleted file mode 100644 index e92a96e3b78a6bf7d95f6262c3b31ca1b62ae2ef..0000000000000000000000000000000000000000 --- a/devui/form/demo/form.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import FormDemoComponent from './form-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: FormDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/form/doc/api-cn.md b/devui/form/doc/api-cn.md deleted file mode 100644 index 0baf4b6ea16ea2c10b762bf7fdf6ca37a661b619..0000000000000000000000000000000000000000 --- a/devui/form/doc/api-cn.md +++ /dev/null @@ -1,283 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { FormModule } from 'ng-devui/form'; -``` - -如果你需使用到 NgForm,则引入: - -```ts -import { FormsModule } from '@angular/forms'; -``` - -在页面中使用: - -```html -
    - - ... - - - - - - - - ... - - - - - - - - - - - -
    - - - -``` - -# dForm - -## dForm 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------: | :-----------------------------------: | :----------: | :------------------------------------------------------------------------- | -------------------------------------------- | -| layout | `'horizontal'\|'vertical'\|'columns'` | 'horizontal' | 可选,设置表单的排列方式 | [基本用法](demo#basic-usage) | -| labelSize | `'sm' \| '' \| 'lg'` | '' | 可选,设置 label 的占宽,未设置默认为 100px,'sm'对应 80px,'lg'对应 150px | [label 横向排列](demo#demo-label-horizontal) | -| labelAlign | `'start' \| 'center' \| 'end'` | 'start' | 可选,设置水平布局方式下,label对齐方式 | [label 横向排列](demo#demo-label-horizontal) | - -## dForm 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :------: | :-----------------: | :-------------------------------------------------------------------------------------- | ---------------------------------------------- | -| dSubmit | `EventEmitter<{valid: boolean, directive: `[`DFormGroupRuleDirective`](#dformgroupruledirective) `\| AbstractControlDirective}, errors: {[key: string]: ValidationErrors}>` | 可选,使用dFormSubmit绑定元素触发提交时,响应事件 | [模板驱动表单验证(推荐)](demo#demo-validate-template) | - -# d-form-item - -## d-form-item 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-------: | :---: | :------------------------------------------ | --------------------------------------------- | -| dHasFeedback | `boolean` | false | 可选,设置当前 formControl 是否显示反馈图标 | [响应式表单验证](demo#demo-validate-reactive) | - -# d-form-label - -## d-form-label 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------: | :-------: | :---: | :------------------------------------------------- | ---------------------------- | -| required | `boolean` | false | 可选,表单选项是否必填 | [基本用法](demo#basic-usage) | -| hasHelp | `boolean` | false | 可选,表单项是否需要帮助指引 | [基本用法](demo#basic-usage) | -| helpTips | `string` | '' | 可选,表单项帮助指引提示内容,需配合 `hasHelp`使用 | [基本用法](demo#basic-usage) | - -# d-form-control - -## d-form-control 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------: | :-----------------------------------------: | :--: | :----------------------------------------- | -------------------------------------------- | -| extraInfo | `string \| TemplateRef` | -- | 可选,附件信息,一般用于补充表单选项的说明 | [label 横向排列](demo#demo-label-horizontal) | -| feedbackStatus | [`DFormControlStatus`](#dformcontrolstatus) | -- | 可选,手动指定当前 control 状态反馈 | [指定表单状态](demo#demo-custom-status) | -| suffixTemplate | `TemplateRef` | -- | 可选,可传入图标模板作为输入框后缀 | - -# dFormSubmit - -- 在`
    `(需绑定 dForm)中指定触发`submit`的元素。 -- 可设置触发事件(默认为'click'),如`dFormSubmit="dblclick"`,设置元素双击时触发`submit`。 - -## dFormSubmit 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------------: | :------: | :-----: | :-------------------------------------------------------------------: | :-------------------------------------------: | -| dFormSubmit | `string` | 'click' | 可选,配置用于触发 submit 的事件名 | [响应式表单验证](demo#demo-validate-reactive) | -| dFormSubmitData | `any` | -- | 可选,配置需要传递与 dSubmit 回调事件数据,可用于需区分多个按钮的场景 | [响应式表单验证](demo#demo-validate-reactive) | - -# dFormReset - -- 在``(需绑定 dForm)中指定触发`reset`的元素。 -- 可设置触发事件(默认为'click'),如`dFormReset="dblclick"`,设置元素双击时触发`reset`。 - -## dFormReset 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------: | :------: | :-----: | :--------------------------------: | :-------: | -| dFormReset | `string` | 'click' | 可选,配置用于触发 submit 的事件名 | | - -# dValidateRules 表单验证 - -## 定位 - -- DevUI 表单验证基于[Angular Form](https://angular.io/guide/forms-overview),完全兼容响应式表单与模板驱动表单。旨在封装与简化表单校验逻辑,你只需配置简单规则,验证消息与验证状态管理全交由 DevUI Form 自动完成。 - -## 如何使用 - -- 当你使用了响应式表单或模板驱动表单(均需在你的模块中引入`Angular FormsModule`): - -```ts -import { FormsModule } from '@angular/forms'; -``` - -- 在你的元素上绑定`dValidateRules`并传入你需要配置的规则即可(_虽在模板中可直接使用字面量传入规则,但考虑了变更检测,我们推荐你在组件控制器中声明规则再绑定到模板中_)。如: - -```html - -``` - -## dValidateRules 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------: | :---------------------------------: | :--: | :--------------------: | :-----------------------------------------------------: | -| dValidateRules | [`DValidateRules`](#dvalidaterules) | -- | 必选,配置你的校验规则 | [模板驱动表单验证(推荐)](demo#demo-validate-template) | - -## dValidateSyncKey 参数 - -表单协同校验。 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------: | :------: | :--: | :-----------------------------------------------------------------------------------------------------------: | :-------------------------------------: | -| dValidateSyncKey | `string` | -- | 必选,配置唯一标识 key,相同 key 表单元素将在其中一个元素值发生变更时,同时触发校验,支持响应式与模板驱动表单 | [表单协同验证](demo#demo-validate-sync) | - -# 接口 & 类型定义 - -### DFormControlStatus - -```ts -export type DFormControlStatus = 'error' | 'pending' | 'success'; -``` - -### DFormControlRuleDirective - -DFormControlRuleDirective 为表单元素对应 dValidateRules 指令对象,以下为指令 Class 名与 selector: - -```ts -@Directive({ - selector: '[dValidateRules][formControlName],[dValidateRules][ngModel],[dValidateRules][formControl]', - exportAs: 'dValidateRules' -}) -``` - -### DFormGroupRuleDirective - -DFormGroupRuleDirective 为表单容器对应 dValidateRules 指令对象,以下为指令 Class 名与 selector: - -```ts -@Directive({ - selector: `[dValidateRules][formGroupName],[dValidateRules][formArrayName],[dValidateRules][ngModelGroup], - [dValidateRules][formGroup],[dValidateRules]form:not([ngNoForm]),[dValidateRules][ngForm]`, - exportAs: 'dValidateRules' -}) -``` - -### DValidateRules - -```ts -export type DValidateRules = - | { - validators?: DValidateRule[]; // 同步校验规则 - - asyncValidators?: DAsyncValidateRule[]; // 异步校验规则 - - asyncDebounceTime?: number; // 异步校验器debounceTime(单位ms),默认为300 - - errorStrategy?: DValidationErrorStrategy; // error更新策略,默认为'dirty' - - message?: string; // 统一配置的message,如果你的某一条校验规则未配置message,将取统一message - - messageShowType?: 'popover' | 'text' | 'none'; // 消息自动显示策略(当前仅单个表单组件下生效),(popover | d-form-item容器内部显示 | 不显示) - - // 消息显示为popover时,设置popover的内容弹出方向,默认为['right', 'bottom'] - popPosition?: 'top' | 'right' | 'bottom' | 'left' | ('top' | 'right' | 'bottom' | 'left')[]; - } - | DValidateRule[]; // 若只需设置同步校验规则,可传同步校验规则数组 -``` - -### DValidateRule - -```TS -export interface DValidateRule { // 定义同步校验规则 - - id ?: string; // 当前rule id,唯一标识当前规则,表单消息机制将以此作为key - - validator ?: DValidatorFn | ValidatorFn; // 校验器,兼容Angular原生校验器(需要设置isNgValidator为true) - - message ?: string; // 校验不通过时返回的提示消息 - - errorStrategy ?: DValidationErrorStrategy; // 当前规则的error更新策略,默认为'dirty' - - priority ?: number; // 当前规则优先级,同时校验不通过,优先级高的规则消息将优先显示,默认为0 - - isNgValidator ?: boolean; // 标识当前校验器是否为Angular原生校验器 - - // 这是一个万能的匹配key,你可使用默认提供的校验器key,或者快捷设置你的自定义rule key(不与默认key&保留字冲突即被识别为你当前id) - [id: string]: boolean | number | string | RegExp | DValidatorFn | ValidatorFn; -} -``` - -### DAsyncValidateRule - -```TS -export interface DAsyncValidateRule { // 定义异步校验规则 - id ?: string; - validator ?: DAsyncValidatorFn | AsyncValidatorFn; - message ?: string; - errorStrategy ?: DValidationErrorStrategy; - priority ?: number; - isNgValidator ?: boolean; - [id: string]: boolean | number | string | RegExp | DAsyncValidatorFn | AsyncValidatorFn; -``` - -### DValidationErrorStrategy - -- pristine:有校验规则不通过即抛出错误 message,dirty:校验规则不通过且状态为 dirty 时抛出错误 message - -```TS -export type DValidationErrorStrategy = 'pristine' | 'dirty'; -``` - -### DValidatorFn - -- 定义 DevUI Form 同步校验器:返回 boolean 值则表示当前规则是否通过 -- 若返回 string|null,null 表示通过,若当前 rule 未设置 message,则返回的 string 将作为当前 rule message - -```TS -export type DValidatorFn = (value: any) => boolean | string | null; -``` - -### DAsyncValidatorFn - -- 定义 DevUI Form 异步校验器:与同步规则类似,不同为需要你的函数需要返回一个 Observable 对象 - -```TS -export type DAsyncValidatorFn = (value: any) => Observable; -``` - -### ruleReservedWords - -- 定义 DevUI Rule 规则的保留字,如果你的 key 不为保留字,则可作为你当前 rule id 使用(默认校验器 id 或自定义校验器 id) - -```TS -export const ruleReservedWords = ['id', 'validator', 'message', 'errorStrategy', 'priority', 'isNgValidator', 'popPosition', 'asyncDebounceTime']; -``` - -### dDefaultValidators - -```TS -export const dDefaultValidators = { - 'required': Validators.required, // 配置不能为空限制,rule中使用:{ required: true } - 'minlength': Validators.minlength, // 配置最小长度限制,rule中使用:{ minlength: 5 } - 'maxlength': Validators.maxlength, // 配置最大长度限制,rule中使用:{ maxlength: 128 } - 'min': Validators.min, // 配置最小值限制,rule中使用:{ min: 0 } - 'max': Validators.max, // 配置最大值限制,rule中使用:{ max: 100 } - 'requiredTrue': Validators.requiredTrue, // 配置需要为true,rule中使用:{ requiredTrue: true } - 'email': Validators.email, // 配置邮箱校验,rule中使用:{ email: true } - 'pattern': Validators.pattern, // 配置正则校验,rule中使用:{ pattern: RegExp } - 'whitespace': DValidators.whiteSpace, // 配置输入不能全为空格限制,rule中使用:{ whitespace: true } -}; -``` diff --git a/devui/form/doc/api-en.md b/devui/form/doc/api-en.md deleted file mode 100644 index b428206135af1ba6d7b2edc684d1016be3e82541..0000000000000000000000000000000000000000 --- a/devui/form/doc/api-en.md +++ /dev/null @@ -1,283 +0,0 @@ -# How to use - -Import into module - -```ts -import { FormModule } from 'ng-devui/form'; -``` - -If you need to use the NgForm, introduce the following - -```ts -import { Forms } from '@angular/forms'; -``` - -In the page - -```html - - - ... - - - - - - - - ... - - - - - - - - - - - - - - - -``` - -# dForm - -## dForm Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :-----------------------------------: | :----------: | :----------------------------------------------------------------------- | ------------------------------------------------------------- | -| layout | `'horizontal'\|'vertical'\|'columns'` | 'horizontal' | Optional. Sets the form arrangement mode. | [Basic usage](demo#basic-usage) | -| labelSize | `'sm' \| '' \| 'lg'` | '' | Optional. Sets the width of the label. If this parameter is not set, the default value is 100 px. 'sm' corresponds to 80 px, 'lg' corresponds to 150px | [Label horizontal arrangement](demo#demo-label-horizontal) | -| labelAlign | `'start'\|'center'\|'end'` | 'start' | Optional. This parameter specifies the label alignment mode in horizontal layout mode. | [label horizontal arrangement](demo#demo-label-horizontal) | - -## dForm Event - -| Parameter | Type | Description | Jump to Demo | -| :-------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| dSubmit | `EventEmitter<{valid: boolean, directive: `[`DFormGroupRuleDirective`](#dformgroupruledirective) `\| AbstractControlDirective}>` | Optional. This event is responded to when the dFormSubmit binding element is used to trigger submission. | [Template-driven form verification (recommended)](demo#demo-validate-template) | - -# d-form-item - -## d-form-item parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-------: | :-----: | :-------------------------------------------------------------------------------- | ------------------------------------------------------- | -| dHasFeedback | `boolean` | false | Optional. Sets whether to display the feedback icon for the current form control. | [Reactive form validation](demo#demo-validate-reactive) | - -# d-form-label - -## d-form-label parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :-------: | :-----: | :--------------------------------------------------------- | ------------------------------- | -| required | `boolean` | false | Optional. Indicating whether the form option is mandatory. | [Basic usage](demo#basic-usage) | -| hasHelp | `boolean` | false | Optional. Indicating whether a form item requires help. | [Basic usage](demo#basic-usage) | -| helpTips | `string` | '' | Optional. This parameter is used together with `hasHelp`. | [Basic usage](demo#basic-usage) | - -# d-form-control - -## d-form-control parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------: | :-----------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -| extraInfo | `string \| TemplateRef` | -- | Optional. attachment information, which is used to supplement the description of table options. | [Label horizontal arrangement](demo#demo-label-horizontal) | -| feedbackStatus | [`DFormControlStatus`](#dformcontrolstatus) | -- | Optional. Manually specify the current control status. | [Specify form status](demo#demo-custom-status) | -| suffixTemplate | `TemplateRef` | -- | Optional. Pass icon template to be the suffix of Input. | - -# dFormSubmit - -- Specify the element that triggers the `submit` in `
    ` (the dForm needs to be bound). -- You can set the trigger event (click by default), for example, `dFormSubmit="dblclick"`, to trigger `submit` when an element is double-clicked. - -## dFormSubmit Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------: | :------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------: | -| dFormSubmit | `string` | 'click' | Optional. Configure the event name used to trigger submit. | [Reactive form validation](demo#demo-validate-reactive) | -| dFormSubmitData | `any` | -- | Optional. Configure the data that needs to be transferred and the dSubmit callback event, which can be used to distinguish multiple buttons. | [Reactive form validation](demo#demo-validate-reactive) | - -# dFormReset - -- Specify the element that triggers the `reset` in `` (the dForm needs to be bound). -- You can set the trigger event (click by default), for example, `dFormReset="dblclick"`, to trigger `reset` when an element is double-clicked. - -## dFormReset Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------: | :------: | :-----: | :-------------------------------------------------------: | :----------: | -| dFormReset | `string` | 'click' | Optional. Configure the event name for triggering submit. | | - -# dValidateRules Form Validation - -## Locating - -- DevUI form verification is based on [Angular Form](https://angular.io/guide/forms-overview) and is fully compatible with responsive forms and template-driven forms. To encapsulate and simplify form validation logic, you only need to configure simple rules. Verification messages and verification status management are automatically completed by DevUI Form. - -## How to use - -- When you use a responsive form or a template-driven form (both include `Angular FormsModule` in your module): - -```ts -import { Forms } from '@angular/forms'; -``` - -- Bind `dValidateRules` to your element and pass in the rules to be configured. (\*Although you can directly use literals to pass in the template, considering change detection, it is recommended that you declare the rules in the component controller and then bind them to the template.) - -```html - -``` - -## dValidateRules Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------: | :---------------------------------: | :-----: | :----------------------------------------: | :----------------------------------------------------------------------------: | -| dValidateRules | [`DValidateRules`](#dvalidaterules) | -- | Required. Configure the verification rule. | [Template-driven form verification (recommended)](demo#demo-validate-template) | - -## dValidateSyncKey Parameter - -Collaborative form validation. - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------: | :------: | :-----: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------: | -| dValidateSyncKey | `string` | -- | Required. This parameter is mandatory. It specifies the unique key. When the value of one element in the form of the same key changes, verification is triggered. responsive and template-driven forms are supported. | [Form collaboration verification](demo#demo-validate-sync) | - -# Interface & Type Definition - -### DFormControlStatus - -```ts -export type DFormControlStatus = 'error' | 'pending' | 'success'; -``` - -### DFormControlRuleDirective - -DFormControlRuleDirective is the dValidateRules instruction object corresponding to the form element. The class name and selector of the instruction are as follows: - -```ts -@Directive({ -selector:' [dValidateRules][formControlName],[dValidateRules][ngModel],[dValidateRules][formControl]', -exportAs: 'dValidateRules' -}) -``` - -### DFormGroupRuleDirective - -DFormGroupRuleDirective is the dValidateRules instruction object corresponding to the form container. The class name and selector of the instruction are as follows: - -```ts -@Directive({ -selector: `[dValidateRules][formGroupName],[dValidateRules][formArrayName],[dValidateRules][ngModelGroup], -[dValidateRules][formGroup],[dValidateRules]form:not([ngNoForm]),[dValidateRules][ngForm]`, -exportAs: 'dValidateRules' -}) -``` - -### DValidateRules - -```ts -export type DValidateRules = - | { - validators?: DValidateRule[]; // Synchronize verification rules. - - asyncValidators?: DAsyncValidateRule[]; // Asynchronous Verification Rule - - asyncDebounceTime?: number; // Asynchronous validator debounceTime (unit: ms). The default value is 300. - - errorStrategy?: DValidationErrorStrategy; // error update policy. The default value is'dirty'. - - message?: string; // Unified message. If no message is configured for a verification rule, the unified message is used. - - messageShowType?: 'popover' | 'text' | 'none'; // Automatic message display policy (currently, this policy takes effect only for a single form component). (displayed in the popover | d-form-item container | not displayed) - - // When the message is displayed as popover, set the popover content pop-up direction. The default value is ['right','bottom']. - popPosition?: 'top' | 'right' | 'bottom' | 'left' | ('top' | 'right' | 'bottom' | 'left')[]; - } - | DValidateRule[]; // If only the synchronization verification rule needs to be set, the synchronization verification rule array can be transferred. -``` - -### DValidateRule - -```TS -export interface DValidateRule {// Define a synchronization verification rule. - -id ? : string; // Current rule ID, which uniquely identifies the current rule. The form message mechanism uses this ID as the key. - -validator ?: DValidatorFn | ValidatorFn; // validator, which is compatible with the native Angular validator. (Set isNgValidator to true.) - -message ? : string; // Message returned when the verification fails. - -errorStrategy ?: DValidationErrorStrategy; // Error update policy of the current rule. The default value is'dirty'. - -priority ? : number; // Priority of the current rule. If the verification fails, the rule with a higher priority is displayed first. The default value is 0. - -isNgValidator ?: boolean; //: indicates whether the current validator is an Angular native validator. - -// This is an all-purpose matching key. You can use the default validator key or quickly set your customized rule key. (If the key does not conflict with the default key or reserved word, the system identifies the current ID.) -[id: string]: boolean | number | string | RegExp | DValidatorFn | ValidatorFn; -} -``` - -### DAsyncValidateRule - -```TS -export interface DAsyncValidateRule {// Define an asynchronous verification rule. -id ? : string; -validator ?: DAsyncValidatorFn | AsyncValidatorFn; -message ? : string; -errorStrategy ?: DValidationErrorStrategy; -priority ? : number; -isNgValidator ? : boolean; -[id: string]: boolean | number | string | RegExp | DAsyncValidatorFn | AsyncValidatorFn; -``` - -### DValidationErrorStrategy - -- primine: throws an error message when a verification rule fails.dirty: throws an error message when the verification rule fails and the status is dirty. - -```TS -export type DValidationErrorStrategy = 'pristine' | 'dirty'; -``` - -### DValidatorFn - -- Define the DevUI Form synchronization validator: If the boolean value is returned, the current rule passes. -- If string|null is returned, null indicates that the check is passed. If no message is set for the current rule, the returned string is used as the current rule message. - -```TS -export type DValidatorFn = (value: any) => boolean | string | null; -``` - -### DAsyncValidatorFn - -- Define DevUI Form asynchronous validator: Similar to the synchronous rule, the difference is that your function needs to return an Observable object. - -```TS -export type DAsyncValidatorFn = (value: any) => Observable; -``` - -### ruleReservedWords - -- Define the reserved word of the DevUI rule. If your key is not a reserved word, it can be used as the current rule ID (default validator ID or customized validator ID). - -```TS -export const ruleReservedWords = ['id','validator','message','errorStrategy','priority','isNgValidator','popPosition', 'asyncDebounceTime']; -``` - -### dDefaultValidators - -```TS -export const dDefaultValidators = { -'required': Validators.required, // The configuration cannot be empty. The following is used in the rule: {required: true} -'minlength': Validators.minlength, // Indicates the minimum length. The value {minlength: 5} is used in the rule. -'maxlength': Validators.maxlength, // Configure the maximum length. {maxlength: 128} is used in the rule. -'min': Validators.min, // Minimum value. {min: 0} is used in the rule. -'max': Validators.max, // Indicates the maximum value. {max: 100} is used in the rule. -'requiredTrue': Validators.requiredTrue, // The value must be true. The value {requiredTrue: true} is used in the rule. -'email': Validators.email, // Configure email verification. Use {email: true} in the rule. -'pattern': Validators.pattern, // Configure regular expression verification. The rule uses {pattern: RegExp}. -'whitespace': DValidators.whiteSpace, // Indicates that the input cannot contain only spaces. The rule uses {whitespace: true}. -}; -``` diff --git a/devui/form/form.tsx b/devui/form/form.tsx deleted file mode 100644 index a459189715636652777a5ec762a77f704b9e6aae..0000000000000000000000000000000000000000 --- a/devui/form/form.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-form', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-form
    - } - } -}) \ No newline at end of file diff --git a/devui/fullscreen/demo/fullscreen-demo.tsx b/devui/fullscreen/demo/fullscreen-demo.tsx deleted file mode 100644 index 7c090c9844c1999000e93ee08452819fb159d1f4..0000000000000000000000000000000000000000 --- a/devui/fullscreen/demo/fullscreen-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-fullscreen-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-fullscreen-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/fullscreen/demo/fullscreen.route.ts b/devui/fullscreen/demo/fullscreen.route.ts deleted file mode 100644 index 532ff0d9f91b0f901461b274948439d8f79fb407..0000000000000000000000000000000000000000 --- a/devui/fullscreen/demo/fullscreen.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import FullscreenDemoComponent from './fullscreen-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: FullscreenDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/fullscreen/doc/api-cn.md b/devui/fullscreen/doc/api-cn.md deleted file mode 100644 index 12b52833b0f30f7a8fe6e06b24e1f84aa264af48..0000000000000000000000000000000000000000 --- a/devui/fullscreen/doc/api-cn.md +++ /dev/null @@ -1,40 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { FullscreenModule } from 'ng-devui/fullscreen'; -``` - -在页面中使用: - -```html - -
    -
    -
    -
    -``` - -# d-fullscreen - -## d-fullscreen 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----: | :-----------------------: | :---------: | :----------------: | ------------------------------------ | -| mode | `'immersive' \| 'normal'` | 'immersive' | 可选,设置全屏模式 | [普通全屏](demo#general-full-screen) | -| zIndex | `number` | 10 | 可选,设置全屏层级 | [普通全屏](demo#general-full-screen) | - -## d-fullscreen 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :--------------: | :---------------------: | :------------------- | ---------------------------------------- | -| fullscreenLaunch | `EventEmitter` | 可选,全屏之后的回调 | [沉浸式全屏](demo#immersive-full-screen) | - -### fullscreen-target 选择器 - -必含指令,内容投影,设置需要全屏的元素[沉浸式全屏](demo#immersive-full-screen)。 - -### fullscreen-launch 选择器 - -必含指令,内容投影,设置触发进入全屏的按钮[沉浸式全屏](demo#immersive-full-screen)。 diff --git a/devui/fullscreen/doc/api-en.md b/devui/fullscreen/doc/api-en.md deleted file mode 100644 index 3b5fb095e0291ccaf8550e78ce2d851afeec9525..0000000000000000000000000000000000000000 --- a/devui/fullscreen/doc/api-en.md +++ /dev/null @@ -1,36 +0,0 @@ -# How To Use -Import in module: -```ts -import { FullscreenModule } from 'ng-devui/fullscreen'; -``` -In the page: -```html - -
    -
    -
    -
    -``` - -# d-fullscreen - -## d-fullscreen parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :-----------------------: | :---------: | :------------------------------------: | --------------------------------------------------------- | -| fullscreen-target | `HTMLElement` | -- | Required. Content projection, set the elements to be displayed in full screen. | [Immersive full screen](demo#immersive-full-screen) | -| fullscreen-launch | `HTMLElement` | -- | Required. Content projection, set the button to trigger the full screen. | [Immersive full screen](demo#immersive-full-screen) | -| mode | `'immersive' \|'normal'` | 'immersive' | Optional. Set the full-screen mode. | [Common full screen](demo#general-full-screen) | -| zIndex | `number` | 10 | Optional. Set the full-screen level. | [Common full screen](demo#general-full-screen) | - -## d-fullscreen event - -| Event | Type | Description | Jump to Demo | -| :--------------: | :---------------------: | :------------------- | --------------------------------------------------------- | -| fullscreenLaunch | `EventEmitter` | Optional. Callback after full screen | [Immersive full screen](demo#immersive-full-screen) | - -### fullscreen-target directive -Required directive. Content projection, set the elements to be displayed in full screen.[Immersive full screen](demo#immersive-full-screen) - -### fullscreen-launch directive -Required directive. Content projection, set the button to trigger the full screen.[Immersive full screen](demo#immersive-full-screen) diff --git a/devui/fullscreen/fullscreen.tsx b/devui/fullscreen/fullscreen.tsx deleted file mode 100644 index adaee5f0cb5ebbc2ae7e2c5aab0d4ead9dcbe8b3..0000000000000000000000000000000000000000 --- a/devui/fullscreen/fullscreen.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-fullscreen', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-fullscreen
    - } - } -}) \ No newline at end of file diff --git a/devui/gantt/demo/gantt-demo.tsx b/devui/gantt/demo/gantt-demo.tsx deleted file mode 100644 index ce024b338fc738d033764a605a04d91ec0a56637..0000000000000000000000000000000000000000 --- a/devui/gantt/demo/gantt-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-gantt-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-gantt-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/gantt/demo/gantt.route.ts b/devui/gantt/demo/gantt.route.ts deleted file mode 100644 index cb60daccea176eb650272d8ca3589e1184938470..0000000000000000000000000000000000000000 --- a/devui/gantt/demo/gantt.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import GanttDemoComponent from './gantt-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: GanttDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/gantt/doc/api-cn.md b/devui/gantt/doc/api-cn.md deleted file mode 100644 index 12440547959e72165c0463e95a5799dc2c787528..0000000000000000000000000000000000000000 --- a/devui/gantt/doc/api-cn.md +++ /dev/null @@ -1,98 +0,0 @@ -## 引入 - -当前组件为实验性组件,需要按需引入,路径如下: - -``` -import { GanttModule } from 'ng-devui/experimental/gantt'; -``` - -### d-gantt-scale 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------------------: | :----------------: | :---: | :----------------------------------------- | -------------------------------------------------------------------------- | -| milestoneList | `GanttMilestone[]` | [] | 可选,版本里程碑列表 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| ganttScaleContainerOffsetLeft | `number` | 0 | 可选,甘特图时间轴容器左偏移像素 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| ganttBarContainerElement | `Element` | null | 必选,甘特图时间条容器,用于显示甘特图标线 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - -### d-gantt-bar 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | 必选,开始时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| endDate | `Date` | null | 必选,结束时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| id | `string` | null | 可选,支持传入 id | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| data | `object` | null | 可选,支持传入任意数据 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| progressRate | `number` | 0 | 可选,进度,例如 30 代表 30%进度 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| tipTemplateRef | `TemplateRef` | null | 可选,自定义提示内容模板 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barMoveDisabled | `boolean` | false | 可选,是否禁止 bar 拖动 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barResizeDisabled | `boolean` | false | 可选,是否禁止 bar 调整起止时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| progressDisabled | `boolean` | false | 可选,是否禁止 bar 调整进度 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - -### d-gantt-bar 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :-----------------: | :---------------------------: | :--------------------------: | -------------------------------------------------------------------------- | -| barMoveStartEvent | `EventEmitter` | 工作项时间条开始拖动事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barMovingEvent | `EventEmitter` | 工作项时间条拖动中事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barMoveEndEvent | `EventEmitter` | 工作项时间条拖动完成事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barResizeStartEvent | `EventEmitter` | 工作项时间条宽度开始调整事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barResizingEvent | `EventEmitter` | 工作项时间条宽度调整中事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barResizeEndEvent | `EventEmitter` | 工作项时间条宽度调整完成事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| barProgressEvent | `EventEmitter` | 工作项进度调整事件 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - - -### d-gantt-milestone 参数 -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | 必选,开始时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| id | `string` | null | 可选,支持传入 id | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| title | `string` | null | 可选,支持传入 title,用于里程碑类型的标题 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - - -### d-gantt-bar-parent 参数 -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | 必选,开始时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| endDate | `Date` | null | 必选,结束时间 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| id | `string` | null | 可选,支持传入 id | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| data | `object` | null | 可选,支持传入任意数据 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| progressRate | `number` | 0 | 可选,进度,例如 30 代表 30%进度 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - -### GanttService 公共方法 - -| 方法 | 参数 | 返回值类型 | 描述 | 跳转 Demo | -| :------------------: | :------------------------------: | :--------: | :----------------------------: | -------------------------------------------------------------------------- | -| setScaleConfig | `GanttScaleConfig` | void | 配置时间轴 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| getDurationWidth | `startDate: Date, endDate: Date` | number | 获取起止时间在时间轴上的宽度 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | -| getDatePostionOffset | `date: Date` | number | 获取时间点在时间轴上的左偏移量 | [与datatable组件结合的甘特图](demo#gantt-with-datatable) | - -#### 甘特图类型定义 - -```javascript -export interface GanttMilestone { - date: Date; - lable: string; -} - -export interface GanttTaskInfo { - id: string; - startDate: Date; - endDate: Date; - title?: string; - progress: string; // 当前进度 - duration: string; // 持续时间 - moveOffset?: number; // 拖动距离 -} - -export interface GanttScaleConfig { - startDate?: Date; - endDate?: Date; - unit?: GanttScaleUnit; -} - -export enum GanttScaleUnit { - day = 'day', - week = 'week', - month = 'month' -} -``` diff --git a/devui/gantt/doc/api-en.md b/devui/gantt/doc/api-en.md deleted file mode 100644 index 76c8c9c3dea92b45d03c8c344be36e780f35cc48..0000000000000000000000000000000000000000 --- a/devui/gantt/doc/api-en.md +++ /dev/null @@ -1,97 +0,0 @@ -## Import - -The current component is an experimental component and needs to be introduced as required. The path is as follows: - -``` -import {GanttModule} from' ng-devui/experimental/gantt'; -``` - -### d-gantt-scale parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------------------: | :----------------: | :---: | :----------------------------------------- | -------------------------------------------------------------------------- | -| milestoneList | `GanttMilestone[]` | [] | Optional. Version milestone list | [Combined With Datatable](demo#gantt-with-datatable) | -| ganttScaleContainerOffsetLeft | `number` | 0 | Optional. Left offset pixel of the Gantt chart time axis container | [Combined With Datatable](demo#gantt-with-datatable) | -| ganttBarContainerElement | `Element` | null | Time bar container of the Gantt chart, which is mandatory. It is used to display the Gantt chart lines. | [Combined With Datatable](demo#gantt-with-datatable) | - -### d-gantt-bar parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | Required. Start time | [Combined With Datatable](demo#gantt-with-datatable) | -| endDate | `Date` | null | Required. End time | [Combined With Datatable](demo#gantt-with-datatable) | -| id | `string` | null | Optional. id is supported | [Combined With Datatable](demo#gantt-with-datatable) | -| data | `object` | null | Optional. Any data can be transferred. | [Combined With Datatable](demo#gantt-with-datatable) | -| progressRate | `number` | 0 | Optional. Progress. For example, 30 indicates 30% progress. | [Combined With Datatable](demo#gantt-with-datatable) | -| tipTemplateRef | `TemplateRef` | null | Optional. Customized prompt content template | [Combined With Datatable](demo#gantt-with-datatable) | -| barMoveDisabled | `boolean` | false | Optional. Whether bar dragging is forbidden | [Combined With Datatable](demo#gantt-with-datatable) | -| barResizeDisabled | `boolean` | false | Optional. Whether to forbid bar adjustment of the start time and end time. | [Combined With Datatable](demo#gantt-with-datatable) | -| progressDisabled | `boolean` | false | Optional. Whether to disable bar adjustment progress | [Combined With Datatable](demo#gantt-with-datatable) | - -### d-gantt-bar event - -| Event | Type | Description | Jump to Demo | -| :-----------------: | :---------------------------: | :--------------------------: | -------------------------------------------------------------------------- | -| barMoveStartEvent | `EventEmitter` | Work Item Time Bar Start Drag Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barMovingEvent | `EventEmitter` | Work Item Time Bar Dragging Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barMoveEndEvent | `EventEmitter` | Work Item Time Bar Drag Completion Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barResizeStartEvent | `EventEmitter` | Work Item Time Bar Width Adjustment Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barResizingEvent | `EventEmitter` | Work Item Time Bar Width Adjustment Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barResizeEndEvent | `EventEmitter` | Work Item Time Bar Width Adjustment Completion Event | [Combined With Datatable](demo#gantt-with-datatable) | -| barProgressEvent | `EventEmitter` | Work Item Progress Adjustment Event | [Combined With Datatable](demo#gantt-with-datatable) | - -### d-gantt-milestone parameter -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | Required. Start time | [Combined With Datatable](demo#gantt-with-datatable) | -| id | `string` | null | Optional. Id is supported | [Combined With Datatable](demo#gantt-with-datatable) | -| title | `string` | null | Optional. The title can be transferred, which is used as the title of the milestone type | [Combined With Datatable](demo#gantt-with-datatable) | - - -### d-gantt-bar-parent parameter -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :----------------: | :--------: | :---------------------------------------------------------------- | -------------------------------------------------------------------------- | -| startDate | `Date` | null | Required. Start time | [Combined With Datatable](demo#gantt-with-datatable) | -| endDate | `Date` | null | Required. End time | [Combined With Datatable](demo#gantt-with-datatable) | -| id | `string` | null | Optional. Id is supported | [Combined With Datatable](demo#gantt-with-datatable) | -| data | `object` | null | Optional. Any data can be transferred | [Combined With Datatable](demo#gantt-with-datatable) | -| progressRate | `number` | 0 | Optional. Progress. For example, 30 indicates 30% progress | [Combined With Datatable](demo#gantt-with-datatable) | - -### GanttService Public Methods - -| Method | Parameter | Return value type | Description | Jump to Demo | -| :------------------: | :------------------------------: | :--------: | :----------------------------: | -------------------------------------------------------------------------- | -| setScaleConfig | `GanttScaleConfig` | void | Configuring the Timeline | [Combined With Datatable](demo#gantt-with-datatable) | -| getDurationWidth | `startDate: Date, endDate: Date` | number | Obtains the width of the start time and end time on the time axis. | [Combined With Datatable](demo#gantt-with-datatable) | -| getDatePostionOffset | `date: Date` | number | Obtaining the Left Offset of a Time Point on the Timeline | [Combined With Datatable](demo#gantt-with-datatable) | - -#### Gantt Chart Type Definition - -```javascript -export interface GanttMilestone { - date: Date; - lable: string; -} - -export interface GanttTaskInfo { - id: string; - startDate: Date; - endDate: Date; - title? : string; - progress: string; // Current progress - duration: string; // Duration - moveOffset? : number; // Drag the distance. -} - -export interface GanttScaleConfig { - startDate? : Date; - endDate? : Date; - unit? : GanttScaleUnit; -} - -export enum GanttScaleUnit { - day = 'day', - week = 'week', - month ='month' -} -``` diff --git a/devui/gantt/gantt.tsx b/devui/gantt/gantt.tsx deleted file mode 100644 index 7b95785cb1853f165043a2fd194775d50553771b..0000000000000000000000000000000000000000 --- a/devui/gantt/gantt.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-gantt', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-gantt
    - } - } -}) \ No newline at end of file diff --git a/devui/image-preview/demo/image-preview-demo.tsx b/devui/image-preview/demo/image-preview-demo.tsx deleted file mode 100644 index 3ef4fe827a2671bdc58eac23a859f67e4b0fd84b..0000000000000000000000000000000000000000 --- a/devui/image-preview/demo/image-preview-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-image-preview-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-image-preview-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/image-preview/demo/image-preview.route.ts b/devui/image-preview/demo/image-preview.route.ts deleted file mode 100644 index 144b24405f5b08f7a14fa40e3fcae87f6dedb2e7..0000000000000000000000000000000000000000 --- a/devui/image-preview/demo/image-preview.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ImagePreviewDemoComponent from './image-preview-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ImagePreviewDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/image-preview/doc/README.md b/devui/image-preview/doc/README.md deleted file mode 100644 index 1b6a404f58f7b7404b37bbdfa39c190aa5d485c4..0000000000000000000000000000000000000000 --- a/devui/image-preview/doc/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# 功能点 -## 第一版本 提供指令 -1. 可进行图片预览、变换、切换 - diff --git a/devui/image-preview/doc/api-cn.md b/devui/image-preview/doc/api-cn.md deleted file mode 100644 index 64d1342f04ce4c6dbc94e3f3fc169c8e45e044f2..0000000000000000000000000000000000000000 --- a/devui/image-preview/doc/api-cn.md +++ /dev/null @@ -1,20 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { ImagePreviewModule } from 'ng-devui/image-preview'; -``` -在页面中使用: -```html -
    -``` - -# dImagePreview - -## dImagePreview 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------: | :--------------------: | :---: | :------------------------------------: | ------------------------------------------------- | -| customSub | `Subject` | -- | 可选,customsub 触发 next 时,打开预览 | [自定义开启预览窗口](demo#custom-usage) | -| disableDefault | `boolean` | false | 可选,关闭默认点击触发图片预览方式 | [自定义开启预览窗口](demo#custom-usage) | -| zIndex | `number` | 1050 | 可选,设置预览时图片的z-index值 | [设置zIndex](demo#z-index-usage) | -| backDropZIndex | `number` | 1040 | 可选,设置预览时图片背景的z-index值 | [设置zIndex](demo#z-index-usage) | diff --git a/devui/image-preview/doc/api-en.md b/devui/image-preview/doc/api-en.md deleted file mode 100644 index bc15479b41dda7849cf9808bd19c00c294f96923..0000000000000000000000000000000000000000 --- a/devui/image-preview/doc/api-en.md +++ /dev/null @@ -1,20 +0,0 @@ -# How To Use -Import in module: -```ts -import { ImagePreviewModule } from 'ng-devui/image-preview'; -``` -In the page: -```html -
    -``` - -# dImagePreview - -## dImagePreview Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------: | :--------------------: | :---: | :------------------------------------: | ------------------------------------------------- | -| customSub | `Subject` | -- | Optional. When customsub triggers next, preview is opened. | [Customized preview window opening](demo#custom-usage) | -| disableDefault | `boolean` | false | Optional. Disable the default image preview mode triggered by clicking. | [Customized preview window enabling](demo#custom-usage) | -| zIndex | `number` | 1050 | Optional. Sets the z-index value of the image during preview. | [Setting zIndex](demo#z-index-usage) | -| backDropZIndex | `number` | 1040 | Optional. Sets the z-index value of the back drop of the image during preview. | [Setting zIndex](demo#z-index-usage) | diff --git a/devui/image-preview/image-preview.tsx b/devui/image-preview/image-preview.tsx deleted file mode 100644 index 5478f3614e2a6e505a5939cd7c2d1149d419565f..0000000000000000000000000000000000000000 --- a/devui/image-preview/image-preview.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-image-preview', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-image-preview
    - } - } -}) \ No newline at end of file diff --git a/devui/input-number/demo/input-number-demo.tsx b/devui/input-number/demo/input-number-demo.tsx deleted file mode 100644 index ce77296db7e6c2f1f36faffdbb40b7b636b22700..0000000000000000000000000000000000000000 --- a/devui/input-number/demo/input-number-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-input-number-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-input-number-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/input-number/demo/input-number.route.ts b/devui/input-number/demo/input-number.route.ts deleted file mode 100644 index ab9b0d7f6b7e294bf34607f71735580776cda4fd..0000000000000000000000000000000000000000 --- a/devui/input-number/demo/input-number.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import InputNumberDemoComponent from './input-number-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: InputNumberDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/input-number/doc/api-cn.md b/devui/input-number/doc/api-cn.md deleted file mode 100644 index d0c9921744d3555b456819968c36b303644c8844..0000000000000000000000000000000000000000 --- a/devui/input-number/doc/api-cn.md +++ /dev/null @@ -1,36 +0,0 @@ -# 如何使用 - -在module中引入: -```ts -import { InputNumberModule } from 'ng-devui'; -``` - -在页面中使用: -```html - -``` - -# d-input-number -## d-input-number 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :----------------: | :---------------------: | :----------------------------------- | -------------------------------------------------------------------------------------- | -| max | `number` | Number.MAX_SAFE_INTEGER | 可选,最大值 | [基本用法](demo#number-basic) | -| min | `number` | Number.MIN_SAFE_INTEGER | 可选,最小值 | [基本用法](demo#number-basic) | -| step | `number` | 1 | 可选,步进值 | [基本用法](demo#number-basic) | -| disabled | `boolean` | false | 可选,禁止输入态开关 | [禁止输入态](demo#number-disabled) | -| size | `'' \| 'sm' \| 'lg'` | '' | 可选,组件大小 | [基本用法](demo#number-basic) | -| ngModel | `number` | -- | 可选,组件的值 | [基本用法](demo#number-basic) | -| decimalLimit | `number` | -- | 可选,限制小数点后的位数 | [限制小数](demo#decimal-limit) | -| autoFocus | `boolean` | false | 可选,自动获取焦点 | -- | -| allowEmpty | `boolean` | false | 可选,是否允许值为空 | [允许空值](demo#number-empty) | -| placeholder | `string` | -- | 可选,要显示的 placeholder | [placeholder 和 maxLength](demo#number-placeholder-maxlength) | -| maxLength | `number` | 0 | 可选,限制最大输入的长度,0 为不限制 | [placeholder 和 maxLength](demo#number-placeholder-maxlength) | -| reg | `RegExp \| string` | -- | 可选,用于限制输入的正则或正则字符串 | [正则限制](demo#number-reg) | - -## d-input-number 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----------------: | :--------------------: | :-------------------------------------------------------- | ------------------------------------------------------ | -| whileValueChanging | `EventEmitter` | 用户使用键盘输入时发出的事件 | [基本用法](demo#number-basic) | -| afterValueChanged | `EventEmitter` | 组件值变化时发出的事件,使用 ngModelChange 来监听值的变化 | [基本用法](demo#number-basic) | diff --git a/devui/input-number/doc/api-en.md b/devui/input-number/doc/api-en.md deleted file mode 100644 index 5966bd51eda9012229fccec6ff5421f9d3c0c3fd..0000000000000000000000000000000000000000 --- a/devui/input-number/doc/api-en.md +++ /dev/null @@ -1,35 +0,0 @@ -# How to use - -Import into module: -```ts -import { InputNumberModule } from 'ng-devui'; -``` - -In the page: -```html - -``` -# d-input-number -## d-input-number Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :----------------: | :---------------------: | :------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | -| max | `number` | Number.MAX_SAFE_INTEGER | Optional. Maximum value | [Basic Usage](demo#number-basic) | -| min | `number` | Number.MIN_SAFE_INTEGER | Optional. Minimum value | [Basic Usage](demo#number-basic) | -| step | `number` | 1 | Optional. Step value | [Basic Usage](demo#number-basic) | -| disabled | `boolean` | false | Optional. This parameter specifies whether to enable the input function. | [Disabled](demo#number-disabled) | -| size | `'' \| 'sm' \| 'lg'` | '' | Optional. Component size | [Basic Usage](demo#number-basic) | -| ngModel | `number` | -- | Optional. Component value | [Basic Usage](demo#number-basic) | -| decimalLimit | `number` | -- | Optional. Limit the number of decimal places. | [Avoid Decimal](demo#decimal-limit) | -| autoFocus | `boolean` | false | Optional. Automatically obtain focus | -- | -| allowEmpty | `boolean` | false | Optional. Whether to allow the value to be empty | [Allow Null](demo#number-empty) | -| placeholder | `string` | -- | Optional. Placeholder to be displayed. | [Set Placeholder and Maxlength](demo#number-placeholder-maxlength) | -| maxLength | `number` | 0 | Optional. Limit the maximum length. The value 0 indicates no limit. | [Set Placeholder and Maxlength](demo#number-placeholder-maxlength) | -| reg | `RegExp \| string` | -- | Optional. It is used to restrict the input regular or regular character string. | [Using Regular Expression](demo#number-reg) | - -## d-input-number Event - -| Event | Type | Description | Jump to Demo | -| :------------------------------: | :--------------------: | :----------------------------------------------------------------- | --------------------------------------------------------------------- | -| whileValueChanging | `EventEmitter` | Event triggered when a user uses the keyboard to enter information | [Basic Usage](demo#number-basic) | -| afterValueChanged | `EventEmitter` | Component changed. The value change is monitored using ngModelChange. | [Basic Usage](demo#number-basic) | diff --git a/devui/input-number/input-number.tsx b/devui/input-number/input-number.tsx deleted file mode 100644 index 369b99244aff64b8b5838b2ffc47c8a68c988154..0000000000000000000000000000000000000000 --- a/devui/input-number/input-number.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-input-number', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-input-number
    - } - } -}) \ No newline at end of file diff --git a/devui/layout/demo/layout-demo.tsx b/devui/layout/demo/layout-demo.tsx deleted file mode 100644 index 56d8edb335d50d248ed34a647367a0b2dedf21e8..0000000000000000000000000000000000000000 --- a/devui/layout/demo/layout-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-layout-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-layout-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/layout/demo/layout.route.ts b/devui/layout/demo/layout.route.ts deleted file mode 100644 index dcc0f8afaae645b0ad42ddd6795f5f9ae63c6b88..0000000000000000000000000000000000000000 --- a/devui/layout/demo/layout.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import LayoutDemoComponent from './layout-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: LayoutDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/layout/doc/api-cn.md b/devui/layout/doc/api-cn.md deleted file mode 100644 index 85336386f097417b09c34e2873e40ed7866ec724..0000000000000000000000000000000000000000 --- a/devui/layout/doc/api-cn.md +++ /dev/null @@ -1,39 +0,0 @@ -# 如何使用 - -在 module 中使用: - -```ts -import { LayoutModule } from 'ng-devui'; -``` - -在页面中使用: - -```html - - - - - -``` - -# d-layout - -布局容器,可以与`d-header`, `d-content`, `d-footer`, `d-aside`组合实现布局; -`d-layout`下可嵌套元素:`d-header`, `d-content`, `d-aside`, `d-layout`。 - -# d-header - -顶部布局,只能放在`d-layout`容器中,作为`d-layout`容器的顶部实现。 -默认高度:40px。 - -# d-footer - -底部布局,只能放在`d-layout`容器中,作为`d-layout`容器的底部实现。 - -# d-content - -内容容器,只能放在`d-layout`容器中,作为`d-layout`容器`d-header`与`d-footer`之间的内容。 - -# d-aside - -侧边栏,只能放在`d-layout`容器中,作为`d-layout`容器的侧边栏部分。 diff --git a/devui/layout/doc/api-en.md b/devui/layout/doc/api-en.md deleted file mode 100644 index 3eb653e03bb83565da95de5427130d45f3a19bbc..0000000000000000000000000000000000000000 --- a/devui/layout/doc/api-en.md +++ /dev/null @@ -1,39 +0,0 @@ -# How to use - -Import into module: - -```ts -import { LayoutModule } from 'ng-devui'; -``` - -In the page: - -```html - - - - - -``` - -# d-layout - -Layout container, which can be combined with `d-header`, `d-content`, `d-footer`, `d-aside` to implement layout. -Elements that can be nested under `d-layout`: `d-header`, `d-content`, `d-aside`, `d-layout`. - -# d-header - -Top layout, which can be implemented only in the `d-layout` container as the top of the `d-layout` container. -Default height: 40 px - -# d-footer - -Bottom layout, which can be implemented only in the `d-layout` container as the bottom of the `d-layout` container. - -# d-content - -Content container, which can be placed only in the `d-layout` container as the content between `d-header` and `d-footer` in the `d-layout` container. - -# d-aside - -Sidebar, which can only be placed in the `d-layout` container as the sidebar part of the `d-layout` container. diff --git a/devui/layout/layout.tsx b/devui/layout/layout.tsx deleted file mode 100644 index e85505cc7a87380299f8f6ff159ae62403718e3f..0000000000000000000000000000000000000000 --- a/devui/layout/layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-layout', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-layout
    - } - } -}) \ No newline at end of file diff --git a/devui/loading/demo/loading-demo.tsx b/devui/loading/demo/loading-demo.tsx deleted file mode 100644 index adf82c4d1620c5096697697690b26b08ae9758bf..0000000000000000000000000000000000000000 --- a/devui/loading/demo/loading-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-loading-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-loading-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/loading/demo/loading.route.ts b/devui/loading/demo/loading.route.ts deleted file mode 100644 index d511a03033c644bd39ebbc2f9cdfeaf646d4daba..0000000000000000000000000000000000000000 --- a/devui/loading/demo/loading.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import LoadingDemoComponent from './loading-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: LoadingDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/loading/doc/api-cn.md b/devui/loading/doc/api-cn.md deleted file mode 100644 index c928711e6e8cef5f5291ae8c82df44dc45ba246a..0000000000000000000000000000000000000000 --- a/devui/loading/doc/api-cn.md +++ /dev/null @@ -1,84 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { LoadingModule } from 'ng-devui/loading'; -``` - -在页面中使用: - -```html - - -``` - -# dLoading - -## dLoading 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------: | :---------------------------: | :--------------------: | :-------------------------------------------------------------------- | ------------------------------------------ | -| loading | [`LoadingType`](#loadingtype) | -- | 可选,控制 loading 状态 | [基本用法](demo#basic-usage) | -| message | `string` | -- | 可选,loading 时的提示信息 | [多 promise](demo#multi-promise) | -| loadingTemplateRef | `TemplateRef` | -- | 可选,自定义 loading 模板 | [自定义样式](demo#custom-style) | -| backdrop | `boolean` | -- | 可选,loading 时是否显示遮罩 | [基本用法](demo#basic-usage) | -| showLoading | `boolean` | -- | 可选,手动启动和关闭 loading 状态,与`loading`参数不能同时使用 | [使用 showLoading 控制](demo#show-loading) | -| positionType | `string` | 'relative' | 可选,指定`dLoading`宿主元素的定位类型,取值与 css position 属性一致。 | [使用 showLoading 控制](demo#show-loading) | -| view | `{top?:string,left?:string}` | {top:'50%',left:'50%'} | 可选,调整 loading 的显示位置,相对于宿主元素的顶部距离与左侧距离 | [基本用法](demo#basic-usage) | -| zIndex | `number` | -- | 可选,loading加载提示的 z-index 值 | [基本用法](demo#basic-usage) | - -### LoadingType - -```ts -export type LoadingType = Observable | Promise | Array> | Array> | Subscription | undefined; -``` - -# LoadingService - -在 component 中引入: - -```ts -import { LoadingService } from 'ng-devui/loading'; -``` - -在 component 里的 constructor 中声明: - -```ts -constructor( private loadingService: LoadingService ) {} -``` - -在页面中使用: - -```html -click me show full screen loading! -在openFullScreen函数中调用loadingService.open(),打开loading 加载,并且获得返回值是一个实例,该实例调用close(), 关闭loading加载。 -``` - -```ts - // 举个例子:const dm = document.querySelector('#me'); - // 举个例子:@ViewChild('loadingTemplateRef1', { static: true }) loadingTemplateRef1: TemplateRef; - this.loadingService.open({ - target: dm, - loadingTemplateRef: loadingTemplateRef1, - backdrop: true, - message: 'One moment please...', - positionType: 'relative', - view: { - top: '50%', - left: '50%' - } - }); -``` - -## LoadingService 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------: | :--------------------------: | :--------------------: | :------------------------------------------------------------------ | ---------------------------------------------- | -| target | `Element` | document.body | 可选,Loading 需要覆盖的 DOM 节点 | [服务方式调用](demo#full-screen) | -| message | `string` | -- | 可选,loading 时的提示信息 | [服务方式调用](demo#full-screen) | -| loadingTemplateRef | `TemplateRef` | -- | 可选,自定义 loading 模板 | [服务方式调用](demo#full-screen) | -| backdrop | `boolean` | true | 可选,loading 时是否显示遮罩 | [服务方式调用](demo#full-screen) | -| positionType | `'static' \| 'relative' \| 'absolute' \| 'fixed' \|'sticky'` | 'relative' | 可选,指定`dLoading`宿主元素的定位类型, |[服务方式调用](demo#full-screen) -| view | `{top?:string,left?:string}` | {top:'50%',left:'50%'} | 可选,调整 loading 的显示位置,相对于宿主元素的顶部距离与左侧距离 | [服务方式调用](demo#full-screen) | -| zIndex | `number` | -- | 可选,弹出框 z-index 值 | [服务方式调用](demo#full-screen) | \ No newline at end of file diff --git a/devui/loading/doc/api-en.md b/devui/loading/doc/api-en.md deleted file mode 100644 index 1ab182b5c978031b5d68a875027fe76dab434786..0000000000000000000000000000000000000000 --- a/devui/loading/doc/api-en.md +++ /dev/null @@ -1,84 +0,0 @@ -# How to use - -Import into module - -```ts -import { LoadingModule } from 'ng-devui/loading'; -``` - -In the page - -```html - - -``` - -# dLoading - -## dLoading Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------: | :---------------------------: | :---------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -| loading | [`LoadingType`](#loadingtype) | -- | Optional. Controlling the loading status | [Basic Usage](demo#basic-usage) | -| message | `string` | -- | Optional. Prompt message during loading | [Multipromise](demo#multi-promise) | -| loadingTemplateRef | `TemplateRef` | -- | Optional. Custom loading template | [Custom Style](demo#custom-style) | -| backdrop | `boolean` | -- | Optional. Indicating whether to display the mask during loading | [Basic Usage](demo#basic-usage) | -| showLoading | `boolean` | -- | Optional. This parameter is used to manually enable or disable the loading status. This parameter cannot be used together with the `loading` parameter | [Using ShowLoading](demo#show-loading) | -| positionType | `string` | 'relative' | Optional. This parameter specifies the positioning type of the `dLoading` host element. The value is the same as that of the css position attribute | [Using ShowLoading](demo#show-loading) | -| view | `{top?:string,left?:string}` | {top: '50%',left:'50%'} | Optional. Adjust the loading display position, that is, the distance between the top and left of the host element | [Basic Usage](demo#basic-usage) | -| zIndex | `number` | -- | Optional. Z-index value in the loading displayed. | [Basic Usage](demo#basic-usage) | - -### LoadingType - -```ts -export type LoadingType = Observable | Promise | Array> | Array> | Subscription | undefined; -``` - -# LoadingService - -Import into component - -```ts -import { LoadingService } from 'ng-devui/loading'; -``` - -In the constructor of component, declare: - -```ts -constructor( private loadingService: LoadingService ) {} -``` - -In the page - -```html -click me show full screen loading! -Invoke loadingService.open() in the openFullScreen function to enable loading. The return value is an instance. The instance invokes close() to disable loading. -``` - -```ts -// For example, const dm = document.querySelector('#me'); -// For Example: @ViewChild('loadingTemplateRef1', {static: true}) loadingTemplateRef1: TemplateRef; - this.loadingService.open({ - target: dm, - loadingTemplateRef: loadingTemplateRef1, - backdrop: true, - message: 'One moment please...', - positionType: 'relative', - view: { - top: '50%', - left: '50%' - } - }); -``` - -## LoadingService Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------: | :--------------------------: | :--------------------: | :------------------------------------------------------------------ | ---------------------------------------------- | -| target | `Element` | document.body | Optional. Loads the DOM nodes to be covered. | [Service function](demo#full-screen) | -| message | `string` | -- | Optional. Prompt message during loading | [Service function](demo#full-screen) | -| loadingTemplateRef | `TemplateRef` | -- | Optional. Custom loading template | [Service function](demo#full-screen) | -| backdrop | `boolean` | true | Optional. Indicating whether to display the mask during loading | [Service function](demo#full-screen) | -| positionType | `'static' \| 'relative' \| 'absolute' \| 'fixed' \|'sticky'` | 'relative' | Optional. This parameter specifies the positioning type of the `dLoading` host element. |[Service function](demo#full-screen) -| view | `{top?:string,left?:string}` | {top: '50%',left:'50%'} | Optional. Adjust the loading display position, that is, the distance between the top and left of the host element | [Service function](demo#full-screen) | -| zIndex | `number` | -- | Optional. Z-index value in the loading displayed. | [Service function](demo#full-screen) | \ No newline at end of file diff --git a/devui/loading/loading.tsx b/devui/loading/loading.tsx deleted file mode 100644 index a17f0afffea46b005f85779aefe76aaa7e657756..0000000000000000000000000000000000000000 --- a/devui/loading/loading.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-loading', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-loading
    - } - } -}) \ No newline at end of file diff --git a/devui/modal/demo/modal-demo.tsx b/devui/modal/demo/modal-demo.tsx deleted file mode 100644 index 68ce4e32d2f8b3f43020396fac2f458c8f6f50c7..0000000000000000000000000000000000000000 --- a/devui/modal/demo/modal-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-modal-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-modal-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/modal/demo/modal.route.ts b/devui/modal/demo/modal.route.ts deleted file mode 100644 index 6bf1e9965a1ef0ca8b5e44c12f487a2c70837b3d..0000000000000000000000000000000000000000 --- a/devui/modal/demo/modal.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ModalDemoComponent from './modal-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ModalDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/modal/doc/api-cn.md b/devui/modal/doc/api-cn.md deleted file mode 100644 index fa270f159538e9e45d3c2ae2f46934a01c6c4d12..0000000000000000000000000000000000000000 --- a/devui/modal/doc/api-cn.md +++ /dev/null @@ -1,128 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { ModalModule } from 'ng-devui/modal'; -``` - -在页面中使用: -```html -click me! -通过openstandardDialog函数中调用dialogService.open()或modalService.open()打开模态弹窗 -``` -```ts -openstandardDialog(dialogtype?: string) { - const results = this.dialogService.open({ - id: 'dialog-service', - width: '346px', - maxHeight: '600px', - showAnimate: true, - title: 'Start Snapshot Version', - content: ModalTestComponent, - backdropCloseable: true, - dialogtype: dialogtype, - onClose: () => { - console.log('on dialog closed'); - }, - data: { - name: 'Tom', - age: 10, - address: 'Chengdu', - }, - }); - } -``` - -# Modal - -**打开 modal**:modalService.**open** ( ~ : **IModalOptions** ) - -## IModalOptions 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-----------------------------: | :------: | :--------------------------------------------- | --------------------------------------------------------------- | -| id | `string` | -- | 必选,弹出框 id | [自定义对话框](demo#custom-dialog) | -| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | [自定义对话框](demo#custom-dialog) | -| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | -| backDropZIndex | `number` | 1040 | 可选,弹出框背景 z-index 值 | -| component | `Type` | -- | 可选,弹出框组件,弹出框会显示组件内容 | [自定义对话框](demo#custom-dialog) | -| injector | `Injector` | true | 可选,可以选择指定将用作组件的父级的注射器。 | -| data | `object` | -- | 可选,传入component实例中的属性 | [自定义对话框](demo#custom-dialog) | -| showAnimate | `boolean` | true | 可选,是否显示动画, | [自定义对话框](demo#custom-dialog) | -| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框, | [自定义对话框](demo#custom-dialog) | -| componentFactoryResolver | `ComponentFactoryResolver` | -- | 可选,自定义动态渲染组件解析器, | -| onClose | `Function` | -- | 可选,弹出框关闭之后回调的函数, | [自定义对话框](demo#custom-dialog) | -| beforeHidden | `Function\|Promise\|Observable` | -- | 可选,关闭窗口之前的回调 | -| placement | `enum('center'\|'top'\|'bottom')` | 'center' | 可选,弹出框出现的位置 | -| offsetX | `string` | '0px' | 可选,弹出框横向偏移 | -| offsetY | `string` | '0px' | 可选,弹出框纵向偏移 | -| bodyScrollable | `boolean` | true | 可选,modal 打开后,body是否可滚动,默认可滚动,false时隐藏滚动条,隐藏滚动条可能会产生抖动,可以通过设置外层fixed来同时避免滚动与抖动 | [通过外层fixed同时避免滚动和抖动](demo#template-fixed) | -| contentTemplate | `TemplateRef` | -- | 可选,弹出框内容模板,与component不兼容 | [自定义弹出框内容模板](demo#template-content) | -| escapable | `boolean` | true | 可选,是否支持esc键关闭弹窗 | - -# dialog 说明 - -**打开 dialog**:dialogService.**open** ( ~ : **IDialogOptions** ) - -## IDialogOptions 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------: | :-----------------------------: | :--------: | :----------------------------------------------------------------------- | ---------------------------------------------------------------- | -| id | `string` | -- | 必选,弹出框 id | [标准对话框](demo#standard-dialog) | -| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | [标准对话框](demo#standard-dialog) | -| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | [信息提示](demo#message-hint) | -| backDropZIndex | `number` | 1040 | 可选,弹出框背景 z-index 值 | -| maxHeight | `string` | -- | 可选,弹出框最大高度(e.g '600px') | [标准对话框](demo#standard-dialog) | -| title | `string` | -- | 可选,弹出框 title | [标准对话框](demo#standard-dialog) | -| content | `string\|Type` | -- | 可选,弹出框内容,支持字符串和组件 | [标准对话框](demo#standard-dialog) | -| html | `boolean` | -- | 可选,content是否是html代码 | [警告弹出框](demo#warning-pop-up) | -| injector | `Injector` | true | 可选,可以选择指定将用作组件的父级的注射器。 | -| data | `object` | -- | 可选,当content为Component时,传递到Component实例中的属性 | [标准对话框](demo#standard-dialog) | -| buttons | `array` | -- | 可选,弹出框按钮,支持自定义文本、样式、禁用、点击事件 | [标准对话框](demo#standard-dialog) | -| showAnimate | `boolean` | true | 可选,是否显示动画, | [拦截对话框关闭](demo#intercept-dialog-closed) | -| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框, | [拦截对话框关闭](demo#intercept-dialog-closed) | -| componentFactoryResolver | `ComponentFactoryResolver` | -- | 可选,自定义动态渲染组件解析器, | -| onClose | `Function` | -- | 可选,弹出框关闭之后回调的函数, | [标准对话框](demo#standard-dialog) | -| beforeHidden | `Function\|Promise\|Observable` | -- | 可选,可以阻止对话框关闭 | [拦截对话框关闭](demo#intercept-dialog-closed) | -| dialogtype | `string` | 'standard' | 可选,弹出框类型,有四种选择['standard'\|'success'\|'failed'\|'warning'\|'info'] | [标准对话框](demo#standard-dialog) | -| draggable | `boolean` | true | 可选,弹出框是否可拖拽 | -| placement | `enum('center'\|'top'\|'bottom')` | 'center' | 可选,弹出框出现的位置 | -| offsetX | `string` | '0px' | 可选,弹出框横向偏移 | -| offsetY | `string` | '0px' | 可选,弹出框纵向偏移 | -| bodyScrollable | `boolean` | true | 可选,dialog 打开后,body是否可滚动,默认可滚动,false时隐藏滚动条,隐藏滚动条可能会产生抖动,可以通过设置外层fixed来同时避免滚动与抖动 | [通过外层fixed同时避免滚动和抖动](demo#template-fixed) | -| contentTemplate | `TemplateRef` | -- | 可选,弹出框内容模板,与content不兼容 | [自定义弹出框内容模板](demo#template-content) | -| escapable | `boolean` | true | 可选,是否支持esc键关闭弹窗 | - -## ModalOpenResult - -| 属性 | 类型 | 说明 | 跳转 Demo | -| :------------------: | :--------------: | :-----------------------------------------------: | :--------------------------------------------------: | -| modalInstance | `ModalComponent` | 返回 Modal 对象,可以作为contentTemplate的context | [标准对话框](demo#standard-dialog) | -| modalContentInstance | `Type` | 返回 Modal 内容的对象 | [标准对话框](demo#standard-dialog) | - -## modalInstance 公共方法 -| 方法名 | 参数 | 默认值 | 说明 | 跳转 Demo | -| :----: | :---: | :----- | :-------: | :-------: | -| hide | -- | -- | 关闭modal | [标准对话框](demo#standard-dialog) | -| updateButtonOptions | buttons | [] | 动态更新dialog里边的button配置项,比如disabled | [更新弹出框按钮状态](demo#update-button-options) | - -## buttons 类型定义 - -```javascript -buttons: Array<{ - id?: string; - cssClass?: string; - text: string; - handler: ($event: Event) => void; - btnwidth?: string; - autofocus?: boolean; - disabled?: boolean; - }>; -``` - -## dMoveable 指令 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------: | :-----------: | :---: | :-------------------------------------------------- | --------- | -| dMoveable | `boolean` | false | 可选,是否启用拖动移动功能 |[自定义对话框](demo#custom-dialog)| -| handle | `HTMLElement` | -- | 可选,可以拖动的元素 |[自定义对话框](demo#custom-dialog)| -| moveEl | `HTMLElement` | -- | 可选,被拖动的区块,默认为使用 dMoveable 指令的元素 |[自定义对话框](demo#custom-dialog)| diff --git a/devui/modal/doc/api-en.md b/devui/modal/doc/api-en.md deleted file mode 100644 index 74891379261d0185f95edad824095d73612ac619..0000000000000000000000000000000000000000 --- a/devui/modal/doc/api-en.md +++ /dev/null @@ -1,128 +0,0 @@ -# How to use -Import into module: -```ts -import { ModalModule } from 'ng-devui/modal'; -``` - -In the page: -```html -click me! -Call dialogService.open() or modalService.open() in the openstandardDialog function to open the drawer board. -``` -```ts -openstandardDialog(dialogtype?: string) { - const results = this.dialogService.open({ - id: 'dialog-service', - width: '346px', - maxHeight: '600px', - showAnimate: true, - title: 'Start Snapshot Version', - content: ModalTestComponent, - backdropCloseable: true, - dialogtype: dialogtype, - onClose: () => { - console.log('on dialog closed'); - }, - data: { - name: 'Tom', - age: 10, - address: 'Chengdu', - }, - }); - } -``` - -# Modal - -**Open the modal**: modalService.**open** (~: **IModalOptions**). - -### IModalOptions - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------------: | :-----------------------------: | :------: | :--------------------------------------------- | --------------------------------------------------------------- | -| id | `string` | -- | Required. ID of the dialog box displayed. | [Custom Dialog Box](demo#custom-dialog) | -| width | `string` | -- | Optional. Width of the pop-up box (e.g '300px'). | [Custom Dialog Box](demo#custom-dialog) | -| zIndex | `number` | 1050 | Optional. Z-index value in the dialog box displayed. | -| backDropZIndex | `number` | 1040 | Optional. Z-index value in the back drop displayed of the dialog box. | -| component | `Type` | -- | Optional. Pop-up component. The component content is displayed in the pop-up box. | [Custom Dialog Box](demo#custom-dialog) | -| injector | `Injector` | true | Optional. You can specify the syringe that will be used as the parent of the component. | -| data | `object` | -- | Optional. The attribute of the component instance is transferred. | [Custom Dialog Box](demo#custom-dialog) | -| showAnimate | `boolean` | true | Optional. Indicating whether to display animations. | [Custom Dialog Box](demo#custom-dialog) | -| backdropCloseable | `boolean` | true | Optional. Can the dialog box be closed when you click a blank area? | [Custom Dialog Box](demo#custom-dialog) | -| componentFactoryResolver | `ComponentFactoryResolver` | -- | Optional. Customized dynamic rendering component parser. | -| onClose | `Function` | -- | Optional. Function called back after the dialog box is closed. | [Custom Dialog Box](demo#custom-dialog) | -| beforeHidden | `Function\|Promise\|Observable` | -- | Optional. Callback before closing a window. | -| placement | `enum('center'\|'top'\|'bottom')` | 'center' | Optional. This parameter is optional and specifies the position where the dialog box is displayed. | -| offsetX | `string` | '0px' | Optional. Horizontal offset of the pop-up box. | -| offsetY | `string` | '0px' | Optional. Vertical offset of the pop-up box. | -| bodyScrollable | `boolean` | true |Optional. Specifies whether the body can scroll after modal is enabled. The default value is false. The scroll bar is hidden. Hiding the scroll bar may cause jitter. You can set the outer fixed to avoid scrolling and jitter. |[The outer layer is fixed to solve the jitter and scrolling problem](demo#template-fixed) | -| contentTemplate | `TemplateRef` | -- | Optional. It is a dialog box content template, which is incompatible with the component. | [Customizing a pop-up box content template](demo#template-content) | -| escapable | `boolean` | true | Optional. Specifies whether to support pop-up window closure by pressing the Esc key. | - -## Dialog Description - -**open dialog**:dialogService.**open** ( ~ : **IDialogOptions** ) - -### IDialogOptions - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------------: | :-----------------------------: | :--------: | :----------------------------------------------------------------------- | ---------------------------------------------------------------- | -| id | `string` | -- | Required. The ID of the dialog box is displayed. | [Standard Dialog Box](demo#standard-dialog) | -| width | `string` | -- | Optional. Width of the dialog box (e.g '300px'). | [Standard Dialog Box](demo#standard-dialog) | -| zIndex | `number` | 1050 | Optional. Z-index value in the dialog box displayed. | [Information](demo#message-hint) | -| backDropZIndex | `number` | 1040 | Optional. Z-index value in the back drop displayed of the dialog box. | -| maxHeight | `string` | -- | Optional. The maximum height of the dialog box (e.g '600px'). | [Standard Dialog Box](demo#standard-dialog) | -| title | `string` | -- | Optional. Pop-up box title. | [Standard Dialog Box](demo#standard-dialog) | -| content | `string\|Type` | -- | Optional. Pop-up box content. Character strings and components are supported. | [Standard Dialog Box](demo#standard-dialog) | -| html | `boolean` | -- | Optional. Whether content is HTML code. | [Warning Dialog Box](demo#warning-pop-up) | -| injector | `Injector` | true | Optional. You can specify the syringe that will be used as the parent of the component. | -| data | `object` | -- | Optional. When content is set to Component, the attribute is transferred to the Component instance. | [Standard Dialog Box](demo#standard-dialog) | -| buttons | `array` | -- | Optional. Pop-up box button, which supports custom text, style, disabling, and click events. | [Standard Dialog Box](demo#standard-dialog) | -| showAnimate | `boolean` | true | Optional. Whether to display animation. | [Blocking dialog box closed](demo#intercept-dialog-closed) | -| backdropCloseable | `boolean` | true | Optional. Can the dialog box be closed when you click a blank area? | [Blocking dialog box closed](demo#intercept-dialog-closed) | -| componentFactoryResolver | `ComponentFactoryResolver` | -- | Optional. Customized dynamic rendering component parser. | -| onClose | `Function` | -- | Optional, Function called back after the dialog box is closed. | [Standard Dialog Box](demo#standard-dialog) | -| beforeHidden | `Function\|Promise\|Observable` | -- | Optional. It can prevent dialog boxes from closing. | [Blocking dialog box closed](demo#intercept-dialog-closed) | -| dialogtype | `string` | 'standard' | Optional. The options are ['standard'\|'success'\|'failed'\|'warning'\|'info']. | [Standard Dialog Box](demo#standard-dialog) | -| draggable | `boolean` | true | Optional. Whether the pop-up box can be dragged. | -| placement | `enum('center'\|'top'\|'bottom')` | 'center' | Optional. This parameter is optional and specifies the position where the dialog box is displayed. | -| offsetX | `string` | '0px' | Optional. Horizontal offset of the pop-up box. | -| offsetY | `string` | '0px' | Optional. Vertical offset of the pop-up box. | -| bodyScrollable | `boolean` | true |Optional. Specifies whether the body can scroll after dialog is enabled. The default value is false. The scroll bar is hidden. Hiding the scroll bar may cause jitter. You can set the outer fixed to avoid scrolling and jitter. |[The outer layer is fixed to solve the jitter and scrolling problem](demo#template-fixed) | -| contentTemplate | `TemplateRef` | -- | Optional. It is a pop-up box content template, which is incompatible with content. | [Customizing a pop-up box content template](demo#template-content) | -| escapable | `boolean` | true | Optional. Specifies whether to support the ESC key to close the pop-up window.| | - -### ModalOpenResult - -| Attribute | Type | Description | Jump to Demo | -| :------------------: | :--------------: | :-----------------------------------------------: | :--------------------------------------------------: | -| modalInstance | `ModalComponent` | Returns a Modal object. Which can be used as the context of the content template. | [Standard Dialog Box](demo#standard-dialog) | -| modalContentInstance | `Type` | Returns the object of Modal content. | [Standard Dialog Box](demo#standard-dialog) | - -### modalInstance 公共方法 -| Method name | Parameter | Default value | Description | Jump to Demo | -| :----: | :---: | :----- | :-------: | :-------: | -| hide | -- | -- | Close modal. | [Standard Dialog Box](demo#standard-dialog) | -| updateButtonOptions | buttons | [] | Dynamically updates the button configuration item in the dialog, for example, disabled. | [Update the button status in the dialog box](demo#update-button-options) | - -### buttons Type Definition - -```javascript -buttons: Array<{ - id?: string; - cssClass?: string; - text: string; - handler: ($event: Event) => void; - btnwidth?: string; - autofocus?: boolean; - disabled?: boolean; - }>; -``` - -## dMoveable directive - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :-----------: | :---: | :-------------------------------------------------- | --------- | -| dMoveable | `boolean` | false | Optional. Whether to enable the drag function. | [Custom Dialog Box](demo#custom-dialog)| -| handle | `HTMLElement` | -- | Optional. Elements that can be dragged. | [Custom Dialog Box](demo#custom-dialog)| -| moveEl | `HTMLElement` | -- | Optional. Dragged block. By default, the element using the dMoveable instruction is used. | [Custom Dialog Box](demo#custom-dialog)| diff --git a/devui/modal/modal.tsx b/devui/modal/modal.tsx deleted file mode 100644 index a2e25f330aa6c7eed93b3cf3ad3f47f9aad7d431..0000000000000000000000000000000000000000 --- a/devui/modal/modal.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-dragdrop', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-dragdrop
    - } - } -}) \ No newline at end of file diff --git a/devui/multi-auto-complete/demo/multi-auto-complete-demo.tsx b/devui/multi-auto-complete/demo/multi-auto-complete-demo.tsx deleted file mode 100644 index 5f375cd4a39753dec0e007562a05aa5ca21d4e69..0000000000000000000000000000000000000000 --- a/devui/multi-auto-complete/demo/multi-auto-complete-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-multi-auto-complete-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-multi-auto-complete-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/multi-auto-complete/demo/multi-auto-complete.route.ts b/devui/multi-auto-complete/demo/multi-auto-complete.route.ts deleted file mode 100644 index 014b181162e89d43222c1a5349dfaa43815e62a0..0000000000000000000000000000000000000000 --- a/devui/multi-auto-complete/demo/multi-auto-complete.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import MultiAutoCompleteDemoComponent from './multi-auto-complete-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: MultiAutoCompleteDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/multi-auto-complete/doc/api-cn.md b/devui/multi-auto-complete/doc/api-cn.md deleted file mode 100644 index e07b81ba419bd4a507495503e6736209cd536e91..0000000000000000000000000000000000000000 --- a/devui/multi-auto-complete/doc/api-cn.md +++ /dev/null @@ -1,69 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { MultiAutoCompleteModule } from 'ng-devui/multi-auto-complete'; -``` - -在页面中使用: - -```html - -``` - -# d-multi-auto-complete - -## d-multi-auto-complete 参数 - -- 本组件基于 dAutoComplete 实现,itemTemplate、noResultItemTemplate 等参数使用方式与 dAutoComplete 一致(此类参数使用 Demo 跳转参考 dAutoComplete 使用)。 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :-----------------------------------: | :---------------------------------------: | :----------------------------------------------------------------------------- | ------------------------------------------ | -| appendToBody | `boolean` | -- | 可选,是否 appendToBody | [基本用法](demo#basic-usage) | -| width | `number` | -- | 可选,控制下拉框宽度,搭配 appendToBody 使用(`px`) | -| disabled | `boolean` | -- | 可选,是否禁用 | [使用禁用](demo#auto-complete-disabled) | -| source | `Array` | -- | 可选,数据列表 | [基本用法](demo#basic-usage) | -| itemTemplate | `TemplateRef` | -- | 可选,下拉选项模板 | [自定义模板展示](demo#auto-custom) | -| noResultItemTemplate | `TemplateRef` | -- | 可选,结果不存在时的显示模板 | [自定义模板展示](demo#auto-custom) | -| delay | `number` | 300 | 可选,输入结束 dalay 毫秒后启动查询(`ms`) | [自定义模板展示](demo#auto-custom) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | 可选,自定义搜索过滤 | [自定义匹配方法](demo#auto-complete-array) | -| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | 可选,对 item 的数据进行自定义显示内容,默认显示 item.label 或 item.toString() | [设置禁用](demo#auto-disable) | -| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | 可选,对选中数据进行转化 | [启用懒加载](demo#auto-lazy-load) | -| tipsText | `string` | -- | 可选,提示文字 | [设置禁用](demo#auto-disable) | -| placeholder | `string` | -- | 可选,placeholder | [基本用法](demo#basic-usage) | -| latestSource | `Array` | -- | 可选, 最近输入 | [最近输入](demo#auto-latest) | - -## d-multi-auto-complete 事件 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------: | :-----------------: | :--: | :------------------------------------------------- | ------------------------------------------ | -| autoSubmit | `EventEmitter` | -- | 可选,当前已选择数据发生变化时,回传当前已选择数据 | [自定义匹配方法](demo#auto-complete-array) | - -# 接口 & 类型定义 - -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { - return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` - -term 为输入的关键字。 - -### defaultFormatter - -```ts -defaultFormatter = (item) => (item ? item.label || item.toString() : ''); -``` - -item 为数据项。 - -### defaultValueParse - -```ts -defaultValueParse = (item) => item; -``` - -item 为数据项。 diff --git a/devui/multi-auto-complete/doc/api-en.md b/devui/multi-auto-complete/doc/api-en.md deleted file mode 100644 index 03f1f8a18346e1a02dce9834f6bfda3f5250a396..0000000000000000000000000000000000000000 --- a/devui/multi-auto-complete/doc/api-en.md +++ /dev/null @@ -1,69 +0,0 @@ -# How to use - -Import into module: - -```ts -import { MultiAutoCompleteModule } from ' ng-devui/multi-auto-complete'; -``` - -In the page: - -```html - -``` - -# d-multi-auto-complete - -## d-multi-auto-complete parameters - -- This component is implemented based on dAutoComplete. The usage of parameters such as itemTemplate and noResultItemTemplate is the same as that of dAutoComplete. (For details about how to use the Demo to jump to such parameters, see dAutoComplete.) - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :-----------------------------------: | :---------------------------------------: | :-------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -| appendToBody | `boolean` | -- | Optional. AppendToBody | [Basic usage](demo#basic-usage) | -| width | `number` | -- | Optional. Controls the width of the drop-down list box. This parameter is used with appendToBody (`px`) | -| disabled | `boolean` | -- | Optional. Indicating whether to disable it | [Disabled](demo#auto-complete-disabled) | -| source | `Array` | -- | Optional. Data list | [Basic usage](demo#basic-usage) | -| itemTemplate | `TemplateRef` | -- | Optional. The drop-down list box contains a template. | [Customized template display](demo#auto-custom) | -| noResultItemTemplate | `TemplateRef` | -- | Optional. Template for displaying the result when the result does not exist | [Customized template display](demo#auto-custom) | -| delay | `number` | 300 | Optional. The query starts after the specified delay milliseconds (`ms`) | [Customized template display](demo#auto-custom) | -| searchFn | `(term: string) => Observable` | [`defaultSearchFn`](#defaultsearchfn) | Optional. Customized search filtering | [Customized matching method](demo#auto-complete-array) | -| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | : Optional. Customize the display content of item data. By default, item.label or item.toString() is displayed. | [Disabled](demo#auto-disable) | -| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | Optional. Converts the selected data | [Enable lazy loading](demo#auto-lazy-load) | -| tipsText | `string` | -- | Optional. Prompt text | [Disabled](demo#auto-disable) | -| placeholder | `string` | -- | Optional. Placeholder | [Basic usage](demo#basic-usage) | -| latestSource | `Array` | -- | Optional. Latest input | [Last input](demo#auto-latest) | - -## d-multi-auto-complete events - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------: | :-----------------: | :-----: | :----------------------------------------------------------------------- | ------------------------------------------------------ | -| autoSubmit | `EventEmitter` | -- | Optional. When the selected data changes, the selected data is returned. | [Customized matching method](demo#auto-complete-array) | - -# Interface & Type Definition - -### defaultSearchFn - -```ts -defaultSearchFn = (term) => { - return of(this.source.filter((lang) => this.formatter(lang).toLowerCase().indexOf(term.toLowerCase()) !== -1)); -}; -``` - -term indicates the entered keyword. - -### defaultFormatter - -```ts -defaultFormatter = (item) => (item ? item.label || item.toString() : ''); -``` - -item indicates a data item. - -### defaultValueParse - -```ts -defaultValueParse = (item) => item; -``` - -item indicates a data item. diff --git a/devui/multi-auto-complete/multi-auto-complete.tsx b/devui/multi-auto-complete/multi-auto-complete.tsx deleted file mode 100644 index 1839de40a7eb3090ed6fbcea64c20d8596b828a4..0000000000000000000000000000000000000000 --- a/devui/multi-auto-complete/multi-auto-complete.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-multi-auto-complete', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-multi-auto-complete
    - } - } -}) \ No newline at end of file diff --git a/devui/pagination/demo/pagination-demo.tsx b/devui/pagination/demo/pagination-demo.tsx deleted file mode 100644 index 01431d60715103523064b830e018388c76a60d73..0000000000000000000000000000000000000000 --- a/devui/pagination/demo/pagination-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-pagination-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-pagination-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/pagination/demo/pagination.route.ts b/devui/pagination/demo/pagination.route.ts deleted file mode 100644 index 60683f86b2c27460d4c79da07f115e934adc8919..0000000000000000000000000000000000000000 --- a/devui/pagination/demo/pagination.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import PaginationDemoComponent from './pagination-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: PaginationDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/pagination/doc/api-cn.md b/devui/pagination/doc/api-cn.md deleted file mode 100644 index 1f0f03a0e76b383edc8bc51690650d24bb25e8ac..0000000000000000000000000000000000000000 --- a/devui/pagination/doc/api-cn.md +++ /dev/null @@ -1,71 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { PaginationModule } from 'ng-devui/pagination'; -``` - -在页面中使用: - -```html - -``` -# d-pagination - -## d-pagination 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------------: | :-------------------------------------------------------------------------------------------------------: | :------------------------: | :------------------------------------------------------------------------------------------------------- | ---------------------------------------- | -| pageSize | `number` | 10 | 可选,每页显示最大条目数量 | [基本用法](demo#basic-usage) | -| total | `number` | 0 | 可选,显示的总条目数 | [基本用法](demo#basic-usage) | -| pageSizeOptions | `number[]` | 10 | 可选,分页每页最大条目数量的下拉框的数据源,默认有四种选择 5, 10, 20, 50 | [多种配置](demo#multiple-configurations) | -| pageSizeDirection | `Array<`[`AppendToBodyDirection`](#appendtobodydirection)`\|`[`ConnectedPosition`](#connectedposition)`>` | ['centerDown', 'centerUp'] | 可选,设置分页每页条目的下拉框展示的方向 | [多种配置](demo#multiple-configurations) | -| pageIndex | `number` | 1 | 可选,初始化页码 | [基本用法](demo#basic-usage) | -| maxItems | `number` | 10 | 可选,分页最多显示几个按钮 | [基本用法](demo#basic-usage) | -| preLink | `string` | -- | 可选,上一页按钮显示图标,默认设置为左箭头图标 | [基本用法](demo#basic-usage) | -| nextLink | `string` | -- | 可选, 下一页按钮显示图标,默认设置为右箭头图标 | [基本用法](demo#basic-usage) | -| size | `number` | '' | 可选,分页组件尺寸,有三种选择 lg,``,sm,分别代表大,中,小 | [基本用法](demo#basic-usage) | -| canJumpPage | `boolean` | true | 可选,是否显示分页输入跳转 | [基本用法](demo#basic-usage) | -| canChangePageSize | `boolean` | false | 可选,是否显示用于选择更改分页每页最大条目数量的下拉框 | [基本用法](demo#basic-usage) | -| canViewTotal | `boolean` | true | 可选,是否显示总条目 | [基本用法](demo#basic-usage) | -| totalItemText | `string` | '所有条目' | 可选,总条目文本 | [极简模式](demo#minimalist-model) | -| goToText | `string` | '跳至' | 可选,跳转文本 | [基本用法](demo#basic-usage) | -| showJumpButton | `boolean` | false | 可选,是否显示跳转按钮 | [多种配置](demo#multiple-configurations) | -| showTruePageIndex | `boolean` | false | 可选,页码超出分页范围时候也显示当前页码的开关 | [多种配置](demo#multiple-configurations) | -| lite | `boolean` | false | 可选,是否切换为极简模式 | [极简模式](demo#minimalist-model) | -| showPageSelector | `boolean` | true | 可选,`极简模式`下是否显示页码下拉 | [极简模式](demo#minimalist-model) | -| haveConfigMenu | `boolean` | false | 可选,`极简模式`下是否显示配置 | [极简模式](demo#minimalist-model) | -| autoFixPageIndex | `boolean` | true | 可选,改变 pageSize 时是否自动修正页码,若`pageSizeChange`事件中会对`pageIndex`做处理,建议设置为`false` | [极简模式](demo#minimalist-model) | - -## d-pagination 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :-------------: | :--------------------: | :--------------------------------------------------------- | ---------------------------------------- | -| pageIndexChange | `EventEmitter` | 可选,页码变化的回调,返回当前页码值 | [多种配置](demo#multiple-configurations) | -| pageSizeChange | `EventEmitter` | 可选,每页最大条目数量变更时的回调,返回当前每页显示条目数 | [多种配置](demo#multiple-configurations) | - -# 接口 & 类型定义 - -### AppendToBodyDirection - -```ts -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -### ConnectedPosition - -```ts -export interface ConnectedPosition { - originX: 'start' | 'center' | 'end'; - originY: 'top' | 'center' | 'bottom'; - - overlayX: 'start' | 'center' | 'end'; - overlayY: 'top' | 'center' | 'bottom'; - - weight?: number; - offsetX?: number; - offsetY?: number; - panelClass?: string | string[]; -} -``` diff --git a/devui/pagination/doc/api-en.md b/devui/pagination/doc/api-en.md deleted file mode 100644 index 1be44204f450db4e1f63bd767068f4f6b317a5c5..0000000000000000000000000000000000000000 --- a/devui/pagination/doc/api-en.md +++ /dev/null @@ -1,72 +0,0 @@ -# How to use - -Import into module: - -```ts -import { PaginationModule } from 'ng-devui/pagination'; -``` - -In the page: - -```html - -``` -# d-pagination - - -## d-pagination parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :-------------------------------------------------: | :------------------------: | :-------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | -| pageSize | `number` | 10 | Optional. Maximum number of entries displayed on each page | [Basic usage](demo#basic-usage) | -| total | `number` | 0 | Optional. Total number of displayed items | [Basic usage](demo#basic-usage) | -| pageSizeOptions | `number[]` | 10 | Optional. Data source of the drop-down list box for the maximum number of items on each page. The options are 5, 10, 20, and 50 by default. | [Multiple configurations](demo#multiple-configurations) | -| pageSizeDirection | `Array` | ['centerDown','centerUp'] | Optional. Sets the display direction of the drop-down list box on each page. For details about AppendToBodyDirection and ConnectedPosition, see dropdown | [Multiple configurations](demo#multiple-configurations) | -| pageIndex | `number` | 1 | Optional. Initializing the page number | [Basic usage](demo#basic-usage) | -| maxItems | `number` | 10 | Optional. Maximum number of buttons that can be displayed on multiple pages. | [Basic usage](demo#basic-usage) | -| preLink | `string` | -- | Optional. Icon of the button on the previous page. The default value is the left arrow icon. | [Basic usage](demo#basic-usage) | -| nextLink | `string` | -- | Optional. The icon is displayed on the next page. The default icon is the right arrow icon. | [Basic usage](demo#basic-usage) | -| size | `number` |'' | Optional. Size of the pagination component. The options are lg, ``, and sm, indicating large, medium, and small respectively. | [Basic usage](demo#basic-usage) | -| canJumpPage | `boolean` | true | Optional. Indicates whether to display pagination input jump. | [Basic usage](demo#basic-usage) | -| canChangePageSize | `boolean` | false | Optional. Display the drop-down list box for selecting the maximum number of entries on each page. | [Basic usage](demo#basic-usage) | -| canViewTotal | `boolean` | true | Optional. Indicating whether to display the total number of entries. | [Basic usage](demo#basic-usage) | -| totalItemText | `string` |'All items' | Optional. Total item text | [Simplified mode](demo#minimalist-model) | -| goToText | `string` |'Jump to' | Optional. Jump to text | [Basic usage](demo#basic-usage) | -| showJumpButton | `boolean` | false | Optional. Whether to display the jump button | [Multiple configurations](demo#multiple-configurations) | -| showTruePageIndex | `boolean` | false | Optional. Whether to display the current page number when the page number exceeds the paging range. | [Special circumstances](demo#exceptional-case) | -| lite | `boolean` | false | Optional. Specifies Whether to switch to the simplified mode. | [Simplified mode](demo#minimalist-model) | -| showPageSelector | `boolean` | true | Optional. Whether to display the page number drop-down list in simplified mode. | [Simplified mode](demo#minimalist-model) | -| haveConfigMenu | `boolean` | false | Optional. Whether to display the configuration in simplified mode | [Simplified mode](demo#minimalist-model) | -| autoFixPageIndex | `boolean` | true | Optional. Indicates whether to automatically correct the page number when the page size is changed. If the pageIndex is processed in the `pageSizeChange` event, you are advised to set the value to `false` | [Simplified Mode](demo#minimalist-model) |. - -## d-pagination event - -| Parameter | Type | Description | Jump to Demo | -| :-------------: | :--------------------: | :--------------------------------------------------------- | --------------------------------------------------------------- | -| pageIndexChange | `EventEmitter` | Optional. Callback of page number change, which returns the current page number. | [Multiple configurations](demo#multiple-configurations) | -| pageSizeChange | `EventEmitter` |Optional. Callback function when the maximum number of items on each page changes. | [Multiple configurations](demo#multiple-configurations) | - -# Interface & Type Definition - -### AppendToBodyDirection - -```ts -export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; -``` - -### ConnectedPosition - -```ts -export interface ConnectedPosition { - originX: 'start' | 'center' | 'end'; - originY: 'top' | 'center' | 'bottom'; - - overlayX: 'start' | 'center' | 'end'; - overlayY: 'top' | 'center' | 'bottom'; - - weight?: number; - offsetX?: number; - offsetY?: number; - panelClass?: string | string[]; -} -``` \ No newline at end of file diff --git a/devui/pagination/pagination.tsx b/devui/pagination/pagination.tsx deleted file mode 100644 index b144b0ba58484d7c6a5cac5dafe807f4e4a70aad..0000000000000000000000000000000000000000 --- a/devui/pagination/pagination.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-pagination', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-pagination
    - } - } -}) \ No newline at end of file diff --git a/devui/panel/demo/panel-demo.tsx b/devui/panel/demo/panel-demo.tsx deleted file mode 100644 index 69ff19c9bd6a49a85c106791db36abafced40fa1..0000000000000000000000000000000000000000 --- a/devui/panel/demo/panel-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-panel-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-panel-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/panel/demo/panel.route.ts b/devui/panel/demo/panel.route.ts deleted file mode 100644 index ad7619f90564b671dd1acdb14f4954b92961fe34..0000000000000000000000000000000000000000 --- a/devui/panel/demo/panel.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import PanelDemoComponent from './panel-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: PanelDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/panel/doc/api-cn.md b/devui/panel/doc/api-cn.md deleted file mode 100644 index 2ec4c7bcf7e1c5ae12b091ce362f6cbd683b60f7..0000000000000000000000000000000000000000 --- a/devui/panel/doc/api-cn.md +++ /dev/null @@ -1,38 +0,0 @@ -# 如何使用 - -在module中引入: -```ts -import { PanelModule } from 'ng-devui'; -``` - -在页面中使用: -```html - - - - - -``` - -# d-panel -## d-panel 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-----------------------------: | :-------: | :----------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| type | [`PanelType`](#paneltype) | 'default' | 可选,面板的类型 | [基本用法](demo#basic-usage) | -| cssClass | `string` | -- | 可选,自定义 class 名 | -| isCollapsed | `boolean` | false | 可选,是否展开 | [基本用法](demo#basic-usage) | -| beforeToggle | `Function\|Promise\|Observable` | -- | 可选,面板折叠状态改变前的回调函数,返回 boolean 类型,返回 false 可以阻止面板改变折叠状态 | [根据条件阻止折叠](demo#condition-change) | - -## d-panel 事件 - -| 参数 | 类型 | 说明 | -| :----: | :---------------------: | :--------------------------------------------- | -| toggle | `EventEmitter` | 可选,点击面板时的回调,返回当前面板的展开状态 | - -# 接口 & 类型定义 - -### PanelType -```ts -export type PanelType = 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info'; -``` \ No newline at end of file diff --git a/devui/panel/doc/api-en.md b/devui/panel/doc/api-en.md deleted file mode 100644 index 13a855ee6696f89bafa33eb1e666eb4ee7764042..0000000000000000000000000000000000000000 --- a/devui/panel/doc/api-en.md +++ /dev/null @@ -1,40 +0,0 @@ -# How to use - -Import into module: - -```ts -import { PanelModule } from 'ng-devui'; -``` - -In the page: - -```html - - - - - -``` - -# d-panel -## d-panel Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-----------------------------: | :-------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| type | [`PanelType`](#paneltype) | 'default' | Optional. Panel type | [Basic Usage](demo#basic-usage) | -| cssClass | `string` | -- | Optional. User-defined class name | -| isCollapsed | `boolean` | false | Optional. Whether to expand the file | [Basic Usage](demo#basic-usage) | -| beforeToggle | `Function\|Promise\|Observable` | -- | Optional. Callback function before the panel folding status changes. The value of this parameter is of the boolean type. If false is returned, the panel folding status changes. | [Prevent Collapse Based on Conditions](demo#condition-change) | - -## d-panel Event - -| Parameter | Type | Description | -| :-------: | :---------------------: | :-------------------------------------------------------------------------------------- | -| toggle | `EventEmitter` | Optional. Callback upon panel click to return the expanded status of the current panel. | - -# Interface & Type Definition - -### PanelType -```ts -export type PanelType = 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info'; -``` \ No newline at end of file diff --git a/devui/panel/panel.tsx b/devui/panel/panel.tsx deleted file mode 100644 index 67a627db5ba5b08a6099819c8a2621d8dcd2127d..0000000000000000000000000000000000000000 --- a/devui/panel/panel.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-panel', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-panel
    - } - } -}) \ No newline at end of file diff --git a/devui/popover/demo/popover-demo.tsx b/devui/popover/demo/popover-demo.tsx deleted file mode 100644 index bf43f4d516ccfb1fa7a3b8e211edb69adcd59722..0000000000000000000000000000000000000000 --- a/devui/popover/demo/popover-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-popover-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-popover-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/popover/demo/popover.route.ts b/devui/popover/demo/popover.route.ts deleted file mode 100644 index 55ddabfcd9b3271a06009ee4fa080906702b4733..0000000000000000000000000000000000000000 --- a/devui/popover/demo/popover.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import PopoverDemoComponent from './popover-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: PopoverDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/popover/doc/api-cn.md b/devui/popover/doc/api-cn.md deleted file mode 100644 index 28704674204084169d9bdf1d712dc48d732ecce9..0000000000000000000000000000000000000000 --- a/devui/popover/doc/api-cn.md +++ /dev/null @@ -1,56 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { PopoverModule } from 'ng-devui/popover'; -``` - -在页面中使用: - -```html - -``` - -# dPopover - -## dPopover 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :--------------------------------------------------------: | :--------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | -| content | `string\|HTMLElement\|TemplateRef` | -- | 必选,弹出框的显示内容或模板引用 | [基本用法](demo#basic-usage) | -| visible | `boolean` | false | 可选,弹框的初始化弹出状态 | [手动控制显示](demo#manual-control-display) | -| trigger | `'hover'\|'click'` | 'click' | 弹框触发方式 | [延时触发](demo#hover-delay-time) | -| controlled | `boolean` | false | 可选,是否通过`trigger`方式触发弹框 | [基本用法](demo#basic-usage) | -| position | [`PositionType`](#positiontype) `\| PositionType[]` | ['top', 'right', 'bottom', 'left'] | 可选,内容弹出方向,以 top-left 为例,top 是指从上边弹出,left 是指左对齐,若不设置对齐方向默认为居中。如果传入数组形式,则当前将按照传入数组次序,自适应选取一个方向。 | [弹出位置](demo#position) | -| popType | `'success' \| 'error' \| 'warning' \| 'info' \| 'default'` | 'default' | 可选,弹出框类型,样式不同 | [基本用法](demo#basic-usage) | -| popMaxWidth | `number` | -- | 可选,限制弹出框最大宽度(`px`) | [自定义提示内容](demo#custom-prompt-content) | -| showAnimate | `boolean` | false | 可选,是否显示动画 | [基本用法](demo#basic-usage) | -| appendToBody | `boolean` | true | 可选,默认为 true,仅当 popover 绑定元素外层宽高不够时,overflow 为 hidden,popover 的弹出框不会被一并隐藏掉。 | [基本用法](demo#basic-usage) | -| zIndex | `number` | 1060 | 可选,z-index 值,用于手动控制层高 | [自定义提示内容](demo#custom-prompt-content) | -| scrollElement | `Element` | window | 可选,在这里默认是`window` , 只有当页面的滚动不在`window`上且`appendToBody`的属性为`true`时候才需要传值 | [父容器设置](demo#parent-container-settings) | -| ~~hoverToContent~~ | `boolean` | false | 可选,是否允许鼠标从宿主移动到内容上,仅需要在 trigger 为 hover 的时候设置(`已废弃`) | [延时触发](demo#hover-delay-time) | -| ~~hoverDelayTime~~ | `number` | 0 | 可选,仅需要在 trigger 为 hover 的时候设置鼠标从宿主移开后到隐藏 popover 的延迟时间,以便鼠标移动到内容上,单位`ms` (`已废弃,请使用mouseLeaveDelay`) | [延时触发](demo#hover-delay-time) | -| mouseEnterDelay | `number` | 150 | 可选,仅需要在 trigger 为 hover 的时候,设置鼠标移入后延时多少才显示 Popover,单位是 `ms` | [延时触发](demo#hover-delay-time) | -| mouseLeaveDelay | `number` | 100 | 可选,仅需要在 trigger 为 hover 的时候,设置鼠标移出后延时多少才隐藏 popover,单位是 `ms` | [延时触发](demo#hover-delay-time) | - - -# 接口 & 类型定义 - -### PositionType - -```ts -export type PositionType = - | 'left' - | 'right' - | 'top' - | 'bottom' - | 'bottom-left' - | 'bottom-right' - | 'top-left' - | 'top-right' - | 'left-top' - | 'left-bottom' - | 'right-top' - | 'right-bottom'; -``` diff --git a/devui/popover/doc/api-en.md b/devui/popover/doc/api-en.md deleted file mode 100644 index 927375d1f4d2adad48bbf72f4c6bdc0746005940..0000000000000000000000000000000000000000 --- a/devui/popover/doc/api-en.md +++ /dev/null @@ -1,55 +0,0 @@ -# How to use - -Import into module: - -```ts -import { PopoverModule } from 'ng-devui/popover'; -``` - -In the page: - -```html - -``` - -# dPopover - -## dPopover parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------------------: | :--------------------------------------------------------: | :--------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| content | `string\|HTMLElement\|TemplateRef` | -- | Required. The display content of the pop-up box or template reference | [Basic Usage](demo#basic-usage) | -| visible | `boolean` | false | Optional. Initial pop-up status of the pop-up dialog box | [Manual Control Display ](demo#manual-control-display) | -| trigger | `hover'\|'click'` | 'click' | Pop-up message triggering mode | [Delay Trigger](demo#hover-delay-time) | -| controlled | `boolean` | false | Optional. Specifies whether to trigger a dialog box in `trigger` mode | [Basic Usage](demo#basic-usage) | -| position | [`PositionType`](#positiontype) `\| PositionType[]` | ['top', 'right', 'bottom', 'left'] | Optional. Specifies the content pop-up direction. For example, top-left indicates the content pop-up direction, and left indicates the left-aligned content. If the alignment direction is not set, the default value is centered. If an array is passed in, a direction is selected adaptively in the array order | [Position](demo#position) | -| popType | `'success' \| 'error' \| 'warning' \| 'info' \| 'default'` | 'default' | Optional. Which indicates the type of the pop-up box with different styles | [Basic Usage](demo#basic-usage) | -| popMaxWidth | `number` | -- | Optional. Limit the maximum width of the pop-up box (`px`) | [Custom Tips](demo#custom-prompt-content) | -| showAnimate | `boolean` | false | Optional. Whether to display animation | [Basic Usage](demo#basic-usage) | -| appendToBody | `boolean` | true | Optional. The default value is true. If the width and height of the outer layer of the element bound to the popover are insufficient, the overflow is hidden and the popover dialog box is not hidden | [Basic Usage](demo#basic-usage) | -| zIndex | `number` | 1060 | Optional. Z-index value, which is used to manually control the height of the layer | [Custom Tips](demo#custom-prompt-content) | -| scrollElement | `Element` | window | Optional. The default value is `window`. This parameter needs to be transferred only when the page scrolling is not on `window` and the attribute of `appendToBody` is `true` | [Parent Container Settings](demo#parent-container-settings) | -| ~~hoverToContent~~ | `boolean` | false | Optional. Whether to allow the cursor to be moved from the host to the content. This parameter is set only when trigger is set to hover (`deprecated`) | [Delay Trigger](demo#hover-delay-time) | -| ~~hoverDelayTime~~ | `number` | 0 | Optional. You need to set the delay from moving the cursor to hiding the popover only when trigger is set to hover so that the cursor can be moved to the content. The unit is `ms` (`deprecated,Use mouseLeaveDelay`) | [Delay Trigger](demo#hover-delay-time) | -| mouseEnterDelay | `number` | 150 | Optional. Only when the type of trigger is hover. Delay for displaying Popover after the mouse is enter. The unit is `ms` | [Delay Trigger](demo#hover-delay-time) | -| mouseLeaveDelay | `number` | 100 | Optional. Only when the type of trigger is hover. Delay for hiding Tooltip after the mouse is leave. The unit is `ms` | [Delay Trigger](demo#hover-delay-time) | - -# Interface & Type Definition - -### PositionType - -```ts -export type PositionType = - | 'left' - | 'right' - | 'top' - | 'bottom' - | 'bottom-left' - | 'bottom-right' - | 'top-left' - | 'top-right' - | 'left-top' - | 'left-bottom' - | 'right-top' - | 'right-bottom'; -``` diff --git a/devui/popover/popover.tsx b/devui/popover/popover.tsx deleted file mode 100644 index acc5cc7925909e0367c90aa86e4db0bf5b032ae4..0000000000000000000000000000000000000000 --- a/devui/popover/popover.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-popover', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-popover
    - } - } -}) \ No newline at end of file diff --git a/devui/progress/demo/progress-demo.tsx b/devui/progress/demo/progress-demo.tsx deleted file mode 100644 index 5fd16814548740f46825910e9cc2b55c361d50bd..0000000000000000000000000000000000000000 --- a/devui/progress/demo/progress-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-progress-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-progress-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/progress/demo/progress.route.ts b/devui/progress/demo/progress.route.ts deleted file mode 100644 index 4acd43fe89c64261ff9d7ca0a127b0dd6b60577f..0000000000000000000000000000000000000000 --- a/devui/progress/demo/progress.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ProgressDemoComponent from './progress-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ProgressDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/progress/doc/api-cn.md b/devui/progress/doc/api-cn.md deleted file mode 100644 index 9b3ea2f177ab67dc8281bd6b65ef3209be984389..0000000000000000000000000000000000000000 --- a/devui/progress/doc/api-cn.md +++ /dev/null @@ -1,23 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { ProgressModule } from 'ng-devui/progress'; -``` -在页面中使用: -```html - -``` - -# d-progress - -## d-progress 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------: | :-------: | :-------: | :------------------------------------------------------- | ---------------------------------------------- | -| percentage | `number` | 0 | 可选,进度条的值最大为 100 | [基本用法](demo#basic-usage) | -| percentageText | `string` | -- | 可选,进度条当前值的文字说明比如:'30%' \| '4/5' | [基本用法](demo#basic-usage) | -| barbgcolor | `string` | '#5170ff' | 可选,进度条的颜色显示,默认为天蓝色 | [基本用法](demo#basic-usage) | -| height | `string` | '20px' | 可选,进度条的高度值,默认值为 20px | [基本用法](demo#basic-usage) | -| isCircle | `boolean` | false | 可选, 显示进度条是否为圈形 | [圆环用法](demo#circle-usage) | -| strokeWidth | `number` | 6 | 可选,设置圈形进度条宽度,单位是进度条与画布宽度的百分比 | [圆环用法](demo#circle-usage) | -| showContent | `boolean` | true | 可选,设置圈形进度条内是否展示内容 | [圆环用法](demo#circle-usage) | diff --git a/devui/progress/doc/api-en.md b/devui/progress/doc/api-en.md deleted file mode 100644 index 5343ceebdc1e8a1c70711d80d6386bef43f4c0d9..0000000000000000000000000000000000000000 --- a/devui/progress/doc/api-en.md +++ /dev/null @@ -1,23 +0,0 @@ -# How To Use -Import in module: -```ts -import { ProgressModule } from 'ng-devui/progress'; -``` -In the page: -```html - -``` - -# d-progress - -## d-progress parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------: | :-------: | :-------: | :------------------------------------------------------- | ---------------------------------------------- | -| percentage | `number` | 0 | Optional. The maximum value of the progress bar is 100. | [Basic Usage](demo#basic-usage) | -| percentageText | `string` | -- | Optional. Text description of the current value of the progress bar, for example, '30%'\| '4/5' | [Basic Usage](demo#basic-usage) | -| barbgcolor | `string` | '#5170ff' | Optional. Color of the progress bar. The default value is sky blue. | [Basic Usage](demo#basic-usage) | -| height | `string` | '20px' | Optional. The default value is 20px. | [Basic Usage](demo#basic-usage) | -| isCircle | `boolean` | false | Optional. Whether the progress bar is displayed in a circle. | [Circle Usage](demo#circle-usage) | -| strokeWidth | `number` | 6 | Optional. Sets the width of the progress bar. The unit is the percentage of the progress bar to the width of the canvas. | [Circle Usage](demo#circle-usage) | -| showContent | `boolean` | true | Optional. Sets whether to display content in the circle progress bar. | [Circle Usage](demo#circle-usage) | diff --git a/devui/progress/progress.tsx b/devui/progress/progress.tsx deleted file mode 100644 index 1604e378a14d76b7ff3cf53b7c628f5199fae5fb..0000000000000000000000000000000000000000 --- a/devui/progress/progress.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-progress', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-progress
    - } - } -}) \ No newline at end of file diff --git a/devui/quadrant-diagram/demo/quadrant-diagram-demo.tsx b/devui/quadrant-diagram/demo/quadrant-diagram-demo.tsx deleted file mode 100644 index 79ab887a52c31adc478dc8ee85e8afa8025120a4..0000000000000000000000000000000000000000 --- a/devui/quadrant-diagram/demo/quadrant-diagram-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-quadrant-diagram-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-quadrant-diagram-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/quadrant-diagram/demo/quadrant-diagram.route.ts b/devui/quadrant-diagram/demo/quadrant-diagram.route.ts deleted file mode 100644 index a52c468a0b87aa84ca0ed9e0e3b5132f6f5d80b1..0000000000000000000000000000000000000000 --- a/devui/quadrant-diagram/demo/quadrant-diagram.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import QuadrantDiagramDemoComponent from './quadrant-diagram-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: QuadrantDiagramDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/quadrant-diagram/doc/api-cn.md b/devui/quadrant-diagram/doc/api-cn.md deleted file mode 100644 index 336155ae5c41dbc8b5362275376dc2238bd10a89..0000000000000000000000000000000000000000 --- a/devui/quadrant-diagram/doc/api-cn.md +++ /dev/null @@ -1,127 +0,0 @@ -## 引入 - -当前组件为实验性组件,需要按需引入,路径如下: - -``` -import { QuadrantDiagramModule } from 'ng-devui/experimental/quadrant-diagram'; -``` - -### d-quadrant-diagram 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-----------------: | :------------------------: | :------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -| view | `IViewConfigs` | {height:900,width:950} | 可选,指定象限图所占宽高,由于需要计算坐标轴及象限区域,值必须为具体数字,若需要根据容器大小变更,建议使用 document 相关方法计算出实际值后传入 | [配置自定义象限图](demo#custom-quadrant) | -| axisConfigs | `IAxisConfigs` | 参考下方`DEFAULT_AXIS_CONFIGS` | 可选,设置坐标轴相关属性,具体配置参数意义参考下方`IAxisConfigs` | [配置自定义象限图](demo#custom-quadrant) | -| showQuadrants | `boolean` | true | 可选,是否显示四个象限区域 | -| quadrantConfigs | `Array` | 参考下方`DEFAULT_QUADRANT_CONFIGS` | 可选,设置四个象限区域的相关属性,数组中数据的顺序分别代表第一象限、第二象限、第三象限、第四象限,具体配置参数意义参考下方`IQuadrantConfigs` | [配置自定义象限图](demo#custom-quadrant) | -| labelData | `Array` | [] | 可选,指定警告提示的样式 | [基本用法](demo#basic-usage) | -| currentLabelSize | `labelSize` | 'large' | 可选,设置当前的标签尺寸,`'small'`表现为点,`'normal'`表现为含有标题的标签,`'large'`表现为含有标题和进度条的标签 | -| smallLabelTemplate | `TemplateRef` | -- | 可选,自定义`currentLabelSize='small'`时的标签样式 | -| normalLabelTemplate | `TemplateRef` | -- | 可选,自定义`currentLabelSize='normal'`时的标签样式 | -| largeLabelTemplate | `TemplateRef` | -- | 可选,自定义`currentLabelSize='large'`时的标签样式 | -| diagramId | `string` | 'devui-quadrant-diagram-'+当前组件顺序 | 可选,为象限图组件添加 id 属性,用于区分不同实例 | [基本用法](demo#basic-usage) | -| dropScope | `string` | 'default' | 可选, 限制 drop 的位置,必须匹配对应的 dragScope ,详情参考`DragDropAPI` | [配置自定义象限图](demo#custom-quadrant) | - -### d-quadrant-diagram 事件 - -| 参数 | 类型 | 描述 |跳转 Demo | -| :-------------: | :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:-----------------: | -| dropEvent | `EventEmitter` | 可选,拖拽放置时的触发事件,返回值`{ dragData: e.dragData, xAxisValue: xAxisValue, yAxisValue: yAxisValue }` ,分别对应当前标签数据,标签放置的 x 值,标签放置的 y 值 | [基本用法](demo#basic-usage) | -| zoomOutEvent | `EventEmitter` | 可选,点击缩小按钮的触发事件,返回值为当前的标签尺寸 | | -| zoomInEvent | `EventEmitter` | 可选,点击放大按钮的触发事件,返回值为当前的标签尺寸 | | -| fullScreenEvent | `EventEmitter` | 可选,点击全屏按钮的触发事件,返回值为当前的是否是全屏状态 | | - -### d-quadrant-diagram 相关类型定义及默认值如下 - -```typescript -export interface IAxisConfigs { - tickWidth?: number; // 刻度的宽(高)度,默认为10 - spaceBetweenLabelsAxis?: number; // 刻度值和坐标轴之间的距离,默认为20 - xAxisLabel?: string; // X轴名称,默认值为'紧急度' - yAxisLabel?: string; // Y轴名称,默认值为'重要度' - axisMargin?: number; // 右侧留出的空白区域 - xWeight?: number; // X轴权重,默认值为1 - yWeight?: number; // Y轴权重,默认值为1 - xAxisRange?: IRangeConfigs; // X轴的坐标值范围和间距设置,默认值为{min:0,max:100,step:10} - yAxisRange?: IRangeConfigs; // Y轴的坐标值范围和间距设置,默认值为{min:0,max:100,step:10} - originPosition?: { - left: number; - bottom: number; - }; // 原点的位置设置,默认值为{left:30,bottom:30} -} -export interface IQuadrantConfigs { - backgroundColor?: any; - color?: any; - title?: string; - top?: number; - left?: number; -} -export interface ILabelDataConfigs { - x: number; // X轴坐标值 - y: number; // Y轴坐标值 - title: string; // 标签的名称 - content?: string; // 鼠标悬浮在标签上时的提示内容 - progress?: number; // 标签对应事项的进度 - [propName: string]: any; // 其他数据 -} - -export interface IViewConfigs { - height: number; // 象限图高度 - width: number; // 象限图宽度 -} - -export interface IRangeConfigs { - min: number; // 坐标轴起始值 - max: number; // 坐标轴终止值 - step: number; // 坐标轴刻度值的间隔 -} - -export type labelSize = 'small' | 'normal' | 'large'; - -export const DEFAULT_AXIS_CONFIGS = { - tickWidth: 10, - spaceBetweenLabelsAxis: 20, - xAxisLabel: '紧急度', - yAxisLabel: '重要度', - xAxisRange: { - min: 0, - max: 100, - step: 10, - }, - yAxisRange: { - min: 0, - max: 50, - step: 5, - }, - originPosition: { - left: 30, - bottom: 30, - }, - axisMargin: 50, - xWeight: 1, - yWeight: 1, -}; -export const DEFAULT_QUADRANT_CONFIGS = [ - { title: '重要紧急' }, - { title: '重要不紧急' }, - { title: '不重要不紧急' }, - { title: '不重要紧急' }, -]; -``` - -```xml - - - -``` - -labelData: 传入的 labelData 数据 - -通过使用`[style.top.px]="labelInstance.getLabelTopValue(yAxisValue,offsetY)"`设置当前标签的 top 位置,其中 yAxisValue 为 y 轴坐标,offsetY 为偏移量,一般取标签高度的一半 -通过使用`[style.left.px]="labelInstance.getLabelLeftValue(xAxisValue,offsetX)"`设置当前标签的 left 位置,其中 yAxisValue 为 x 轴坐标,offsetX 为偏移量,一般取标签宽度度的一半 - -### d-quadrant-diagram 设计原则 - -#### 坐标值的确定 - -标签的坐标轴是根据标签中心点的位置所得出 diff --git a/devui/quadrant-diagram/doc/api-en.md b/devui/quadrant-diagram/doc/api-en.md deleted file mode 100644 index b66c46a304a4fc42eba1adec2eff402886ffde0e..0000000000000000000000000000000000000000 --- a/devui/quadrant-diagram/doc/api-en.md +++ /dev/null @@ -1,127 +0,0 @@ -## Import - -The current component is an experimental component and needs to be introduced as required. The path is as follows: - -``` -import {QuadrantDiagramModule} from' ng-devui/experimental/quadrant-diagram'; -``` - -### d-quadrant-diagram parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------------: | :------------------------: | :------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -| view | `IViewConfigs` | {height:900,width:950} | Optional. Specifies the width and height of the quadrant map. The value must be a specific number because the coordinate axis and quadrant area need to be calculated. If you need to change the value based on the container size, you are advised to use the document method to calculate the actual value and then transfer the value. | [Customize](demo#custom-quadrant) | -| axisConfigs | `IAxisConfigs` | Set the attributes of the coordinate axis by referring to `DEFAULT_AXIS_CONFIGS` | For details about the configuration parameters, see `IAxisConfigs` | [Customize](demo#custom-quadrant) | -| showQuadrants | `boolean` | true | Optional. Indicates whether to display four quadrants. | -| quadrantConfigs | `Array` | Set the attributes of the four quadrants by referring to `DEFAULT_QUADRANT_CONFIGS` | Optional. The sequence of data in the array indicates the first quadrant, second quadrant, third quadrant, and fourth quadrant respectively. For details about the parameter meaning, see `IQuadrantConfigs` | [Customize](demo#custom-quadrant) |. -| labelData | `Array` | [] | Optional. Specifies the style of the warning prompt. | [Basic Usage](demo#basic-usage) | -| currentLabelSize | `labelSize` | 'large' | Optional. Sets the current label size. The value `small'` is represented as a dot, and the value `normal'` is represented as a label with a title, `large'` is a label with a title and progress bar. | -| smallLabelTemplate | `TemplateRef` | -- |: Optional. Customize the label style when `currentLabelSize='small '`. | -| normalLabelTemplate | `TemplateRef` | -- |: Optional. Customize the label style when `currentLabelSize='normal '`. | -| largeLabelTemplate | `TemplateRef` | -- |: Optional. Customize the label style when `currentLabelSize='large'`. | -| diagramId | `string` | 'devui-quadrant-diagram-'+current component sequence | Optional. Add the ID attribute to the quadrant component to distinguish different instances. | [Basic Usage](demo#basic-usage) | -| dropScope | `string` | 'default' | Optional. This parameter specifies the drop position. The value must match the corresponding dragScope. For details, see `DragDropAPI` | [Customize](demo#custom-quadrant) |. - -### d-quadrant-diagram event - -| Parameter | Type | Description | Jump to Demo | -| :-------------: | :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:-----------------: | -| dropEvent | `EventEmitter` | Optional. Triggered event when a tag is dragged. The return value is `{dragData: e.dragData, xAxisValue: xAxisValue, yAxisValue: yAxisValue}`, which corresponds to the current tag data, x value of the tag, and y value of the tag. | [Basic Usage](demo#basic-usage) | -| zoomOutEvent | `EventEmitter` | Optional. Triggering event when the zoom-in button is clicked. The return value is the current label size. | -| zoomInEvent | `EventEmitter` | OptionaL. Triggering event when the zoom-in button is clicked. The return value is the current label size. | -| fullScreenEvent | `EventEmitter` | Optional. Triggering event when the full-screen button is clicked. The return value is whether the current status is full-screen. | - -### d-quadrant-diagram: - -```typescript -export interface IAxisConfigs { -tickWidth? : number; // Scale width (height). The default value is 10. -spaceBetweenLabelsAxis?: number; // Distance between the scale value and the coordinate axis. The default value is 20. -xAxisLabel? : string; // X axis name. The default value is Critical. -yAxisLabel? : string; // Y axis name. The default value is Importance. -axisMargin? : number; // Blank area on the right -xWeight? : number; // Weight of the X axis. The default value is 1. -yWeight? : number; // Y-axis weight. The default value is 1. -Set the coordinate value range and spacing of the xAxisRange?: IRangeConfigs; // X axis. The default value is {min:0,max:100,step:10}. -Set the coordinate value range and spacing of the yAxisRange?: IRangeConfigs; // Y axis. The default value is {min:0,max:100,step:10}. -originPosition? : { -left: number; -bottom: number; -}; // Origin position. The default value is {left:30,bottom:30}. -} -export interface IQuadrantConfigs { -backgroundColor? : any; -color? : any; -title? : string; -top? : number; -left? : number; -} -export interface ILabelDataConfigs { -x: number; // X-axis value -y: number; // Y-axis value -title: string; // Tag name -content? : string; // Message displayed when the cursor is hovered on the label. -progress? : number; // Progress of the item corresponding to the label -[propName: string]: any; // Other data -} - -export interface IViewConfigs { -height: number; // Quadrant image height -width: number; // Quadrant image width -} - -export interface IRangeConfigs { -min: number; // Start value of the coordinate axis. -max: number; // End value of the coordinate axis. -step: number; // Interval between scale values on the coordinate axis. -} - -export type labelSize = 'small' | 'normal' | 'large'; - -export const DEFAULT_AXIS_CONFIGS = { -tickWidth: 10, -spaceBetweenLabelsAxis: 20, -xAxisLabel: 'Urgent', -yAxisLabel: 'Importance', -xAxisRange: { -min: 0, -max: 100, -step: 10, -}, -yAxisRange: { -min: 0, -max: 50, -step: 5, -}, -originPosition: { -left: 30, -bottom: 30, -}, -axisMargin: 50, -xWeight: 1, -yWeight: 1, -}; -export const DEFAULT_QUADRANT_CONFIGS = [ -{title:'Major and Critical'}, -{title:'Major but not critical'}, -{title:'Not critical'}, -{title:'Not critical'}, -]; -``` - -```xml - - - -``` - -labelData: input labelData data. - -Use `[style.top.px]="labelInstance.getLabelTopValue(yAxisValue, offsetY)"` to set the top position of the current label. yAxisValue indicates the y axis, and offsetY indicates the offset. Generally, the value is half of the label height. -Use `[style.left.px]="labelInstance.getLabelLeftValue(xAxisValue, offsetX)"` to set the left position of the current label. yAxisValue indicates the x coordinate, and offsetX indicates the offset. Generally, the value is half of the width of the label. - -### D-quadrant-diagram Design Principles - -#### Determining Coordinates - -The axis of the label is determined by the position of the label's center point. diff --git a/devui/quadrant-diagram/quadrant-diagram.tsx b/devui/quadrant-diagram/quadrant-diagram.tsx deleted file mode 100644 index 9370e36dbffe88108cdf39b037f59b7a40acd90c..0000000000000000000000000000000000000000 --- a/devui/quadrant-diagram/quadrant-diagram.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-quadrant-diagram', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-quadrant-diagram
    - } - } -}) \ No newline at end of file diff --git a/devui/radio/demo/radio-demo.tsx b/devui/radio/demo/radio-demo.tsx deleted file mode 100644 index d029d9aca009699237f764e63a240bd1b83de32d..0000000000000000000000000000000000000000 --- a/devui/radio/demo/radio-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-radio-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-radio-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/radio/demo/radio.route.ts b/devui/radio/demo/radio.route.ts deleted file mode 100644 index f025bf24e596cc73802406c6b6a036bc68653dfa..0000000000000000000000000000000000000000 --- a/devui/radio/demo/radio.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import RadioDemoComponent from './radio-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: RadioDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/radio/doc/api-cn.md b/devui/radio/doc/api-cn.md deleted file mode 100644 index 95ac2c22ab6ac0c7a4ad16ffd62904cf161ae795..0000000000000000000000000000000000000000 --- a/devui/radio/doc/api-cn.md +++ /dev/null @@ -1,47 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { RadioModule } from 'ng-devui'; -``` - -在页面中使用 - -```html - - -``` - -# d-radio -## d-radio 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-----------------------------: | :---: | :------------------------------------------------------------------------------ | ------------------------------------ | -| name | `string` | -- | 必选,单选项名称 | [互相独立的单选项](demo#basic-usage) | -| value | `string` | -- | 必选,单选项值 | [互相独立的单选项](demo#basic-usage) | -| disabled | `boolean` | false | 可选,是否禁用该单选项 | [禁用](demo#disabled) | | -| beforeChange | `Function \| Promise \| Observable` | -- | 可选,radio 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 radio 切换 | [回调切换](demo#condition-change) | - -## d-radio 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :-----------: | :-----------------: | :------------------------------------------ | ------------------------------------ | -| ngModelChange | `EventEmitter` | Form 事件,单选项值改变时触发,返回选中的值 | [互相独立的单选项](demo#basic-usage) | - - -# d-radio-group -## d-radio-group 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-----------------------------: | :------: | :-------------------------------------------------------------------------------------------: | -------------------------------------- | -| name | `string` | -- | 必选,单选项名称 (radio 唯一标识符) | [竖向排列](demo#vertical) | -| value | `array` | -- | 必选,单选数据组 | [竖向排列](demo#vertical) | -| cssStyle | `'row' \| 'column'` | 'column' | 可选,设置横向或纵向排列 | [横向排列](demo#horizontal) | | -| beforeChange | `Function \| Promise \| Observable` | -- | 可选,radio-group 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 radio-group 的切换 | [回调切换](demo#condition-radio-group) | - -## d-radio-group 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----: | :-----------------: | :------------------------------- | ------------------------- | -| change | `EventEmitter` | 单选项值改变时触发,返回选中的值 | [竖向排列](demo#vertical) | diff --git a/devui/radio/doc/api-en.md b/devui/radio/doc/api-en.md deleted file mode 100644 index ea254c90f0202613cc16417ec064241e47c90c4e..0000000000000000000000000000000000000000 --- a/devui/radio/doc/api-en.md +++ /dev/null @@ -1,46 +0,0 @@ -# How to use - -Import into module: - -```ts -import { RadioModule } from 'ng-devui'; -``` - -In the page: - -```html - - -``` - -# d-radio -## d-radio Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-----------------------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | -| name | `string` | -- | Required. Single-option name | [Independent Radios](demo#basic-usage) | -| value | `string` | -- | Required. Single-option value | [Independent Radios](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Whether to disable this option. | [Disabled Radios](demo#disabled) | | -| beforeChange | `Function \| Promise \| Observable` | -- | Callback function before radio switching, which is optional. The return type is boolean. If false is returned, radio switching is prevented. | [Switch with Condition](demo#condition-change) | - -## d-radio Event - -| Event | Type | Description | Jump Demo | -| :-----------: | :-----------------: | :------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | -| ngModelChange | `EventEmitter` | Form event. This event is triggered when the value of a single option changes. The selected value is returned. | [Independent Radios](demo#basic-usage) | - -# d-radio-group -## d-radio-group Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-----------------------------: | :------: | :------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -| name | `string` | -- | Required. Single-option name (unique identifier of the radio) | [Vertical Arrangement](demo#vertical) | -| value | `array` | -- | Required. Single-choice data group | [Vertical Arrangement](demo#vertical) | -| cssStyle | `'row' \| 'column'` | 'column' | Optional. Set the horizontal or vertical arrangement | [Horizontal Arrangement](demo#horizontal) | | -| beforeChange | `Function \| Promise \| Observable` | -- | Callback function before radio-group switching. The return value is of the boolean type. If false is returned, radio-group switching is prevented. | [Switch With Condition in A Radio Group](demo#condition-radio-group) | - -## d-radio-group Event - -| Event | Type | Description | Jump to Demo | -| :----: | :-----------------: | :-------------------------------------------------------------------------------------- | ------------------------------------- | -| change | `EventEmitter` | Triggered when the value of a single option changes and the selected value is returned. | [Vertical Arrangement](demo#vertical) | diff --git a/devui/radio/radio.tsx b/devui/radio/radio.tsx deleted file mode 100644 index 4b78f0b776dd32d4ae58da009ac0b27163fdeb9d..0000000000000000000000000000000000000000 --- a/devui/radio/radio.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-radio', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-radio
    - } - } -}) \ No newline at end of file diff --git a/devui/rate/demo/rate-demo.tsx b/devui/rate/demo/rate-demo.tsx deleted file mode 100644 index a735c81a2851199233e1ef84146a4ae5b16466d1..0000000000000000000000000000000000000000 --- a/devui/rate/demo/rate-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-rate-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-rate-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/rate/demo/rate.route.ts b/devui/rate/demo/rate.route.ts deleted file mode 100644 index ce96b2192d0c03143e61cd9ef89cd6c4148a1bfe..0000000000000000000000000000000000000000 --- a/devui/rate/demo/rate.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import RateDemoComponent from './rate-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: RateDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/rate/doc/api-cn.md b/devui/rate/doc/api-cn.md deleted file mode 100644 index 5a4e97330499586e33c8e637f9b27e1806a7c66a..0000000000000000000000000000000000000000 --- a/devui/rate/doc/api-cn.md +++ /dev/null @@ -1,22 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { RateModule } from 'ng-devui/rate'; -``` - -在页面中使用: -```html - -``` -# Rate - -## d-rate 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------: | :-----------------------------: | :---: | :------------------------------------------------------- | ------------------------------------------------------ | -| read | `boolean` | false | 可选,设置是否为只读模式,只读模式无法交互 | [只读模式](demo#read-only-mode) | -| count | `number` | 5 | 可选,设置总等级数 | [只读模式](demo#read-only-mode) | -| type | `'success'\|'warning'\|'error'` | -- | 可选,设置当前评分的类型,不同类型对应不同颜色 | [使用type参数](demo#using-the-type-parameter) | -| color | `string` | -- | 可选,星星颜色 | [动态模式-自定义](demo#dynamic-mode-Custom) | -| icon | `string` | -- | 可选,评分图标的样式,只支持 devUI 图标库中所有图标 | [动态模式](demo#dynamic-mode) | -| character | `string` | -- | 可选,评分图标的样式,icon 与 character 只能设置其中一个 | [动态模式-自定义](demo#dynamic-mode-Custom) | diff --git a/devui/rate/doc/api-en.md b/devui/rate/doc/api-en.md deleted file mode 100644 index 75b4451488eb4dcaac861e0080e8ec1ef6057dc7..0000000000000000000000000000000000000000 --- a/devui/rate/doc/api-en.md +++ /dev/null @@ -1,22 +0,0 @@ -# How to use -Import into module: -```ts -import { RateModule } from 'ng-devui/rate'; -``` - -In the page: -```html - -``` -# Rate - -## d-rate parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :-----------------------------: | :---: | :------------------------------------------------------- | ------------------------------------------------------ | -| read | `boolean` | false | Optional. This parameter specifies whether to enable read-only mode. In read-only mode, interaction is not supported. | [Read-only Mode](demo#read-only-mode) | -| count | `number` | 5 | Optional. Sets the total number of levels. | [Read-only Mode](demo#read-only-mode) | -| type | `'success'\|'warning'\|'error'` | -- | Optional. Set the current rating type. Different types correspond to different colors. | [Use the type parameter](demo#using-the-type-parameter) | -| color | `string` | -- | Optional. Star color. | [Dynamic Mode-Custom](demo#dynamic-mode-Custom) | -| icon | `string` | -- | Optional. Style of the rating icon. Only all icons in the DevUI icon library are supported. | [Dynamic Mode](demo#dynamic-mode) | -| character | `string` | -- | Optional. Scoring icon style. Only one of icon and character can be set. | [Dynamic Mode-Custom](demo#dynamic-mode-Custom) | diff --git a/devui/read-tip/demo/read-tip-demo.tsx b/devui/read-tip/demo/read-tip-demo.tsx deleted file mode 100644 index e9d918c79a0fc052deab4bdaf13e355c843620fc..0000000000000000000000000000000000000000 --- a/devui/read-tip/demo/read-tip-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-read-tip-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-read-tip-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/read-tip/demo/read-tip.route.ts b/devui/read-tip/demo/read-tip.route.ts deleted file mode 100644 index f839e91ef7ca473cbc492d45ee97b589d7f1b412..0000000000000000000000000000000000000000 --- a/devui/read-tip/demo/read-tip.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ReadTipDemoComponent from './read-tip-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ReadTipDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/read-tip/doc/api-cn.md b/devui/read-tip/doc/api-cn.md deleted file mode 100644 index a4686b94eae69848229b3dad242bd6c82745d63a..0000000000000000000000000000000000000000 --- a/devui/read-tip/doc/api-cn.md +++ /dev/null @@ -1,59 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { ReadTipModule } from 'ng-devui/read-tip'; -``` - -在页面中使用: - -```html - ... -``` - -# dReadTip - -## dReadTip 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :---------------------------------: | :-------------------------: | :------------------------------ | -------------------------------------------- | -| readTipOptions | [`ReadTipOptions`](#readtipoptions) | [详见下方](#readtipoptions) | 必选,配置提示选项 | [基本用法](demo#basic) | -| readTipOptions.rules | [`ReadTipRules`](#readtiprules) | -- | 必选,配置 readtip 内容 | [包括多个提示的 readtip](demo#multi-readtip) | -| contentTemplate | `TemplateRef` | -- | 可选,传入模板显示 readtip 内容 | [传入模板显示内容](demo#readtip-template) | - -# 接口 & 类型定义 - -### ReadTipOptions - -```ts -export interface ReadTipOptions { - trigger?: 'hover' | 'click'; // 默认值是 hover - showAnimate?: boolean; // 默认值是 false - mouseenterTime?: number; // 默认值是 100 - mouseleaveTime?: number; // 默认值是 100 - position?: PositionType | PositionType[]; // 默认值是 'top' - overlayClassName?: string; // 默认值为空字符串 - rules: ReadTipRules; -} -``` - -### ReadTipRules - -```ts -export type ReadTipRules = ReadTipRule | ReadTipRule[]; - -export interface ReadTipRule { - key?: string; - selector: string; - trigger?: 'hover' | 'click'; // 可以继承自 ReadTipOptions - title?: string; - content?: string; - showAnimate?: boolean; // 可以继承自 ReadTipOptions - mouseenterTime?: number; // 可以继承自 ReadTipOptions - mouseleaveTime?: number; // 可以继承自 ReadTipOptions - position?: PositionType | PositionType[]; // 可以继承自 ReadTipOptions - overlayClassName?: string; // 可以继承自 ReadTipOptions - dataFn?: ({ element, rule: ReadTipRule }) => Observable<{ title?: string; content?: string; template?: TemplateRef }>; -} -``` diff --git a/devui/read-tip/doc/api-en.md b/devui/read-tip/doc/api-en.md deleted file mode 100644 index 99998286a601776cdb68a491d9fc184cb56794a2..0000000000000000000000000000000000000000 --- a/devui/read-tip/doc/api-en.md +++ /dev/null @@ -1,59 +0,0 @@ -# How to use - -Import into module: - -```ts -import { ReadTipModule } from 'ng-devui/read-tip'; -``` - -In the page: - -```html - ... -``` - -# dReadTip - -## dReadTip parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :---------------------------------: | :-----: | :------------------------------------------- | ------------------------------------------------------ | -| readTipOptions | [`ReadTipOptions`](#readtipoptions) | -- | Required. Set readtip options. | [Basic Usage](demo#basic-usage) | -| readTipOptions.rules | [`ReadTipRules`](#readtiprules) | -- | Option. Set the content of readtip | [Include Multiple Readtip](demo#multi-readtip) | -| contentTemplate | `TemplateRef` | -- | Options. Using template to customize content | [Display Content with Template](demo#readtip-template) | - -# Interface & Type Definition - -### ReadTipOptions - -```ts -export interface ReadTipOptions { - trigger?: 'hover' | 'click'; // default is hover - showAnimate?: boolean; // default is false - mouseenterTime?: number; // default is 100 - mouseleaveTime?: number; // default is 100 - position?: PositionType | PositionType[]; // default is 'top' - overlayClassName?: string; // default is '' - rules: ReadTipRules; -} -``` - -### ReadTipRules - -```ts -export type ReadTipRules = ReadTipRule | ReadTipRule[]; - -export interface ReadTipRule { - key?: string; - selector: string; - trigger?: 'hover' | 'click'; // can inherit from ReadTipOptions - title?: string; - content?: string; - showAnimate?: boolean; // can inherit from ReadTipOptions - mouseenterTime?: number; // can inherit from ReadTipOptions - mouseleaveTime?: number; // can inherit from ReadTipOptions - position?: PositionType | PositionType[]; // can inherit from ReadTipOptions - overlayClassName?: string; // can inherit from ReadTipOptions - dataFn?: ({ element, rule: ReadTipRule }) => Observable<{ title?: string; content?: string; template?: TemplateRef }>; -} -``` diff --git a/devui/read-tip/read-tip.tsx b/devui/read-tip/read-tip.tsx deleted file mode 100644 index a66e730e66835c5b07f0381d6a1aadd79a6b87a6..0000000000000000000000000000000000000000 --- a/devui/read-tip/read-tip.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-read-tip', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-read-tip
    - } - } -}) \ No newline at end of file diff --git a/devui/search/demo/search-demo.tsx b/devui/search/demo/search-demo.tsx deleted file mode 100644 index 8ca5f9dbbd10ce2a8d12a1bbbdb14ef3d5f4f9dc..0000000000000000000000000000000000000000 --- a/devui/search/demo/search-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-search-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-search-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/search/demo/search.route.ts b/devui/search/demo/search.route.ts deleted file mode 100644 index e8ef9bd3aaef780b97f1e980bbb636263eb3d9f5..0000000000000000000000000000000000000000 --- a/devui/search/demo/search.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import SearchDemoComponent from './search-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: SearchDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/search/doc/api-cn.md b/devui/search/doc/api-cn.md deleted file mode 100644 index ead7e61c5569e69f0ab4b945eb4d65323032c178..0000000000000000000000000000000000000000 --- a/devui/search/doc/api-cn.md +++ /dev/null @@ -1,32 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { SearchModule } from 'ng-devui/search'; -``` - -在页面中使用: -```html - -``` -# Search - -## d-search 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-----------: | :-------: | :---------------------: | :-------------------------------------- | ----------------------------------------------------- | -| size | `string` | '' | 可选,搜索框尺寸,有三种选择 lg、''、sm | [基本用法](demo#basic-usage) | -| placeholder | `string` | 'Please Input keywords' | 可选,输入框的 placeholder | -| maxLength | `number` | Number.MAX_SAFE_INTEGER | 可选,输入框的 max-length | [双向绑定](demo#bidirectional-binding) | -| delay | `number` | 300 | 可选,debounceTime 的延迟 | -| disabled | `boolean` | false | 可选,输入框是否可用 | [基本用法](demo#basic-usage) -| autoFocus | `boolean` | false | 可选,输入框是否自动对焦 | [自动对焦](demo#auto-focus) | -| isKeyupSearch | `boolean` | false | 可选,是否支持输入值立即出发 searchFn | [基本用法](demo#basic-usage) | -| iconPosition | `string` | 'right' | 可选,搜索图标位置,有两种选择'left' / 'right'| [搜索图标左置](demo#icon-left) | -| noBorder | `boolean` | 'false' | 可选,是否显示边框 | [搜索图标左置](demo#icon-left) | -| cssClass | `string` | '' | 可选,支持传入类名到输入框上 | | - -## d-search 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :------: | :------: | :--------------------------------------------------- | ------------------------------------------- | -| searchFn | `string` | 回车或点击搜索按钮触发的回调函数,返回文本框输入的值 | [基本用法](demo#basic-usage) | diff --git a/devui/search/doc/api-en.md b/devui/search/doc/api-en.md deleted file mode 100644 index 0a8bcbfeb0dea115e275a0a7c68f3b98be723002..0000000000000000000000000000000000000000 --- a/devui/search/doc/api-en.md +++ /dev/null @@ -1,32 +0,0 @@ -# How to use -Import into module: -```ts -import { SearchModule } from 'ng-devui/search'; -``` - -In the page: -```html - -``` -# Search - -## d-search parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------: | :-------: | :---------------------: | :-------------------------------------- | ----------------------------------------------------- | -| size | `string` |'' | Optional. Specifies the size of the search box. The options are lg, '', and sm. | [Basic Usage](demo#basic-usage) | -| placeholder | `string` |'Please Input keywords' | Optional. This parameter specifies the placeholder in the input box. | -| maxLength | `number` | Number.MAX_SAFE_INTEGER | Optional. Max-length of the text box. | [Two-way Binding](demo#bidirectional-binding) | -| delay | `number` | 300 | Optional. Delay of debounceTime. | -| disabled | `boolean` | false | Optional. Indicating whether the text box is available. | [Basic Usage](demo#basic-usage) -| autoFocus | `boolean` | false | Optional. Whether to enable autofocus for the text box. | [Auto Focus](demo#auto-focus) | -| isKeyupSearch | `boolean` | false | Optional. Indicates whether to support immediate searchFn after input. | [Basic Usage](demo#basic-usage) | -| iconPosition | `string` | 'right' | Optional. The options are'left' and'right'.| [Left Search Icon](demo#icon-left)| -| noBorder | `boolean` | 'false' | Optional. Specifies whether to display the border. | [Left Search Icon](demo#icon-left) | -| cssClass | `string` |'' | Optional. The class name can be transferred to the text box. | | - -## d-search event - -| Event | Type | Description | Jump to Demo | -| :------: | :------: | :--------------------------------------------------- | ------------------------------------------- | -| searchFn | `string` | Callback function triggered by pressing Enter or clicking the search button to return the value entered in the text box. | [Basic Usage](demo#basic-usage) | diff --git a/devui/search/search.tsx b/devui/search/search.tsx deleted file mode 100644 index 29717923663a07f291ff8eb9b31dccde19fae282..0000000000000000000000000000000000000000 --- a/devui/search/search.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-search', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-search
    - } - } -}) \ No newline at end of file diff --git a/devui/select/demo/select-demo.tsx b/devui/select/demo/select-demo.tsx deleted file mode 100644 index ef734f005bcf4f60c88f7e84536cec2e3cb16fb1..0000000000000000000000000000000000000000 --- a/devui/select/demo/select-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-select-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-select-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/select/demo/select.route.ts b/devui/select/demo/select.route.ts deleted file mode 100644 index c6565f5588821128aa0d9c80e69f9bd8022d4fc3..0000000000000000000000000000000000000000 --- a/devui/select/demo/select.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import SelectDemoComponent from './select-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: SelectDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/select/doc/api-cn.md b/devui/select/doc/api-cn.md deleted file mode 100644 index 7b6472a5255ae0adf75e4d644daedf993316d222..0000000000000000000000000000000000000000 --- a/devui/select/doc/api-cn.md +++ /dev/null @@ -1,96 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```typescript -import { SelectModule } from 'ng-devui/select'; -``` - -在页面中使用: - -```html - -``` - -## d-select - -### d-select 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------------------------------------------: | :-------------------------------------------------: | :----------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| options | `array` | [] | 可选, 和 searchFn 互斥,两者必须有且只有一个。下拉选项资源`string` `object` | [基本用法](demo#basic-usage) | -| isSearch | `boolean` | false | 可选,是否支持过滤搜索 | [使用对象](demo#object-filter) | -| scrollHight | `string` | '300px' | 可选,下拉菜单高度,建议使用 px 作为高度单位 | -| highlightItemClass | `string` | 'bg-grey' | 可选,下拉高亮 css | -| filterKey | `string` | -- | 当传入资源 options 类型为 object 时,必选,针对传入资源 options 的每项对应字段做过滤操作 | [使用对象](demo#object-filter) | -| multiple | `boolean` | false | 可选,是否支持多选 | [自定义搜索功能](demo#custom-search) | -| isSelectAll | `boolean` | false | 可选,是否显示全选 | [全选下拉选项](demo#select-all) | -| readonly | `boolean` | true | 可选,是否可以输入 | [标签化](demo#labelization) | -| size | `string` | '' | 可选,下拉选框尺寸,有三种选择`'lg'`,`''`,`'sm'` | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,是否禁用下拉框 | [禁用](demo#disabled) | -| placeholder | `string` | 'Please Input keywords' | 可选,输入框的 placeholder | [基本用法](demo#basic-usage) | -| searchPlaceholder | `string` | '' | 可选,搜索功能输入框的 placeholder | [自定义搜索功能](demo#custom-search) | -| searchFn | `function` | -- | 可选,搜索函数,当需要自定义下拉选择过滤规则时可以使用 | [自定义搜索功能](demo#custom-search) | -| valueParser | `function` | -- | 可选,决定选择框文字如何显示,默认显示 filterKey 字段或者本身的值 | -| formatter | `function` | -- | 可选,决定下拉框每项文字如何显示,默认显示 filterKey 字段或者本身的值 | -| direction | `'up'\|'down'\|'auto'` | '' | 可选,下拉选框尺寸,有三种选择`'up'`,`'down'`,`'auto'` | [禁用](demo#disabled) | -| overview | `string` | 'border' | 可选,决定选择框样式显示,默认有边框`'border'`,`'underlined'` | [基本用法](demo#basic-usage) | -| enableLazyLoad | `boolean` | false | 可选,是否支持数据懒加载,用于滚动到底部时动态请求数据 | [虚拟滚动 或 懒加载](demo#lazy-load-virtual-scroll) | -| extraConfig | `object` | N/A | 可选, 可输入配置项 参考示例 | [自定义模板](demo#select-template) | -| extraConfig.labelization | `object` | N/A | 可选, 标签化多选结果的配置项,参考示例 | [标签化](demo#labelization) | -| extraConfig.labelization.enable | `boolean` | false | 可选下的必填参数, 是否启用标签化,使用必须置为 true,参考示例 | [标签化](demo#labelization) | -| extraConfig.labelization.overflow | `string` | '' | 可选, 多个标签超出容器时候的预处理行为,值为`'normal' \| 'scroll-y' \| 'multiple-line' \| 'string'` 对应默认隐藏,纵向滚动、自动变多行和自定义类 | [标签化](demo#labelization) | -| extraConfig.labelization.containerMaxHeight | `string` | '1.8em' | 可选, 限制容器最高高度。 多行模式下默认不限制高度,单行模式下默认为 1.8em | -| ~~extraConfig.labelization.containnerMaxHeight~~ | `string` | '1.8em' | 已废弃, 限制容器最高高度。 多行模式下默认不限制高度,单行模式下默认为 1.8em, 请使用`extraConfig.labelization.containerMaxHeight` | -| extraConfig.labelization.labelMaxWidth | `string` | '100%' | 可选下, 限制标签宽度,默认值为行宽的 100% | -| extraConfig.selectedItemWithTemplate | `object` | N/A | 可选,在单选情况下,显示选项使用了 template 的情况下,顶部选中的内容是否也以 template 展示,参考示例 | [自定义模板](demo#select-template) | -| extraConfig.selectedItemWithTemplate.enable | `boolean` | -- | 可选下的必填参数, 是否启用选中项使用模板,使用必须置为 true,参考示例 | [自定义模板](demo#select-template) | -| optionDisabledKey | `string` | '' | 可选,禁用单个选项;当传入资源 options 类型为`Object`,比如设置为`'disabled'`,则当对象的 disabled 属性为 true 时,该选项将禁用;当设置为`''`时不禁用单个选项 | [禁用](demo#disabled) | -| optionImmutableKey | `string` | '' | 可选,禁用单个选项;当传入资源 options 类型为`Object`,比如设置为`'immutable'`,则当对象的 immutable 属性为 true 时,该选项将禁被禁止变更;当设置为`''`时不生效 | [禁用](demo#disabled) | -| noResultItemTemplate | `TemplateRef` | -- | 可选,没有匹配项的展示结果 | -| keepMultipleOrder | `string` | 'user-select' | 可选,`'user-select' \| 'origin'`,配置多选的时候是否维持原数组排序还是用户选择的顺序排序,默认是用户顺序 | [设置已选项顺序源数组顺序或选中顺序](demo#multi-keep-order) | -| customViewTemplate | `TemplateRef` | -- | 可选,支持自定义区域显示内容定制,可以使用 choose 来选择某项,choose 需要传两个必填参数,第一个为选择的选项,第二个为选项在列表的 index 值,event 参数选填,若不填请自行处理冒泡,详见 demo | [自定义区域](demo#custom-area) | -| customViewDirection | `'bottom' \| 'right'\| 'left'` | 'bottom' | 可选, customViewTemplate 所处的相对下拉列表的位置 | [自定义区域方向和选中](demo#custom-area-direction) | -| appendToBody | `boolean` | false | 可选, true 会被附加到 body | [附着到 Body 上](demo#append-to-body) | -| appendToBodyDirections | `Array` | `['rightDown', 'leftDown', 'rightUp', 'leftUp']` | 可选,方向数组优先采用数组里靠前的位置,AppendToBodyDirection 和 ConnectedPosition 请参考 dropdown | [自定义区域方向和选中](demo#custom-area-direction) | -| autoFocus | `boolean` | false | 可选,是否自动聚焦 | -| toggleOnFocus | `boolean` | false | 可选,是否 focus 自动展开下拉列表 | -| width | `number` | -- | 可选,搭配 appendToBody 使用,设置下拉宽度 | [自定义区域方向和选中](demo#custom-area-direction) | -| virtualScroll | `boolean` | false | 可选,是否虚拟滚动,大数据量场景试用 | [虚拟滚动 或 懒加载](demo#lazy-load-virtual-scroll) | -| allowClear | `boolean` | false | 可选, 配置是否允许清空选值,仅单选场景适用 | [允许清空值](demo#allow-clear-value) | -| inputItemTemplate | `TemplateRef` | -- | 可选,自定义模板,若传入,会忽略 ContentChild | | -| ~~~notAutoScroll~~~ | `boolean` | false | `待改名`~~~可选,自动聚焦的时候,自动滚动到 select 位置~~~ | -| templateItemSize | `number` | false | `待完善`可选,模板单条高度, appendToBody 必须为 true | -| loadingTemplateRef | `TemplateRef` | -- | 可选,自定义 loading 模板 | [虚拟滚动 或 懒加载](demo#lazy-load-virtual-scroll) | - -### d-select 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----------: | :-------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -| valueChange | `EventEmitter\|any>` | 可选,输出函数,当选中某个选项项后,将会调用此函数,参数为当前选择项的值 | -| toggleChange | `EventEmitter` | 可选,输出函数,下拉打开关闭 toggle 事件 | [异步加载显示加载中](demo#async-loading) | -| loadMore | `EventEmitter<{instance: SelectComponent, event: ScrollEvent}>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.instance.loadFinish()`结束本次加载, event 为懒加载监听的滚动事件,参考 dLazyLoad | [虚拟滚动 或 懒加载](demo#lazy-load-virtual-scroll) | - -注意: 使用 appendToBody 后需要在有滚动条的地方使用`cdkScrollable` - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import { ScrollDispatchModule } from '@angular/cdk/scrolling'; - -@NgModule({ - imports: [ - // ... - ScrollDispatchModule, - // ... - ] -}) -``` - -```html -
    - -
    -``` diff --git a/devui/select/doc/api-en.md b/devui/select/doc/api-en.md deleted file mode 100644 index 4001d3fd9b4bfbc27290384afff519157d0e91af..0000000000000000000000000000000000000000 --- a/devui/select/doc/api-en.md +++ /dev/null @@ -1,95 +0,0 @@ -# How to use - -Import into module: - -```typescript -import { SelectModule } from 'ng-devui/select'; -``` - -In the page: - -```html - -``` - -## d-select - -### d-select Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------------------------------------: | :-------------------------------------------------: | :-------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| options | `array` | [] | Optional. This parameter and searchFn are mutually exclusive. Only one of them is required. Resource of the drop-down list box: `string` `object` | [Basic Usage](demo#basic-usage) | -| isSearch | `boolean` | false | Optional. indicating whether to support filtering search. | [Use object](demo#object-filter) | -| scrollHight | `string` | '300px' | Optional. Height of the drop-down list box. You are advised to use px as the height unit. | -| highlightItemClass | `string` | 'bg-grey' | Optional. The drop-down list box is highlighted. css | -| filterKey | `string` | -- | Optional. This parameter is required when the input resource options type is object. Filter the fields corresponding to the input resource options. | [Use object](demo#object-filter) | -| multiple | `boolean` | false | Optional. indicating whether to support multiple selections. | [Custom Search](demo#custom-search) | -| isSelectAll | `boolean` | false | Optional. Whether to display all options. | [Select All](demo#select-all) | -| readonly | `boolean` | true | Optional. Whether the value can be entered | [Tagged](demo#labelization) | -| size | `string` | '' | Optional. Size of the drop-down list box. The options are as follows: `'lg'`, `''`, and `'sm'` | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. indicating whether to disable the drop-down list box. | [Disable](demo#disabled) | -| placeholder | `string` | 'Please Input keywords' | Optional. This parameter specifies the placeholder of the input box. | [Basic Usage](demo#basic-usage) | -| searchPlaceholder | `string` | '' | Optional. placeholder in the search text box. | [Custom Search](demo#custom-search) | -| searchFn | `function` | -- | Optional. Search function. You can use this function when you need to customize filtering rules from the drop-down list box. | [Custom Search](demo#custom-search) | -| valueParser | `function` | -- | Optional. This parameter determines how to display the text in the selection box. By default, the filterKey field or its value is displayed. | -| formatter | `function` | -- | Optional. This parameter determines how to display each text in the drop-down list box. By default, the filterKey field or its value is displayed. | -| direction | `'up'\|'down'\|'auto'` | 'down' | Optional. The options are as follows: up, down, and auto. | [Disabled](demo#disabled) | -| overview | `string` | 'border' | Optional. This parameter specifies the selection box style. By default, the border is `'border'`,`'underlined'` | [Basic Usage](demo#basic-usage) | -| enableLazyLoad | `boolean` | false | Optional. Whether to support data lazy loading. It is used to dynamically request data when scrolling to the bottom. | [Virtual scrolling or lazy loading](demo#lazy-load-virtual-scroll) | -| extraConfig | `object` | N/A | Optional. You can enter configuration items. Example | [Customized template](demo#select-template) | -| extraConfig.labelization | `object` | N/A | Optional. It is a configuration item for labeling the multi-selection result. For details, see. | [Labeling](demo#labelization) | -| extraConfig.labelization.enable | `boolean` | false | Indicates whether to enable tagging. This parameter is mandatory under . The value must be true. For details, see the example | [Labeling](demo#labelization) | -| extraConfig.labelization.overflow | `string` | '' | Optional. Preprocessing behavior when multiple tags exceed the container. The value is `'normal'\| 'scroll-y' \| 'multiple-line' \| 'string'`, indicating that the tag is hidden by default, vertical scrolling, automatic multi-line, and custom class | [labeling](demo#labelization) | -| extraConfig.labelization.containerMaxHeight | `string` | '1.8em ' | Specifies the maximum height of the container. This parameter is optional. By default, the height is not limited in multi-line mode. In single-line mode, the height is 1.8em by default. | -| ~~extraConfig.labelization.containnerMaxHeight~~ | `string` | '1.8em' | `Deprecated`. specifies the maximum height of a container. By default, the height is not limited in multi-line mode. In single-line mode, the height is 1.8 em by default. Use `extraConfig.labelization.containerMaxHeight` | . | -| extraConfig.labelization.labelMaxWidth | `string` | '100% ' | Optional. Limit the label width. The default value is 100% of the row width. | -| extraConfig.selectedItemWithTemplate | `object` | N/A | Optional. When a single option is selected and the display option is set to template, check whether the selected content is displayed in the template format. For details, see the example. | [Customized template](demo#select-template) | -| extraConfig.selectedItemWithTemplate.enable | `boolean` | -- | This parameter is required under labelization. It specifies whether to enable the selected items to use the template. The value must be true. For details, see Example | [Customized Template](demo#select-template) | -| optionDisabledKey | `string` | '' | Optional. A single option is disabled. If the input resource options type is Object, for example, Disabled, and the disabled attribute of the object is true, this option is disabled. When this parameter is set to `''`, a single option is not disabled. | [Disabled](demo#disabled) | -| optionImmutableKey | `string` | '' | Optional. A single option is disabled. If the input resource option type is Object, for example, immutable, and the immutable attribute of the object is true, the option cannot be changed. This parameter does not take effect when it is set to `''`. | [Disabled](demo#disabled) | -| noResultItemTemplate | `TemplateRef` | -- | Optional. No matching result is displayed. | -| keepMultipleOrder | `string` | 'user-select' | Optional. `'user-select' \| 'origin'` indicates whether to maintain the original array or user-selected sequence when multiple selections are performed, the default value is the user order. | [Sets the selected order source array order or selection order](demo#multi-keep-order) | -| customViewTemplate | `TemplateRef` | -- | Optional. Content displayed in the customized area can be customized. You can choose to select an item. Two mandatory parameters need to be transferred. The first parameter is the selected option, the second parameter is the index value of the option in the list, and the event parameter is Optional. if this parameter is left empty, handle the pop-up. For details, see demo | [Custom Area](demo#custom-area) | -| customViewDirection | `'bottom' \|'right'\|'left'` | 'bottom' | customViewTemplate position in the relative drop-down list box | [Customizing Area Orientation and Selecting](demo#custom-area-direction) | -| appendToBody | `boolean` | false | Optional. true: The value is attached to the body. | [Attach to the body](demo#append-to-body) | -| appendToBodyDirections | `Array` | `['rightDown','leftDown','rightUp','leftUp']` | Optional. The first position in the array is preferred for the direction array, for details about AppendToBodyDirection and ConnectedPosition, see dropdown | [CCustomizing Area Orientation and Selecting](demo#custom-area-direction) | -| autoFocus | `boolean` | false | Optional. Whether to enable auto-focus. | -| toggleOnFocus | `boolean` | false | Optional. indicating whether to automatically expand the drop-down list box by focusing. | -| width | `number` | -- | Optional. This parameter is used with appendToBody to set the drop-down width. | [Customizing Area Orientation and Selecting](demo#custom-area-direction) | -| virtualScroll | `boolean` | false | Optional. Whether to use virtual scrolling. This parameter is used in scenarios with a large amount of data. | [Virtual scrolling or lazy loading](demo#lazy-load-virtual-scroll) | -| allowClear | `boolean` | false | Optional specifies whether to clear the selected value. This parameter applies only to single-choice scenarios. | [Allowed to clear value](demo#allow-clear-value) | -| inputItemTemplate | `TemplateRef` | -- | Optional. Customized template. If this parameter is transferred, ContentChild is ignored. | | -| ~~~notAutoScroll~~~ | `boolean` | false | `To be renamed`~~~ Optional. When autofocus is enabled, the system automatically scrolls to the select position.~~~ | -| templateItemSize | `number` | false | `To be improved` Optional. The height of a single template is required. appendToBody must be true. | -| loadingTemplateRef | `TemplateRef` | -- | Optional. Customized loading template | [Virtual scrolling or lazy loading](demo#lazy-load-virtual-scroll) | - -### d-select event - -| Event | Type | Description | Jump to Demo | -| :----------: | :-------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -| valueChange | `EventEmitter\|any>` | Optional. output function. This function is invoked after an option is selected. The parameter is the value of the current option. | -| toggleChange | `EventEmitter` | Optional. output function. It is optional. It is used to enable or disable the toggle event. | [Asynchronous loading indicates that the toggle event is being loaded](demo#async-loading) | -| loadMore | `EventEmitter<{instance: SelectComponent, event: ScrollEvent}>` | lazy loading trigger event. This event is used together with `enableLazyLoad` and `$event.instance.loadFinish()` is used to end the loading. event indicates the lazy loading listening scrolling event. For details, see dLazyLoad | [Virtual scrolling or lazy loading](demo#lazy-load-virtual-scroll) | . | - -Note: After appendToBody is used, use `cdkScrollable` where the scroll bar exists. - -```terminal -npm install @angular/cdk --save -``` - -```TypeScript -import {ScrollDispatchModule} from '@angular/cdk/scrolling'; -@NgModule({ -imports: [ -//... -ScrollDispatchModule, -//... -] -}) -``` - -```html -
    - -
    -``` diff --git a/devui/shared/devui-codebox/devui-codebox.scss b/devui/shared/devui-codebox/devui-codebox.scss deleted file mode 100644 index 4e255f721fb1592ca6589f1e59e75ca60ecb1361..0000000000000000000000000000000000000000 --- a/devui/shared/devui-codebox/devui-codebox.scss +++ /dev/null @@ -1,151 +0,0 @@ -@import '../../style/theme/color'; -@import '../../style/core/font'; - -.code-box { - border: 1px solid $devui-line; - border-radius: 4px; - display: inline-block; - width: 100%; - position: relative; - margin: 4px 0; - transition: all 0.2s; -} - -.devui-code-copy { - fill: $devui-text; -} - -.code-box-demo { - border-bottom: 1px solid $devui-dividing-line; - padding: 42px 20px 50px; -} - -.code-box-meta.markdown { - position: relative; - padding: 10px 40px; - border-radius: 0 0 4px 4px; - transition: background-color 0.4s; - width: 100%; - font-size: $devui-font-size; - margin-bottom: 0; - overflow-x: unset; -} - -.code-box.expand .code-box-meta { - border-radius: 0; - border-bottom: 1px dashed $devui-dividing-line; -} - -.code-box-title { - position: absolute; - top: -14px; - padding: 1px 8px; - color: #777777; - border-radius: 4px 4px 0 0; - background: $devui-base-bg; - transition: background-color 0.4s; -} - -.code-box-title > a { - color: rgba(0, 0, 0, 0.65); - font-size: $devui-font-size-card-title; - font-weight: 500; - text-decoration: none; -} - -.code-box .collapse { - display: block; /* .collapse conflick with bootstrap */ - position: absolute; - left: 15px; - // background: $devui-block; - top: -9px; - cursor: pointer; - width: 16px; - height: 16px; - line-height: 16px; - opacity: 0.55; - text-align: center; - transition: all 0.3s; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - & > svg > path { - fill: $devui-text; - } -} - -.dark-mode .code-box .collapse { - opacity: 1; -} - -.code-box .highlight-wrapper { - display: none; - overflow: auto; - border-radius: 0 0 4px 4px; -} - -.code-box .highlight-wrapper-expand { - display: block; -} - -.code-box .highlight { - padding: 5px; - position: relative; -} - -.code-box-actions { - position: absolute; - top: 10px; - right: 12px; - text-align: right; - cursor: pointer; -} - -.code-box-code-copy:hover { - color: #108ee9; - -webkit-transform: scale(1.2); - transform: scale(1.2); -} - -.code-box-code-copy { - font-size: $devui-font-size-card-title; - cursor: pointer; - color: #222222; - transition: all 0.24s; - background: $devui-base-bg; - width: 20px; - height: 20px; - line-height: 20px; - text-align: center; - border-radius: 20px; - opacity: 0; -} - -.code-box .highlight pre { - margin: 0; - padding: 0; -} - -.code-box pre { - margin: 0; - width: auto; - border: none; - margin-top: 10px; -} - -.code-box pre code { - border: none; -} - -.highlight-wrapper:hover .code-box-code-copy, -.highlight-wrapper:hover .code-box-codepen, -.highlight-wrapper:hover .code-box-riddle { - opacity: 0.66; -} - -.code-box.expand .collapse { - -webkit-transform: rotate(90deg); - transform: rotate(90deg); -} diff --git a/devui/slider/demo/slider-demo.tsx b/devui/slider/demo/slider-demo.tsx deleted file mode 100644 index ce7101e2d19198207331a0520c6d4c6c2516dce0..0000000000000000000000000000000000000000 --- a/devui/slider/demo/slider-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-slider-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-slider-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/slider/demo/slider.route.ts b/devui/slider/demo/slider.route.ts deleted file mode 100644 index a3708504605012f0db1ce09acf7f7bdfc07ee12f..0000000000000000000000000000000000000000 --- a/devui/slider/demo/slider.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import SliderDemoComponent from './slider-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: SliderDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/slider/doc/api-cn.md b/devui/slider/doc/api-cn.md deleted file mode 100644 index 2d4fd224f8fc96bfe4d092d4ace7e98820a041fe..0000000000000000000000000000000000000000 --- a/devui/slider/doc/api-cn.md +++ /dev/null @@ -1,27 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { SliderModule } from 'ng-devui/slider'; -``` -在页面中使用: -```html - -``` - -# d-slider - -## d-slider 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :----------------: | :----------------------: | :------------------------------------------------------------------ | --------------------------------------------------- | -| min | `number` | 0 | 可选,滑动输入条的最小值 | [基本用法](demo#basic-usage) | -| max | `number` | 100 | 可选,滑动输入条的最大值 | [基本用法](demo#basic-usage) | -| step | `number` | 1 | 可选,滑动输入条的步长,取值必须大于等于 0,且必须可被(max-min)整除 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,值为 true 时禁止用户输入 | [禁止输入态](demo#slider-disabled) | -| tipsRenderer | `function \| null` | (value) => String(value) | 可选,渲染 Popover 内容的函数,传入 null 时不显示 Popover | [异定制Popover的显示内容](demo#slider-custom) | - -## d-slider 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| afterChange | `EventEmitter` | 滑动结束事件,与`onmouseup`触发时机一致,返回当前值。 | [基本用法](demo#basic-usage) | diff --git a/devui/slider/doc/api-en.md b/devui/slider/doc/api-en.md deleted file mode 100644 index 58055caa39d85f442f8331165830d020fb9da3ec..0000000000000000000000000000000000000000 --- a/devui/slider/doc/api-en.md +++ /dev/null @@ -1,27 +0,0 @@ -# How To Use -Import into module: -```ts -import { SliderModule } from 'ng-devui/slider'; -``` -In the page: -```html - -``` - -# d-slider - -## d-slider parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :----------------: | :----------------------: | :------------------------------------------------------------------ | --------------------------------------------------- | -| min | `number` | 0 | Optional. Minimum value of the sliding input bar | [Basic Usage](demo#basic-usage) | -| max | `number` | 100 | Optional. Maximum value of the sliding input bar | [Basic Usage](demo#basic-usage) | -| step | `number` | 1 | Optional. Step of the sliding input bar. The value must be greater than or equal to 0 and must be divisible by (max-min). | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. When the value is true, users are not allowed to enter. | [Input forbidden state](demo#slider-disabled) | -| tipsRenderer | `function \| null` | (value) => String(value) | Optional. This parameter indicates the function for rendering popover content. If null is transferred, popover content is not displayed. | [Customized popover content displayed](demo#slider-custom) | - -## d-slider event - -| Event | Type | Description | Jump to Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| afterChange | `EventEmitter` | Sliding end event, which is triggered at the same time as `onmouseup`. The current value is returned. | [Basic Usage](demo#basic-usage) | diff --git a/devui/slider/slider.tsx b/devui/slider/slider.tsx deleted file mode 100644 index 767796502b9baabefc65851c27679764d02c500e..0000000000000000000000000000000000000000 --- a/devui/slider/slider.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-slider', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-slider
    - } - } -}) \ No newline at end of file diff --git a/devui/splitter/demo/splitter-demo.tsx b/devui/splitter/demo/splitter-demo.tsx deleted file mode 100644 index 2834e09515eeecb12a59745c2c62ca162c7e8559..0000000000000000000000000000000000000000 --- a/devui/splitter/demo/splitter-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-splitter-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-splitter-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/splitter/demo/splitter.route.ts b/devui/splitter/demo/splitter.route.ts deleted file mode 100644 index 6d6a38f7f48c77b4d83e0b7424669fd4465d6f32..0000000000000000000000000000000000000000 --- a/devui/splitter/demo/splitter.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import SplitterDemoComponent from './splitter-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: SplitterDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/splitter/doc/api-cn.md b/devui/splitter/doc/api-cn.md deleted file mode 100644 index 43ea5200a31da3b4882770849fedde3833f7ff75..0000000000000000000000000000000000000000 --- a/devui/splitter/doc/api-cn.md +++ /dev/null @@ -1,47 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { SplitterModule } from 'ng-devui/splitter'; -``` -在页面中使用: -```html - - - - -``` - -# d-splitter - -## d-splitter 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----------------: | :------------------------: | :----------: | :---------------------------------------------------------- | ------------------------------------------------- | -| orientation | `'vertical'\|'horizontal'` | 'horizontal' | 可选,指定 Splitter 分割方向,可选值'vertical'\|'horizontal' | [基本用法](demo#basic-usage) | -| splitBarSize | `string` | '2px' | 可选,分隔条大小,默认 2px | [基本用法](demo#basic-usage) | -| disabledBarSize | `string` | '1px' | 可选,pane 设置不可调整宽度时生效 | [垂直布局用法](demo#vertical-layout) | -| showCollapseButton | `boolean` | true | 可选,是否显示收起/展开按钮 | [折叠收缩显示菜单](demo#shrink-show-menu) | - -# d-splitter-pane - -## d-splitter-pane 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :---------------: | :-------------------------: | :----: | :---------------------------------------------------- | ---------------------------------------------------------------------- | -| size | `string` | -- | 可选,指定 pane 宽度,设置像素值或者百分比 | [基本用法](demo#basic-usage) | -| minSize | `string` | -- | 可选,指定 pane 最小宽度,设置像素值或者百分比 | [基本用法](demo#basic-usage) | -| maxSize | `string` | -- | 可选,指定 pane 最大宽度,设置像素值或者百分比 | [基本用法](demo#basic-usage) | -| resizable | `boolean` | true | 可选,指定 pane 是否可调整大小,会影响相邻 pane | [垂直布局用法](demo#vertical-layout) | -| collapsible | `boolean` | false | 可选,指定 pane 是否可折叠收起 | [基本用法](demo#basic-usage) | -| collapsed | `boolean` | false | 可选,指定 pane 初始化是否收起,配合`collapsible`使用 | [垂直布局用法](demo#vertical-layout) | -| collapseDirection | `'before'\|'after'\|'both'` | 'both' | 可选,指定非边缘 pane 收起方向,配合`collapsible`使用 | [指定折叠收起方向](demo#certain-unfold-direction) | -| shrink | `boolean` | false | 可选,是否在 pane 进行折叠后收缩 pane 宽度而非收起 | [折叠收缩显示菜单](demo#shrink-show-menu) | -| shrinkWidth | `number` | 36 | 可选,折叠后收缩的 pane 宽度 (单位:px) | [折叠收缩显示菜单](demo#shrink-show-menu) | - -## d-splitter-pane 事件 - -| 事件 | 类型 | 描述 | 跳转 Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| sizeChange | `EventEmitter` | 大小变动时,返回改变后的值,像素值或者百分比 | [基本用法](demo#basic-usage) | -| collapsedChange | `EventEmitter` | 折叠和展开时,返回当前 pane 是否折叠 | [基本用法](demo#basic-usage) | -| shrinkStatusChange | `EventEmitter` | 收缩和展开时,返回当前 pane 是否收缩 | [折叠收缩显示菜单](demo#shrink-show-menu) | diff --git a/devui/splitter/doc/api-en.md b/devui/splitter/doc/api-en.md deleted file mode 100644 index 1a0867cc8e1d9d674ce5188bbe89e5c06ce074b8..0000000000000000000000000000000000000000 --- a/devui/splitter/doc/api-en.md +++ /dev/null @@ -1,47 +0,0 @@ -# How To Use -Import in module: -```ts -import { SplitterModule } from 'ng-devui/splitter'; -``` -In the page: -```html - - - - -``` - -# d-splitter - -## d-splitter parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------------: | :------------------------: | :----------: | :---------------------------------------------------------- | ------------------------------------------------- | -| orientation | `'vertical'\|'horizontal'` | 'horizontal' | Optional. It specifies the split direction of the splitter. The value can be'vertical'\|'horizontal' | [Basic usage](demo#basic-usage) | -| splitBarSize | `string` | '2px' | Optional. The default value is 2px. | [Basic usage](demo#basic-usage) | -| disabledBarSize | `string` | '1px' | Optional. This parameter is valid when the unadjustable width is set for the panel. | [Vertical layout usage](demo#vertical-layout) | -| showCollapseButton | `boolean` | true | Optional. Whether to display the collapse/expand button | [Collapse and collapse menu](demo#shrink-show-menu) | - -# d-splitter-pane - -## d-splitter-pane parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :-------------------------: | :----: | :---------------------------------------------------- | ---------------------------------------------------------------------- | -| size | `string` | -- | Optional. Specifies the width of the pane and sets the pixel value or percentage. | [Basic usage](demo#basic-usage) | -| minSize | `string` | -- | Optional. Specifies the minimum width of the pane and sets the pixel value or percentage. | [Basic usage](demo#basic-usage) | -| maxSize | `string` | -- | Optional. This parameter specifies the maximum width of the pane and sets the pixel value or percentage. | [Basic usage](demo#basic-usage) | -| resizable | `boolean` | true | Optional. Specifies whether the size of a pane can be adjusted, which affects adjacent panes. | [Vertical layout usage](demo#vertical-layout) | -| collapsible | `boolean` | false | Optional. Specifies whether the pane can be collapsed or collapsed. | [Basic usage](demo#basic-usage) | -| collapsed | `boolean` | false | Optional. Specifies whether to collapse the pane during initialization. This parameter is used together with `collapsible`. | [Vertical layout usage](demo#vertical-layout) | -| collapseDirection | `before'\|'after'\|'both'` | 'both' | Optional. This parameter specifies the folding direction of a non-edge pane. This parameter is used together with `collapsible`. | [Specify the folding direction](demo#certain-unfold-direction) | -| shrink | `boolean` | false | Optional. Indicating whether to shrink the pane width after the pane is collapsed. | [Collapse and collapse menu](demo#shrink-show-menu) | -| shrinkWidth | `number` | 36 | Optional. Width of the pane to be collapsed after collapse (unit: px). | [Collapse and collapse menu](demo#shrink-show-menu) | - -## d-splitter-pane event - -| Event | Type | Description | Jump to Demo | -| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------------------- | -| sizeChange | `EventEmitter` | When the size changes, the changed value (pixel value or percentage) is returned. | [Basic usage](demo#basic-usage) | -| collapsedChange | `EventEmitter` | Whether the current pane is collapsed or expanded. | [Basic usage](demo#basic-usage) | -| shrinkStatusChange | `EventEmitter` | Whether to collapse the current pane when the current pane is collapsed or expanded. | [Collapse and collapse menu](demo#shrink-show-menu) | diff --git a/devui/splitter/splitter.tsx b/devui/splitter/splitter.tsx deleted file mode 100644 index d1cf671d8dd30f9e934e8062e8f9ac259b5906fe..0000000000000000000000000000000000000000 --- a/devui/splitter/splitter.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-splitter', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-splitter
    - } - } -}) \ No newline at end of file diff --git a/devui/status/demo/status-demo.tsx b/devui/status/demo/status-demo.tsx deleted file mode 100644 index 63003ea6f5eebe421ff3627d10f3a956b4e4c055..0000000000000000000000000000000000000000 --- a/devui/status/demo/status-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-status-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-status-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/status/demo/status.route.ts b/devui/status/demo/status.route.ts deleted file mode 100644 index adb8b979c4c12301466c2a845a539f451589efd5..0000000000000000000000000000000000000000 --- a/devui/status/demo/status.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import StatusDemoComponent from './status-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: StatusDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/status/doc/api-cn.md b/devui/status/doc/api-cn.md deleted file mode 100644 index ab04ceb48c7190ca6d4b872d3c63df81268d7f3b..0000000000000000000000000000000000000000 --- a/devui/status/doc/api-cn.md +++ /dev/null @@ -1,16 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { StatusModule } from 'ng-devui/status'; -``` - -在页面中使用: -```html - -``` -# d-status -## d-status 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--: | :------: | :-------: | :--------------------------------------------------------------------------- | ------------------------------------------- | -| type | `invalid\|running\|waiting\|important\|less-important\|error` | 'invalid' | 必选,类型,值有 success、error、warning、initial、waiting、running、invalid | [基本用法](demo#basic-usage) | diff --git a/devui/status/doc/api-en.md b/devui/status/doc/api-en.md deleted file mode 100644 index 38090811bdf16a06fbb29a46a44c695980fe74be..0000000000000000000000000000000000000000 --- a/devui/status/doc/api-en.md +++ /dev/null @@ -1,18 +0,0 @@ -# How to use -The following information is introduced into the module - -```ts -import { StatusModule } from 'ng-devui/status'; -``` - -On the page - -```html - -``` -# d-status -## d-status parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :-----------------------------------------------------------: | :-------: | :----------------------------------------------------------------------------------------- | -------------------------------------------------------- | -| type | `invalid\|running\|waiting\|important\|less-important\|error` | 'invalid' | Required. The value can be success, error, warning, initial, waiting, running, or invalid. | [Basic usage](demo#basic-usage) | diff --git a/devui/status/status.tsx b/devui/status/status.tsx deleted file mode 100644 index 3252bd0e6c0a809a786c62eecf5237ab7f65ca8a..0000000000000000000000000000000000000000 --- a/devui/status/status.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-status', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-status
    - } - } -}) \ No newline at end of file diff --git a/devui/steps-guide/demo/steps-guide-demo.tsx b/devui/steps-guide/demo/steps-guide-demo.tsx deleted file mode 100644 index dfb46a4138c75e704938354283283465065726a5..0000000000000000000000000000000000000000 --- a/devui/steps-guide/demo/steps-guide-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-steps-guide-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-steps-guide-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/steps-guide/demo/steps-guide.route.ts b/devui/steps-guide/demo/steps-guide.route.ts deleted file mode 100644 index 0e58b13d2575a52a9ad81207ada4fdf78363273d..0000000000000000000000000000000000000000 --- a/devui/steps-guide/demo/steps-guide.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import StepsGuideDemoComponent from './steps-guide-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: StepsGuideDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/steps-guide/doc/api-cn.md b/devui/steps-guide/doc/api-cn.md deleted file mode 100644 index 232c5f58cd92262b93c66163e3dcac42cae9763a..0000000000000000000000000000000000000000 --- a/devui/steps-guide/doc/api-cn.md +++ /dev/null @@ -1,75 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { StepsGuideModule } from 'ng-devui/steps-guide'; -``` - -在页面中使用: - -```html - - -``` - -# dStepsGuide - -## dStepsGuide 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :-------------------------------------------------: | :--: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | -| pageName | `string` | -- | 必选,用于标识操作指引是否显示,一组操作指引序列建议使用相同值 | [基本用法](demo#basic-usage) | -| steps | `Array<`[`StepItem`](#stepitem)`>` | [] | 必选,操作指引步骤数组,如通过 StepsGuideService.setSteps 设置了操作指引步骤,则优先使用服务中的,StepItem 对象定义见下 | [基本用法](demo#basic-usage) | -| stepIndex | `number` | -- | 必选,当前步骤在整个操作指引序列中的索引 | [基本用法](demo#basic-usage) | -| ~~position~~ | [`StepsGuidePositionType`](#stepsguidepositiontype) | top | 可选,指引信息弹出的位置方向,可选值:top、top-left、top-right、bottom、bottom-left、bottom-right、left、right(`已废弃,请使用dStepsGuidePosition`) | [基本用法](demo#basic-usage) | -| dStepsGuidePosition | [`StepsGuidePositionType`](#stepsguidepositiontype) | top | 可选,指引信息弹出的位置方向,可选值:top、top-left、top-right、bottom、bottom-left、bottom-right、left、right | [基本用法](demo#basic-usage) | -| leftFix | `number` | 0 | 可选,用于修正指引信息的位置 | [自定义位置](demo#custom-usage) | -| topFix | `number` | 0 | 可选,用于修正指引信息的位置 | [自定义位置](demo#custom-usage) | -| zIndex | `number` | 1100 | 可选,用于调整指引信息的显示层级 | [自定义位置](demo#custom-usage) | -| targetElement | `HTMLElement` | -- | 可选,指引信息显示的目标 dom ,如果指定,不再使用指令所在的 dom 作为目标 | [自定义位置](demo#custom-usage) | -| scrollElement | `HTMLElement` | -- | 可选,指引信息跟随滚动定位的容器 dom ,默认会自动获取,如果与预想 dom 不同时需要指定 | | -| scrollToTargetSwitch | `boolean` | true | 可选,是否自动滚动页面至指引信息显示的位置 dom | [基本用法](demo#basic-usage) | -| observerDom | `HTMLElement` | -- | 可选,允许用户指定一个 dom 反馈页面变化。主要用于用户无法控制或判断的且不会触发 resize 事件的 dom 改变导致指引信息位置变化的情况,例如:指引信息绑定在 fixed 定位的头部菜单,页面随路由跳转内容变化会显示或隐藏滚动条导致头部菜单的 dom 位置发生变化 | [自定义位置](demo#custom-usage) | -| extraConfig | [`ExtraConfig`](#extraconfig) | -- | 可选,扩展配置,用于隐藏上一步按钮和步骤圆点图标,ExtraConfig 对象定义见下文 | [自定义位置](demo#custom-usage) | - -### StepItem - -```ts -export interface StepItem { - title: string; // 引导标题 - content: string; // 引导介绍内容 -} -``` - -### StepsGuidePositionType - -```ts -export type StepsGuidePositionType = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; -``` - -### ExtraConfig - -```ts -export interface ExtraConfig { - hidePreStep: boolean; // 隐藏上一步按钮 - hideStepNav: boolean; // 隐藏步骤圆点图标显示 -} -``` - -### dStepsGuide 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :-----------: | :-----------------------------------------------------: | :--------------------------------------------------------------- | :--------------------------- | -| operateChange | `EventEmitter<`[`OperateResponse`](#operateresponse)`>` | 可选,返回当前步骤索引和当前操作,OperateResponse 对象定义见下文 | [基本用法](demo#basic-usage) | - -# 接口 & 类型定义 - -### OperateResponse - -```ts -OperateResponse { - currentIndex: number; // 当前索引 - clickType: 'prev' | 'next' | 'close'; // 当前操作 -} -``` diff --git a/devui/steps-guide/doc/api-en.md b/devui/steps-guide/doc/api-en.md deleted file mode 100644 index cd98f1fba7859d0f58b59caf91e7707be068ed46..0000000000000000000000000000000000000000 --- a/devui/steps-guide/doc/api-en.md +++ /dev/null @@ -1,76 +0,0 @@ -# How to use - -Import into module - -```ts -import { StepsGuideModule } from 'ng-devui/steps-guide'; -``` - -In the page - -```html - - -``` - -# dStepsGuide - -## dStepsGuide Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :-------------------------------------------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | -| pageName | `string` | -- | Required. This parameter specifies whether to display the operation guide. It is recommended that you use the same value for a group of operation guide sequences. | [Basic usage](demo#basic-usage) | -| steps | `Array<`[`StepItem`](#stepitem)`>` | [] | Required. Operation guide step array. If an operation guide step is set through StepsGuideService.setSteps, the step in the service is preferentially used. For the definition of the StepItem object, see the following | [Basic usage](demo#basic-usage) | -| stepIndex | `number` | -- | Required. Index of the current step in the operation guide sequence. | [Basic usage](demo#basic-usage) | -| ~~position~~ | [`StepsGuidePositionType`](#stepsguidepositiontype) | top | Optional. Guide the position and direction of information dragging, optional values: top, top-left, top-right, bottom, left-left, bottom-right, left, right (`deprecated, please use dStepsGuidePosition`). | [Basic usage](demo#basic-usage) | -| dStepsGuidePosition | [`StepsGuidePositionType`](#stepsguidepositiontype) | top | Optional. Guide the position and direction of the information pop-up, optional values: top, top-left, top-right, bottom, bottom-left, bottom-right, left, right | [Basic usage](demo#basic-usage) | -| leftFix | `number` | 0 | Optional. It is used to correct the location of the guidance information. | [Customized location](demo#custom-usage) | -| topFix | `number` | 0 | Optional. Used to correct the location of guidance information. | [Customized location](demo#custom-usage) | -| zIndex | `number` | 1100 | Optional. This parameter is used to adjust the display level of guidance information. | [Customized position](demo#custom-usage) | -| targetElement | `HTMLElement` | -- | Optional. This parameter specifies the target dom in the instruction information. If this parameter is specified, the dom where the instruction is located is not used as the target. | [Customized location](demo#custom-usage) | -| scrollToTargetSwitch | `boolean` | true | Optional. Indicates whether to automatically scroll to the location where the guide information is displayed. dom | [Customized location](demo#custom-usage) | -| targetElement | `HTMLElement` | -- | Optional. This parameter specifies the target dom in the instruction information. If this parameter is specified, the dom where the instruction is located is not used as the target. | [Customized location](demo#custom-usage) | -| scrollToTargetSwitch | `boolean` | true | Optional. Indicates whether to automatically scroll to the location where the guide information is displayed. dom | [Customized location](demo#custom-usage) | -| observerDom | `HTMLElement` | -- | Optional. Allows users to specify a dom to report page changes. This parameter is used when the location of the guide information changes due to the dom change that cannot be controlled or determined by the user and does not trigger the resize event. For example, the guide information is bound to the header menu of fixed positioning, the dom position of the header menu changes because the scroll bar is displayed or hidden when the page changes with the route. | [Customized position](demo#custom-usage) | -| extraConfig | [`ExtraConfig`](#extraconfig) | -- | Optional. Extended configuration used to hide the button and dot icon of the previous step. For details about the definition of the ExtraConfig object, see the following description. | [Customized location](demo#custom-usage) | - -### StepItem - -```ts -export interface StepItem { - title: string; // guide title - content: string; // guide content -} -``` - -### StepsGuidePositionType - -```ts -export type StepsGuidePositionType = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; -``` - -### ExtraConfig - -```ts -export interface ExtraConfig { - hidePreStep: boolean; // Hide Previous Button - hideStepNav: boolean; // Hide step dot icon display -} -``` - -### dStepsGuide Event - -| Parameter | Type | Description | Jump to Demo | -| :-----------: | :-----------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------ | -| operateChange | `EventEmitter<`[`OperateResponse`](#operateresponse)`>` | Optional. Returns the index of the current step and the current operation. For details about the OperateResponse object, see the following description. | [Basic usage](demo#basic-usage) | - -# Interface & Type Definition - -### OperateResponse - -```ts -OperateResponse { - currentIndex: number; // Current index - clickType: 'prev' | 'next' | 'close'; // Current Operation -} -``` diff --git a/devui/steps-guide/steps-guide.tsx b/devui/steps-guide/steps-guide.tsx deleted file mode 100644 index 35704156e50ad69165bc55816df944ca6a5a116a..0000000000000000000000000000000000000000 --- a/devui/steps-guide/steps-guide.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-steps-guide', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-steps-guide
    - } - } -}) \ No newline at end of file diff --git a/devui/sticky/demo/sticky-demo.tsx b/devui/sticky/demo/sticky-demo.tsx deleted file mode 100644 index abf4917d69af99b5f48e40334f57eeaad402dffe..0000000000000000000000000000000000000000 --- a/devui/sticky/demo/sticky-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-sticky-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-sticky-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/sticky/demo/sticky.route.ts b/devui/sticky/demo/sticky.route.ts deleted file mode 100644 index 508c883b905f5e309698834090ffa9fd9d574585..0000000000000000000000000000000000000000 --- a/devui/sticky/demo/sticky.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import StickyDemoComponent from './sticky-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: StickyDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/sticky/doc/api-cn.md b/devui/sticky/doc/api-cn.md deleted file mode 100644 index 0bf45b30cf4dcff727d73715d35dae70638bb36c..0000000000000000000000000000000000000000 --- a/devui/sticky/doc/api-cn.md +++ /dev/null @@ -1,53 +0,0 @@ -# 如何使用 - -在module中引入: -```ts -import { StickyModule } from 'ng-devui'; -``` - -在页面中使用: -```html - -``` - -# d-sticky - -使用了一个组件能在父容器或者指定容器出现在可视区域的时候,跟随可视区域移动,在父容器或者指定容器从可视区域消失的时候,跟随父容器移动到可视区域外。如果父容器等于可视窗口,那组件不会消失。 - -便贴组件的内容必须有自己的宽度和高度,否则浮动的时候可能会宽度高度不正确。 - -目前只支持垂直方向跟随。 - -**注意**:父容器必须有个高度,并且不会由于组件的浮动出现高度塌陷,否则组件无法跟随浮动。 - -**注意**:由于监听了页面的滚动,一个页面里的 sticky 元素不应有太多,影响性能。 - -## d-sticky 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :----------------------------: | :----------------------: | :------------------------------------------------------------------------------------: | ----------------------------------------------------- | -| zIndex | `number` | -- | 可选,指定包裹层的 z-index,用于浮动的时候控制 z 轴的叠放 | [基本用法](demo#basic-usage) | -| container | `HTMLElement` | 父容器 | 可选,触发的容器,可不同于父容器 | [基本用法](demo#basic-usage) | -| view | `{top?:number,bottom?:number}` | {top:0,bottom:0} | 可选,用于可视区域的调整,比如顶部有固定位置的头部等,数值对应被遮挡的顶部或底部的高度 | [基本用法](demo#basic-usage) | -| scrollTarget | `HTMLElement` | document.documentElement | 可选,设置要发生滚动的容器,一般为滚动条所在容器,为主页面的滚动条时候可以不设置 | [更换滚动容器](demo#scroll-target) | - -**注意**: container 范围如果大于 scrollTarget,生效的只有 scrollTarget 范围。 - -## d-sticky 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----------: | :--------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ----------------------------------------------- | -| statusChange | [`EventEmitter`](#stickystatus) | 可选,状态变化的时候触发,值为变化后的状态值 | [基本用法](demo#basic-usage) | - -# 接口 & 类型定义 - -### StickyStatus -```ts -/** - * normal: 表示处于正常状态 - * follow: 表示处于跟着页面滚动固定位置状态 - * stay: 表示横向滚动时候的跟随固定状态 - * remain: 表示被容器托起处于容器底部跟着容器走的状态 - */ -export type StickyStatus = 'normal' | 'follow' | 'stay' | 'remain'; -``` diff --git a/devui/sticky/doc/api-en.md b/devui/sticky/doc/api-en.md deleted file mode 100644 index aef39b5dcb252bf54caa0221b3bc87744c11bfde..0000000000000000000000000000000000000000 --- a/devui/sticky/doc/api-en.md +++ /dev/null @@ -1,53 +0,0 @@ -# How to use - -Import into module: -```ts -import { StickyModule } from 'ng-devui'; -``` - -In the page: -```html - -``` - -# d-sticky - -A component is used to move with the visual area when the parent container or specified container appears in the visual area, when a parent container or a specified container disappears from the visible area, the container moves out of the visible area with the parent container. If the parent container is equal to the visible window, the component does not disappear. - -The content of the notepad must have its own width and height; otherwise, the width and height may be incorrect when floating. - -Currently, only the vertical direction is supported. - -**Note**: that the parent container must have a height and do not collapse due to component floats, otherwise the component cannot follow the float. - -**Note**: that the page scrolling is monitored. Therefore, there should be no too many sticky elements on a page, which affects the performance. - -## d-sticky Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :----------------------------: | :----------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | --------------------------------------------------------------------- | -| zIndex | `number` | -- | Optional. This parameter specifies the z-index of the wrapping layer, which is used to control the stacking of the z axis during floating. | [Basic Usage](demo#basic-usage) | -| container | `HTMLElement` | Parent container | Optional. Triggered container, which can be different from the parent container. | [Basic Usage](demo#basic-usage) | -| view | `{top?:number,bottom?:number}` | {top:0,bottom:0} | Optional. It is used to adjust the visible region, for example, the head with a fixed position on the top. The value corresponds to the height of the blocked top or bottom. | [Basic Usage](demo#basic-usage) | -| scrollTarget | `HTMLElement` | document.documentElement | Optional. Sets the container where the scroll bar is located. This parameter is optional when the scroll bar is on the home page. | [Replace Rolling Container](demo#scroll-target) | - -Note: If the container range is greater than the scrollTarget range, only the scrollTarget range takes effect. - -## d-sticky Event - -| Event | Type | Description | Jump to Demo | -| :----------: | :--------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------- | -| statusChange | [`EventEmitter`](#stickystatus) | Optional. It is triggered when the status changes. The value is the status after the change. | [Basic Usage](demo#basic-usage) | - -# Interface & Type Definition - -### StickyStatus -```ts -/** - * normal: Normal state. - * follow: Indicates that the page is scrolled to a fixed position. - * stay: Indicates the following fixed status during horizontal scrolling. - * remain: Represents being lifted by the container in the condition of following the container at the bottom of the container. - */ -export type StickyStatus = 'normal' | 'follow' | 'stay' | 'remain'; -``` diff --git a/devui/sticky/sticky.tsx b/devui/sticky/sticky.tsx deleted file mode 100644 index b0e714cd7e33e99d662075d815dfb132828d7227..0000000000000000000000000000000000000000 --- a/devui/sticky/sticky.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-sticky', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-sticky
    - } - } -}) \ No newline at end of file diff --git a/devui/tabs/demo/tabs-demo.tsx b/devui/tabs/demo/tabs-demo.tsx deleted file mode 100644 index e6f28eece40afd2143d590d669ca99847a168982..0000000000000000000000000000000000000000 --- a/devui/tabs/demo/tabs-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tabs-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tabs-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tabs/demo/tabs.route.ts b/devui/tabs/demo/tabs.route.ts deleted file mode 100644 index 42c3fd37e86ddc9e7f8ead66235c634fe34e68d4..0000000000000000000000000000000000000000 --- a/devui/tabs/demo/tabs.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TabsDemoComponent from './tabs-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TabsDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/tabs/doc/api-cn.md b/devui/tabs/doc/api-cn.md deleted file mode 100644 index b0d44dfe0ffcdcc4f736d2db26d821afbcb62f79..0000000000000000000000000000000000000000 --- a/devui/tabs/doc/api-cn.md +++ /dev/null @@ -1,46 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { TabsModule } from 'ng-devui/tabs'; -``` - -在页面中使用: - -```html - - - ... - ... - - -``` -# d-tabs -## d-tabs 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-----------------------------: | :----: | :---------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | -| type | `tabs\|pills\|options` | 'tabs' | 可选,选项卡组的类型 | [配置类型与排列](demo#configuration-type-and-arrangement) | -| showContent | `boolean` | true | 可选,是否显示选项卡对应的内容 | [不设置内容](demo#no-set-content) | -| activeTab | `string` | -- | 可选,当前激活的选项卡,值为选项卡的 id | [基本用法](demo#basic-usage) | -| cssClass | `string` | -- | 可选,自定义选项卡组的 css 类 | [自定义模板](demo#custom-template) | -| customWidth | `string` | -- | 可选,自定义选项卡的宽度 | [配置类型与排列](demo#configuration-type-and-arrangement) | -| vertical | `boolean` | false | 可选,是否垂直显示 | [配置类型与排列](demo#configuration-type-and-arrangement) | -| beforeChange | `function\|Promise\|Observable` | -- | tab 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 tab 的切换 | [拦截 tab 切换](demo#intercept-tab-switch) | -| reactivable | `boolean` | false | 可选,点击当前处于激活态的 tab 时是否触发`activeTabChange`事件,`true`为允许触发,`false`为不允许触发 | [拦截 tab 切换](demo#intercept-tab-switch) | - -## d-tabs 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :-------------: | :----------------------------: | :-------------------------------------------------- | ---------------------------- | -| activeTabChange | `EventEmitter` | 可选,选项卡切换的回调函数,返回当前激活选项卡的 id | [基本用法](demo#basic-usage) | - -### d-tab 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------: | :--------------: | :---: | :------------------------------------- | --------------------------------- | -| tabId | `string` | -- | 可选,选项卡的 id 值, 需要设置为唯一值 | [基本用法](demo#basic-usage) | -| id | `number\|string` | -- | 可选,一般和`tabId`一致 | [基本用法](demo#basic-usage) | -| title | `string` | -- | 可选,选项卡的标题 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,选项卡是否不可用 | [不设置内容](demo#no-set-content) | diff --git a/devui/tabs/doc/api-en.md b/devui/tabs/doc/api-en.md deleted file mode 100644 index 477fccc72c84f7d127c1e098d5cbd8cc4019001a..0000000000000000000000000000000000000000 --- a/devui/tabs/doc/api-en.md +++ /dev/null @@ -1,48 +0,0 @@ -# How to use - -Import into module: - -```ts -import { TabsModule } from 'ng-devui/tabs'; -``` - -In the page: - -```html - - - ... - ... - - -``` - -# d-tabs - -## d-tabs parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-----------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| type | `tabs\|pills\|options` | 'tabs' | Optional. Tab group type | [Configuration type and arrangement](demo#configuration-type-and-arrangement) | -| showContent | `boolean` | true | Optional. Indicating whether to display the content corresponding to the tab. | [No Content](demo#no-set-content) | -| activeTab | `string` | -- | Optional. Currently activated tab. The value is the ID of the tab. | [Basic Usage](demo#basic-usage) | -| cssClass | `string` | -- | Optional. CSS class of a customized tab group | [Customized Template](demo#custom-template) | -| customWidth | `string` | -- | Optional. It indicates the width of the customized tab. | [Configuration Type and Arrangement](demo#configuration-type-and-arrangement) | -| vertical | `boolean` | false | Optional. Indicating whether to display vertically | [Configuration Type and Arrangement](demo#configuration-type-and-arrangement) | -| beforeChange | `function\|Promise\|Observable` | -- | Optional. Tab Callback function before switching. The value of this parameter is of the boolean type. If false is returned, tab switching can be prevented. | [Interception Tab Switching](demo#intercept-tab-switch) | -| reactivable | `boolean` | false | Optional. Indicates whether to trigger the `activeTabChange` event when a tab in the active state is clicked. The value true indicates that the event can be triggered, and the value false indicates that the event cannot be triggered. | [Interception Tab Switching](demo#intercept-tab-switch) | - -## d-tabs event - -| Parameter | Type | Description | Jump to Demo | -| :-------------: | :----------------------------: | :---------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | -| activeTabChange | `EventEmitter` | Optional. Callback function for switching tabs. This parameter is optional. It returns the ID of the currently activated tab. | [Basic usage](demo#basic-usage) | - -## d-tab Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :--------------: | :-----: | :------------------------------------------------------------- | --------------------------------- | -| tabId | `string` | -- | Optional. Tab ID, which must be unique. | [Basic usage](demo#basic-usage) | -| id | `number\|string` | -- | Optional. Generally, the value is the same as that of `tabId`. | [Basic usage](demo#basic-usage) | -| title | `string` | -- | Optional. Tab title | [Basic usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Indicating whether the tab is unavailable | [No Content](demo#no-set-content) | diff --git a/devui/tabs/tabs.tsx b/devui/tabs/tabs.tsx deleted file mode 100644 index 9b5934b2c9e15ed7f5e666bb6fa00bc3e18845ad..0000000000000000000000000000000000000000 --- a/devui/tabs/tabs.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { computed, defineComponent, provide, reactive } from 'vue' -import './tabs.scss'; -export type Active = string | number | null; -export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider' -export interface Tabs { - state: TabsState; -} -interface TabsState { - data?: any[], - showContent: boolean, - active: any -} -export default defineComponent({ - name: 'd-tabs', - props: { - modelValue: { - type: [String, Number], - default: null - }, - // TODO:其中 slider 类型还没有实现 - type: { - type: String as () => TabsType, - default: 'tabs' - }, - showContent: { - type: Boolean, - default: true - }, - vertical: { - type: Boolean, - default: false - }, - reactivable: { - type: Boolean, - default: true - }, - customWidth: { - type: String - }, - cssClass: { - type: String - } - }, - // TODO: beforeChange没有完成实现 - emits: ['update:modelValue', 'activeTabChange', 'beforeChange'], - setup(props, { emit, slots }) { - const active = computed(() => { - return props.modelValue - }) - const state: TabsState = reactive({ - data: [], - active, - showContent: props.showContent - }); - provide('tabs', { - state - }); - function activateTab(tab: Active) { - emit('beforeChange'); - emit('update:modelValue', tab); - if (props.reactivable) { - emit('activeTabChange', tab) - } - } - - const ulClass: string[] = [props.type]; - props.cssClass && ulClass.push(props.cssClass); - props.vertical && ulClass.push('devui-nav-stacked') - return () => { - return
    -
      - { - state.data.map((item, i) => { - return
    • activateTab((item.id || item.tabId))} class={active.value === (item.id || item.tabId) ? 'active' : ''} id={item.id || item.tabId} > - - {item.title} - -
    • - }) - } -
      -
    - {slots.default()} -
    - - } - } -}) - diff --git a/devui/tags-input/demo/tags-input-demo.tsx b/devui/tags-input/demo/tags-input-demo.tsx deleted file mode 100644 index 479f5abead9a75d85bdc5c315e22b3c94f62542d..0000000000000000000000000000000000000000 --- a/devui/tags-input/demo/tags-input-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tags-input-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tags-input-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tags-input/demo/tags-input.route.ts b/devui/tags-input/demo/tags-input.route.ts deleted file mode 100644 index 7fc7f8f2de5ef172a755399f8db324a84dd8517e..0000000000000000000000000000000000000000 --- a/devui/tags-input/demo/tags-input.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TagsInputDemoComponent from './tags-input-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TagsInputDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': '', - 'en-us': '' - }} -] - -export default routes diff --git a/devui/tags-input/doc/api-cn.md b/devui/tags-input/doc/api-cn.md deleted file mode 100644 index ed498c9d85ba48e3a39c889cbc19b458abf2246b..0000000000000000000000000000000000000000 --- a/devui/tags-input/doc/api-cn.md +++ /dev/null @@ -1,44 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { TagsInputModule } from 'ng-devui/tags-input'; -``` - -在页面中使用: -```html - - -``` -# TagsInput - -## d-tags-input 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------------: | :-----------------------------: | :---------------------: | :---------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -| tags | `Array` | [] | 必选,记录输入的标签和选择的标签列表 | [基本用法](demo#basic-usage) | -| displayProperty | `string` | 'name' | 可选,列表项使用的属性名 | [基本用法](demo#basic-usage) | -| placeholder | `boolean` | '' | 可选,输入框的 placeholder | [基本用法](demo#basic-usage) | -| minLength | `number` | 3 | 可选,输入标签内容的最小长度 | [基本用法](demo#basic-usage) | -| maxLength | `number` | Number.MAX_SAFE_INTEGER | 可选,输入标签内容的最大长度 | [基本用法](demo#basic-usage) | -| maxTags | `number` | Number.MAX_SAFE_INTEGER | 可选,可输入标签的最大个数 | [基本用法](demo#basic-usage) | -| caseSensitivity | `boolean` | false | 可选,大小写敏感,默认忽略大小 | [基本用法](demo#basic-usage) | 写 | -| spellcheck | `boolean` | true | 可选,input 输入框是否开启拼写检查的 | [基本用法](demo#basic-usage) | spellcheck | -| isAddBySpace | `boolean` | true | 可选,是否支持空格键输入标 | [基本用法](demo#basic-usage) | 签 | -| suggestionList | `Array` | [] | 可选,下拉选项,默认可选择的标签列表 | [基本用法](demo#basic-usage) | -| checkBeforeAdd | `Function\|Promise\|Observable` | 无 | 可选,自定义校验函数,类型为(newTag: string) => boolean 或者 Promise或者 Observable | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,disabled 灰化状态 | [基本用法](demo#basic-usage) | - -备注:除传入`tags`方式实现外,还可采用`ngModel`绑定数组的方式,详细使用示例参考[双向绑定](demo#ng-model)。 - -## d-tags-input 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :---------: | :-----------------: | :------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | -| valueChange | `EventEmitter` | 当选中某个选项项后,将会调用此函数,参数为当前选择项的值。如果需要获取所有选择状态的值,请使用(ngModelChange) | [基本用法](demo#basic-usage) | diff --git a/devui/tags-input/doc/api-en.md b/devui/tags-input/doc/api-en.md deleted file mode 100644 index ab81c23d98ad13424a6cc1ba8108124d80fdcb38..0000000000000000000000000000000000000000 --- a/devui/tags-input/doc/api-en.md +++ /dev/null @@ -1,44 +0,0 @@ -# How to use -Import into module: -```ts -import { TagsInputModule } from 'ng-devui/tags-input'; -``` - -In the page: -```html - - -``` -# TagsInput - -## d-tags-input parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------: | :-----------------------------: | :---------------------: | :------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -| tags | `Array` | [] | Required. This parameter records the entered tag and selected tag list. | [Basic Usage](demo#basic-usage) | -| displayProperty | `string` | 'name' | Optional. Attribute name used by a list item | [Basic Usage](demo#basic-usage) | -| placeholder | `boolean` | '' | Optional. This parameter specifies the placeholder in the text box. | [Basic Usage](demo#basic-usage) | -| minLength | `number` | 3 | Optional. Enter the minimum length of the tag content. | [Basic Usage](demo#basic-usage) | -| maxLength | `number` | Number.MAX_SAFE_INTEGER | Optional. Enter the maximum length of the tag content. | [Basic Usage](demo#basic-usage) | -| maxTags | `number` | Number.MAX_SAFE_INTEGER | Optional. Maximum number of tags that can be entered | [Basic Usage](demo#basic-usage) | -| caseSensitivity | `boolean` | false | Optional. Is case sensitive. The default value is ignoring. | [Basic Usage](demo#basic-usage) | Write | -| spellcheck | `boolean` | true | Optional. Indicates whether to enable spelling check in the input text box. | [Basic Usage](demo#basic-usage) | spellcheck | -| isAddBySpace | `boolean` | true | Optional. Whether to support the space bar. | [Basic Usage](demo#basic-usage) | label. | -| suggestionList | `Array` | [] | Optional. This parameter is a drop-down list box. The default tag list can be selected. | [Basic Usage](demo#basic-usage) | -| checkBeforeAdd | `Function\|Promise\|Observable` | None | Optional. User-defined verification function whose type is (newTag: string) => boolean, Promise, or Observable | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Disabled is unavailable. | [Basic Usage](demo#basic-usage) | - -Note: In addition to the "tags" mode, you can also use the "ngModel" mode to bind arrays. For details, see [Two-way Binding](demo#ng-model). - -## d-tags-input event - -| Event | Type | Description | Jump to Demo | -| :---------: | :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | -| valueChange | `EventEmitter` | This function is invoked when an option is selected. The parameter is the value of the selected option. To obtain the values of all selection states, use (ngModelChange) | [Basic Usage](demo#basic-usage) | diff --git a/devui/tags-input/tags-input.tsx b/devui/tags-input/tags-input.tsx deleted file mode 100644 index e07e6982a45a3038f7894189ee8c60b678e5136a..0000000000000000000000000000000000000000 --- a/devui/tags-input/tags-input.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tags-input', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tags-input
    - } - } -}) \ No newline at end of file diff --git a/devui/tags/demo/tags-demo.tsx b/devui/tags/demo/tags-demo.tsx deleted file mode 100644 index c14f79c07ea36143a6124439fa8e6f445f83b66b..0000000000000000000000000000000000000000 --- a/devui/tags/demo/tags-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tags-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tags-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tags/demo/tags.route.ts b/devui/tags/demo/tags.route.ts deleted file mode 100644 index 932cbc2ac0f369b4170b4623118e0f125275d131..0000000000000000000000000000000000000000 --- a/devui/tags/demo/tags.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TagsDemoComponent from './tags-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TagsDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/tags/doc/api-cn.md b/devui/tags/doc/api-cn.md deleted file mode 100644 index 2d90fe1e06e365cdf83e7d32a947df90ab049bf0..0000000000000000000000000000000000000000 --- a/devui/tags/doc/api-cn.md +++ /dev/null @@ -1,47 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { TagsModule } from 'ng-devui/tags'; -``` - -在页面中使用: -```html - -``` -# Tags - -## d-tag 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----------------: | :-----------: | :-------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | -| tag | `string` | -- | 必选,记录输入的标签和选择的标签 | [单个标签](demo#single-tag) | -| mode | `ITagMode` | 'default' | 可选,标签的类型 `'default' \| 'checkable' \| 'closeable'` | [单个标签](demo#single-tag) | -| titleContent | `string` | -- | 可选,设置鼠标悬浮时 title 的显示内容 | [单个标签](demo#single-tag) | -| labelStyle | `string` | '' | 可选,标签的样式 可使用'blue-w98'、'aqua-w98' 、'olivine-w98' 、'green-w98' 、'yellow-w98' 、'orange-w98'、'pink-w98'、'red-w98'、'purple-w98',或可传入自定义 class | [单个标签](demo#single-tag) | -| deletable | `boolean` | false | 可选,设置标签是否可删除 | [单个标签](demo#single-tag) | -| customViewTemplate | `TemplateRef` | -- | 可选,自定义标签模板 | [单个标签](demo#single-tag) | -| checked | `boolean` | false | 可选,标签选中的初始状态 | [单个标签](demo#single-tag) | -| customColor | `string` | '' | 可选,传入颜色字符串(如'#f50'),自定义彩色标签的颜色 | [单个标签](demo#single-tag) | - -## d-tag 事件 - -| 事件名称 | 类型 | 描述 | 跳转 Demo | -| :-----------: | :----------------------------------------: | :-------------------------------- | -------------------------------------------- | -| tagDelete | `EventEmitter<{ tag: tag, event: event }>` | 删除 tag 的时候触发的事件 | [单个标签](demo#single-tag) | -| checkedChange | `EventEmitter` | tag 的 check 状态改变时触发的事件 | | - -## d-tags 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------: | :--------: | :-------: | :--------------------------------------------------------- | ------------------------------------------ | -| tags | `Array` | [] | 必选,记录输入的标签和选择的标签 | [标签组](demo#tags-group) | -| mode | `ITagMode` | 'default' | 可选,标签的类型 `'default' \| 'checkable' \| 'closeable'` | [标签组](demo#tags-group) | -| displayProperty | `string` | '' | 可选,设置属性名,使得标签名为该属性对应的值 | [标签组](demo#tags-group) | -| deletable | `boolean` | false | 可选,设置标签是否可删除 | [标签组](demo#tags-group) | -| titleProperty | `string` | '' | 可选,设置属性名,鼠标悬浮时 title 显示的值 | [标签组](demo#tags-group) | - -## d-tags 事件 - -| 事件名称 | 类型 | 描述 | 跳转 Demo | -| :-------: | :------------------------------------------------------: | :---------------------------- | ------------------------------------------ | -| tagDelete | `EventEmitter<{ tag: tag, index: index, event: event }>` | 删除某个 tag 的时候触发的事件 | [标签组](demo#tags-group) | diff --git a/devui/tags/doc/api-en.md b/devui/tags/doc/api-en.md deleted file mode 100644 index c7ba9df91441536faca55055ef04c621b785a46a..0000000000000000000000000000000000000000 --- a/devui/tags/doc/api-en.md +++ /dev/null @@ -1,44 +0,0 @@ -# How to use -Import into module: -```ts -import { TagsModule } from 'ng-devui/tags'; -``` - -In the page: -```html - -``` -# Tags - -## d-tag parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------------------: | :-----------: | :-----: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -| tag | `string` | -- | Required. The entered tag and selected tag are recorded. | [Single Tag](demo#single-tag) | -| titleContent | `string` | -- | Optional. Sets the title displayed when the cursor is hovered. | [Single Tag](demo#single-tag) | -| labelStyle | `string` | '' | Optional. The label can be blue-w98, aqua-w98, olivine-w98, green-w98, yellow-w98, orange-w98, pink-w98, red-w98, or purple-w98, you can also transfer a custom class. | [Single Tag](demo#single-tag) | . | -| deleteable | `boolean` | false | Optional. Specifies whether a tag can be deleted. | [Single Tag](demo#single-tag) | -| customViewTemplate Template | `TemplateRef` | -- | Optional. Custom tag template. | [Single Tag](demo#single-tag) | -| checked | `boolean` | false | Optional. Initial status of a tag. selected. | [Single Tag](demo#single-tag) | -| customColor | `string` | '' | Optional. Enter a color string (for example, '#f50') and customize the color label. | [Single Tag](demo#single-tag) | - -## d-tag event - -| Event name | Type | Description | Jump to Demo | -| :--------: | :--------------------------------------: | :------------------------------------ | ---------------------------------------------- | -| tagDelete | `EventEmitter<{tag: tag, event: event}>` | Event triggered when a tag is deleted. | [Single Tag](demo#single-tag) | - -## d-tags parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------: | :-------: | :-----: | :-------------------------------------------------------------------------------------------------- | --------------------------------------------- | -| tags | `Array` | [] | Required. It records the entered tag and selected tag. | [Tag Group](demo#tags-group) | -| displayProperty | `string` | '' | Optional. Set the attribute name to the value of the attribute. | [Tag Group](demo#tags-group) | -| deleteable | `boolean` | false | Optional. Specifies whether a tag can be deleted. | [Tag Group](demo#tags-group) | -| titleProperty | `string` | '' | Optional. Sets the attribute name. When the cursor is hovered, the value of the title is displayed. | [Tag Group](demo#tags-group) | - -## d-tags event - -| Event name | Type | Description | Jump to Demo | -| :--------: | :----------------------------------------------------: | :------------------------------------ | --------------------------------------------- | -| tagDelete | `EventEmitter<{tag: tag, index: index, event: event}>` | Event triggered when a tag is deleted. | [Tag Group](demo#tags-group) | diff --git a/devui/text-input/demo/text-input-demo.tsx b/devui/text-input/demo/text-input-demo.tsx deleted file mode 100644 index fbfc389ac0453ceb346d24ab9c604307cbb306df..0000000000000000000000000000000000000000 --- a/devui/text-input/demo/text-input-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-text-input-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-text-input-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/text-input/demo/text-input.route.ts b/devui/text-input/demo/text-input.route.ts deleted file mode 100644 index 52fe195c041001c994cbe5036fcf221324830274..0000000000000000000000000000000000000000 --- a/devui/text-input/demo/text-input.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TextInputDemoComponent from './text-input-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TextInputDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/text-input/doc/api-cn.md b/devui/text-input/doc/api-cn.md deleted file mode 100644 index 34be38cee214eed9da24962656041bd17805c6f6..0000000000000000000000000000000000000000 --- a/devui/text-input/doc/api-cn.md +++ /dev/null @@ -1,23 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { TextInputModule } from 'ng-devui/text-input'; -``` - -在页面中使用: - -```xml - -``` - -# dTextInput -## dTextInput 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :-------: | :---: | :--------------------------: | ----------------------------------------------- | -| id | `string` | -- | 可选,文本框 id |[基本用法](demo#basic-usage)| -| placeholder | `string` | -- | 可选,文本框 placeholder | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,文本框是否被禁用 | [基本用法](demo#basic-usage) | -| error | `boolean` | false | 可选,文本框是否出现输入错误 | [基本用法](demo#basic-usage) | diff --git a/devui/text-input/doc/api-en.md b/devui/text-input/doc/api-en.md deleted file mode 100644 index 9144e9365bea494657c152e5836f88cbfb131f4d..0000000000000000000000000000000000000000 --- a/devui/text-input/doc/api-en.md +++ /dev/null @@ -1,23 +0,0 @@ -# How to use - -Import into module: - -```ts -import { TextInputModule } from 'ng-devui/text-input'; -``` - -In the page: - -```xml - -``` - -# dTextInput -### dTextInput Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :-------: | :---: | :--------------------------: | ----------------------------------------------- | -| id | `string` | -- | Optional. Text-input ID | [Basic Usage](demo#basic-usage)| -| placeholder | `string` | -- | Optional. Text-input placeholder | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Indicating whether the Text-input is disabled. | [Basic Usage](demo#basic-usage) | -| error | `boolean` | false | Optional. Indicating whether an input error occurs in the Text-input. | [Basic Usage](demo#basic-usage) | diff --git a/devui/text-input/text-input.tsx b/devui/text-input/text-input.tsx deleted file mode 100644 index 8f23393d02fa4e0a9d1f4edb8c65af0087f6f59a..0000000000000000000000000000000000000000 --- a/devui/text-input/text-input.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-text-input', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-text-input
    - } - } -}) \ No newline at end of file diff --git a/devui/textarea/demo/textarea-demo.tsx b/devui/textarea/demo/textarea-demo.tsx deleted file mode 100644 index 59ee8c252362831176e59fffc4c738b50cca0221..0000000000000000000000000000000000000000 --- a/devui/textarea/demo/textarea-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-textarea-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-textarea-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/textarea/demo/textarea.route.ts b/devui/textarea/demo/textarea.route.ts deleted file mode 100644 index 178aedb03db65e8174fe1e3b103f4a9fb502b315..0000000000000000000000000000000000000000 --- a/devui/textarea/demo/textarea.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TextareaDemoComponent from './textarea-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TextareaDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/textarea/doc/api-cn.md b/devui/textarea/doc/api-cn.md deleted file mode 100644 index 711dfee9fd6bd1ebb785006002dc36651e695cfe..0000000000000000000000000000000000000000 --- a/devui/textarea/doc/api-cn.md +++ /dev/null @@ -1,24 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { TextareaModule } from 'ng-devui/textarea'; -``` - -在页面中使用: - -```xml - -``` - -# dTextarea -## dTextarea 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------: | :-----------------------------------------: | :---: | :----------------------------------------------------------------------------------: | --------------------------------------------- | -| id | `string` | -- | 可选,文本框 id | [基本用法](demo#basic-usage) | -| placeholder | `string` | -- | 可选,文本框 placeholder | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,文本框是否被禁用 | [基本用法](demo#basic-usage) | -| error | `boolean` | false | 可选,文本框是否出现输入错误 | [基本用法](demo#basic-usage) | -| resize | `none \| vertical \| horizontal \| both \| inherit` | none | 可选,文本框是否可调整大小,可选项:不可调整,水平调整,垂直调整,自由调整,默认继承 | [调整大小](demo#resize) | diff --git a/devui/textarea/doc/api-en.md b/devui/textarea/doc/api-en.md deleted file mode 100644 index bc07881651c4bc0818f61767a32537d7d1a28aeb..0000000000000000000000000000000000000000 --- a/devui/textarea/doc/api-en.md +++ /dev/null @@ -1,23 +0,0 @@ -# How to use - -Import into module: - -```ts -import { TextareaModule } from 'ng-devui/textarea'; -``` - -In the page: - -```xml - -``` -# dTextarea -## dTextarea Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------: | :-----------------------------------------: | :---: | :----------------------------------------------------------------------------------: | --------------------------------------------- | -| id | `string` | -- | Optional. Textarea ID | [Basic Usage](demo#basic-usage) | -| placeholder | `string` | -- | Optional. Textarea placeholder | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Indicating whether the textarea is disabled | [Basic Usage](demo#basic-usage) | -| error | `boolean` | false | Optional. Indicating whether an input error occurs in the textarea | [Basic Usage](demo#basic-usage) | -| resize | `none \| vertical \| horizontal \| both \| inherit` | none | Optional. Indicates whether the textarea can be resized. The options are as follows: Unadjustable, Horizontal, Vertical, and Free. The default value is inherited | [Resizable](demo#resize) | diff --git a/devui/textarea/textarea.tsx b/devui/textarea/textarea.tsx deleted file mode 100644 index 2dd6c8ede2a35723c4e10b90fff5bf064b2fe59a..0000000000000000000000000000000000000000 --- a/devui/textarea/textarea.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-textarea', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-textarea
    - } - } -}) \ No newline at end of file diff --git a/devui/time-axis/demo/time-axis-demo.tsx b/devui/time-axis/demo/time-axis-demo.tsx deleted file mode 100644 index b5447a3e2d95d9a50ebac364bcafa0d3b1d853f6..0000000000000000000000000000000000000000 --- a/devui/time-axis/demo/time-axis-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-time-axis-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-time-axis-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/time-axis/demo/time-axis.route.ts b/devui/time-axis/demo/time-axis.route.ts deleted file mode 100644 index 48c7b5e9162d0571ed5344c3d8d77bf745f403fe..0000000000000000000000000000000000000000 --- a/devui/time-axis/demo/time-axis.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TimeAxisDemoComponent from './time-axis-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TimeAxisDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/time-axis/doc/api-cn.md b/devui/time-axis/doc/api-cn.md deleted file mode 100644 index 40575c9e1bb15946e52e6b8fb2325052aa6ca2cf..0000000000000000000000000000000000000000 --- a/devui/time-axis/doc/api-cn.md +++ /dev/null @@ -1,57 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { TimeAxisModule } from 'ng-devui/time-axis'; -``` -在页面中使用: -``` - -``` - -# d-time-axis - -## d-time-axis 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------: | :------: | :--: | :-------------------------------------------------------- | -------------------------------------------------------- | -| data | `TimeAxisData` | -- | 可选,配置数据,是一个对象 | [基本用法](demo#basic-usage) | -| contentTemplate | `TemplateRef` | -- | 可选,内容模板,默认为空,当 model 为 `template` 时需要设置 | [内容使用模板自定义](demo#content-with-template) | - -## data 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------: | :--------------------------: | :--: | :-------------- | -------------------------------------------------------- | -| direction | `'vertical'\|'horizontal'` | '' | 可选,方向 | [设置方向](demo#direction) | -| position | `'left'\|'bottom'` | '' | 可选,时间点定位 | [基本用法](demo#basic-usage) | -| model | `'text'\|'html'\|'template'` | '' | 可选,模型 | [内容使用html](demo#content-with-html) | -| list | `array` | [] | 可选,列表数据 | [基本用法](demo#basic-usage) | - -## list 参数 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :----: | :-----------------------------------------: | :--: | :------------------------------------------------------- | ------------------------------------------------------ | -| time | `string` | -- | 可选,时间 | [基本用法](demo#basic-usage) | -| text | `string` | -- | 可选,文本内容 | [基本用法](demo#basic-usage) | -| type | `'primary'\|'success'\|'danger'\|'warning'` | -- | 可选,类型 | [设置方向](demo#direction) | -| status | `'runned'\|'running'` | -- | 可选,状态,默认为空,值可以是 runned 已完成,running 运行中 | [设置方向](demo#direction) | -| data | `array` | -- | 可选,模板数据,当 model 设置为 template 时生效 | [内容使用模板自定义](demo#content-with-template) | - -## TimeAxisData - -``` -interface TimeAxisData { - direction?: 'vertical' | 'horizontal'; - position?: 'bottom' | 'left'; - model: 'text' | 'html' | 'template'; - list: Array<{ - time?: string; - text?: string; - type?: 'primary' | 'success' | 'danger' | 'warning'; - status?: 'runned' | 'running' | ''; - iconClass?: string; - data?: any; - }>; -} -``` diff --git a/devui/time-axis/doc/api-en.md b/devui/time-axis/doc/api-en.md deleted file mode 100644 index e6c4a0143bacfbba12f66de09d776d23aa445683..0000000000000000000000000000000000000000 --- a/devui/time-axis/doc/api-en.md +++ /dev/null @@ -1,56 +0,0 @@ -# How to use - -Import into the module: -```ts -import { TimeAxisModule } from 'ng-devui/time-axis'; -``` -In the page: -``` - -``` - -# d-time-axis - -## d-time-axis parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------: | :------: | :--: | :-------------------------------------------------------- | -------------------------------------------------------- | -| data | `TimeAxisData` | -- | Optional, configuration data. It is an object. | [Basic usage](demo#basic-usage) | -| contentTemplate | `TemplateRef` | -- | Optional, Content template. This parameter is left empty by default. This parameter is mandatory when model is set to `template`. | [Customize content using a template](demo#content-with-template) | - -## data parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------: | :--------------------------: | :--: | :-------------- | -------------------------------------------------------- | -| direction | `'vertical'\|'horizontal'` |'' | Optional, direction | [Setting direction parameters](demo#direction) | -| position | `'left'\|'bottom'` |'' | Optional, It is used to locate the time point. | [Basic usage](demo#basic-usage) | -| model | `'text'\|'html'\|'template'` |'' | Optional, Model | [Content Use HTML](demo#content-with-html) | -| list | `array` | [] | Optional, List data | [Basic usage](demo#basic-usage) | - -## list parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----: | :-----------------------------------------: | :--: | :----------------------------------------------------------- | ----------------------------------------------- | -| time | `string` | -- | Optional, time | [Basic usage](demo#basic-usage) | -| text | `string` | -- | Optional, Text content | [Basic usage](demo#basic-usage) | -| type | `'primary'\|'success'\|'danger'\|'warning'` | -- | Optional, type | [Setting direction parameters](demo#direction) | -| status | `'runned'\|'running'` | -- | Optional, The default value is empty. The value can be runned or running. | [Setting direction parameters](demo#direction) | -| data | `array` | -- | Optional, Template data. This parameter is valid only when model is set to template. | [Customize content using a template](demo#content-with-template) | - -## TimeAxisData - -``` -interface TimeAxisData { - direction?: 'vertical' | 'horizontal'; - position?: 'bottom' | 'left'; - model: 'text' | 'html' | 'template'; - list: Array<{ - time?: string; - text?: string; - type?: 'primary' | 'success' | 'danger' | 'warning'; - status?: 'runned' | 'running' | ''; - iconClass?: string; - data?: any; - }>; -} -``` \ No newline at end of file diff --git a/devui/time-axis/time-axis.tsx b/devui/time-axis/time-axis.tsx deleted file mode 100644 index 689b4a2351a8ab1862d6f8e0abe287e5fe49f786..0000000000000000000000000000000000000000 --- a/devui/time-axis/time-axis.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-time-axis', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-time-axis
    - } - } -}) \ No newline at end of file diff --git a/devui/time-picker/demo/time-picker-demo.tsx b/devui/time-picker/demo/time-picker-demo.tsx deleted file mode 100644 index fc36e3e5c34f8697d9fc600041bd669c8a7ba92e..0000000000000000000000000000000000000000 --- a/devui/time-picker/demo/time-picker-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-time-picker-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-time-picker-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/time-picker/demo/time-picker.route.ts b/devui/time-picker/demo/time-picker.route.ts deleted file mode 100644 index 65bfd2d6d293a828eb35e81239969310a037e67b..0000000000000000000000000000000000000000 --- a/devui/time-picker/demo/time-picker.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TimePickerDemoComponent from './time-picker-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TimePickerDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/time-picker/doc/api-cn.md b/devui/time-picker/doc/api-cn.md deleted file mode 100644 index 941f7a66ecfc7886ad745a7d3a82cf4699abbded..0000000000000000000000000000000000000000 --- a/devui/time-picker/doc/api-cn.md +++ /dev/null @@ -1,52 +0,0 @@ -# 如何使用 - -在module中引入: - -``` -import { TimePickerModule } from 'ng-devui/time-picker'; -``` -在页面中使用: -``` - -``` -# TimePicker - -## TimePicker参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转Demo | -| :-----------------------: | :------------: | :--------: | :-------------------------------------------| :-----------------------------------------------------------------| -| disabled | `boolean` | false | 可选,禁用选择 |[基本用法](demo#basic-usage) | -| timePickerWidth | `number` | -- | 可选,下拉框的宽度 |[基本用法](demo#basic-usage) | -| autoOpen | `boolean` | false | 可选,初始化是否直接展开 |[基本用法](demo#basic-usage) | -| format | `string` | 'hh:mm:ss' | 可选,传入格式化,控制时间格式 |[格式化](demo#format) | -| minTime | `string` | '00:00:00' | 可选,限制最小可选时间 |[格式化](demo#format) | -| maxTime | `string` | '23:59:59' | 可选,限制最大可选时间 |[格式化](demo#format) | -| customViewTemplate | `TemplateRef` | -- | 可选,自定义快捷设置时间或自定义操作区内容 |[传入模板](demo#custom) | -| appendToBodyDirections | `Array` | `['rightDown', 'leftDown', 'rightUp', 'leftUp']` | 方向数组优先采用数组里靠前的位置 | -- | - -## TimePicker事件 - -| 事件 | 类型 | 说明 | 跳转Demo | -| :----------------: | :--------------------: | :------------------------------------------: | :------------------------------------------------------------------| -| selectedTimeChange | `EventEmitter` | 可选,确定的时候会发出新激活的子项的数据 |[基本用法](demo#basic-usage) | - -## 可调用的组件内部方法 - -详情参见[传入模板](demo#custom) - -```TypeScript -// 参数timeObj为必传,选择对应时间,触发selectedTimeChange -chooseTime(timeObj) -// 其中必须包含time:他是一个时间字符串,若不传type,则time必须是完整的时间,并且会直接选中对应时间,若传type,则time必须是单个时间,并且会选中对应的事件 -// type为可选:他是一个字符串,并且只能传'hh'、'mm'、'ss'的其中一个,大小写不敏感,需要和上述time结合使用 -TimeObj { - time: string; - type?: string; -} -// 参数timeObj为必传,选择对应时间,触发confirmTimeChange -confirmTime(timeObj) -// 清空已选择的时间 -clearAll() -// 隐藏选择器,在调用chooseTime的时候不会触发关闭,需要自行手动关闭,在调用confirmTime的时候会直接关闭 -hide() -``` diff --git a/devui/time-picker/doc/api-en.md b/devui/time-picker/doc/api-en.md deleted file mode 100644 index 6497e9b7649ad5f125c50817ce9cf88d5778e495..0000000000000000000000000000000000000000 --- a/devui/time-picker/doc/api-en.md +++ /dev/null @@ -1,53 +0,0 @@ -# How to use - -Import into module: - -``` -import {TimePickerModule} from' ng-devui/time-picker'; -``` -In the page: -``` - -``` - -# TimePicker - -## TimePicker Parameters - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------------------: | :------------: | :--------: | :-------------------------------------------| :-----------------------------------------------------------------| -| disabled | `boolean` | false | Optional. Disable selection. | [Basic usage](demo#basic-usage) | -| timePickerWidth | `number` | -- | Optional, width of the drop-down list box | [Basic usage](demo#basic-usage) | -| autoOpen | `boolean` | false | Optional, indicating whether to expand the initialization directly. | [Basic usage](demo#basic-usage) | -| format | `string` | 'hh:mm:ss' | Optional. The input format is used to control the time format. | [Format](demo#format) | -| minTime | `string` | '00:00:00' | Optional. The minimum available time is limited. | [formatting](demo#format) | -| maxTime | `string` | '23:59:59' | Optional. The maximum time allowed is limited. | [formatting](demo#format) | -| customViewTemplate | `TemplateRef` | -- | Optional. Customize the time or content in the operation area. | [Input template](demo#custom) | -| appendToBodyDirections | `Array` | ` ['rightDown','leftDown','rightUp','leftUp']` | The first position in the array is preferred for the direction array. | -- | - -## TimePicker Event - -| Event | Type | Description | Jump Demo | -| :----------------: | :--------------------: | :------------------------------------------: | :------------------------------------------------------------------| -| selectedTimeChange | `EventEmitter` |: optional. When you confirm it, the data of the newly activated subitem is sent. | [Basic usage](demo#basic-usage) | - -## Internal methods that can be invoked - -For details, see(demo#custom). - -```TypeScript -// The timeObj parameter is mandatory. Select the corresponding time to trigger selectedTimeChange. -chooseTime(timeObj) -// The value must contain time: a time character string. If type is not transferred, the value of time must be a complete time and the corresponding time is selected. If type is transferred, the value of time must be a single time and the corresponding event is selected. -// type is optional. It is a character string and can only be hh, mm, or ss. The value is case-insensitive and must be used together with time. -TimeObj { -time: string; -type? : string; -} -// The timeObj parameter is mandatory. Select the corresponding time to trigger confirmTimeChange. -confirmTime(timeObj) -// Clear the selected time. -clearAll() -// Hide the selector. The selector is not closed when chooseTime is called. You need to manually close the selector. The selector is directly closed when confirmTime is called. -hide() -``` diff --git a/devui/time-picker/time-picker.tsx b/devui/time-picker/time-picker.tsx deleted file mode 100644 index 946613a2f51628e202b3052d9780aa5a4c66fb9d..0000000000000000000000000000000000000000 --- a/devui/time-picker/time-picker.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-time-picker', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-time-picker
    - } - } -}) \ No newline at end of file diff --git a/devui/toast/demo/toast-demo.tsx b/devui/toast/demo/toast-demo.tsx deleted file mode 100644 index 2781b03502dc2a43fcfe0ac946007fc2f6c2dd0d..0000000000000000000000000000000000000000 --- a/devui/toast/demo/toast-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-toast-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-toast-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/toast/demo/toast.route.ts b/devui/toast/demo/toast.route.ts deleted file mode 100644 index 4000ac6682580a18ad3be8ad61b9643744ae70d8..0000000000000000000000000000000000000000 --- a/devui/toast/demo/toast.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ToastDemoComponent from './toast-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ToastDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/toast/doc/api-cn.md b/devui/toast/doc/api-cn.md deleted file mode 100644 index 434c8da3c72e084c879b3c42ca542362065cbea8..0000000000000000000000000000000000000000 --- a/devui/toast/doc/api-cn.md +++ /dev/null @@ -1,48 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { ToastModule } from 'ng-devui/toast'; -``` - -在页面中使用: - -```xml - -``` - -# d-toast - -## d-toast 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------: | :--------------------------: | :----: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | -| value | [`Array`](#message) | -- | 必选,消息内容数组,Message 对象定义见下文 | [基本用法](demo#basic-usage) | -| life | `number` | 5000 | 可选,超时时间,超时后自动消失,鼠标悬停可以阻止消失,单位毫秒。普通、成功、提示类默认为 5000 毫秒,错误、警告类默认为 10000 毫秒 | [超时时间](demo#life) | -| lifeMode | `string` | global | 可选,超时时间模式,预设值为 global 和 single 。默认为 global,所有消息使用 life 或群组第一个消息的预设超时时间; 设置为 single 时, 每个消息使用自身的超时时间,参见 Message 中的 life 定义 | [每个消息使用单独的超时时间](demo#single) | -| sticky | `boolean` | false | 可选,是否常驻,默认自动关闭 | -| style | `string` | -- | 可选,样式 | -| styleClass | `string` | -- | 可选,类名 | - -## d-toast 事件 - -| 参数 | 类型 | 说明 | -| :---------: | :-----------------------: | :----------------------------------------------------------------------------- | -| closeEvent | `EventEmitter` | 可选,返回被手动关闭或自动消失的单条消息内容 | -| valueChange | `EventEmitter` | 可选,返回变化(手动关闭或自动消失)后剩余消息内容数组,Message 对象定义见下文 | - -# 接口 & 类型定义 - -### Message - -```ts -export interface Message { - severity?: string; // 预设值有 common、success、error、warn、info,超时时间参见 life 说明,未设置或非预设值时超时时间为 5000 毫秒,warn 和 error 为 10000 毫秒 - summary?: string; // 消息标题。当设置超时时间,未设置标题时,不展示标题和关闭按钮 - detail?: string; // 消息内容,推荐使用content替换 - content?: string | TemplateRef; // 消息内容,支持纯文本和模板,推荐使用 - life?: number; // 单个消息超时时间,需设置 lifeMode 为 single 。每个消息使用自己的超时时间,开启该模式却未设置时按 severity 判断超时时间 - id?: any; // 消息ID -} -``` diff --git a/devui/toast/doc/api-en.md b/devui/toast/doc/api-en.md deleted file mode 100644 index 8cf9d1504ea169ba4c6341bfb98a197454ea5861..0000000000000000000000000000000000000000 --- a/devui/toast/doc/api-en.md +++ /dev/null @@ -1,48 +0,0 @@ -# How to use - -Import into module: - -```ts -import { ToastModule } from 'ng-devui/toast'; -``` - -In the page: - -```xml - -``` - -# d-toast - -## d-toast Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------: | :--------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -| value | [`Array`](#message) | -- | Required. Message content array. For details about the message object definition, see the following description. | [Basic usage](demo#basic-usage) | -| life | `number` | 5000 | Optional. Timeout interval, in milliseconds. The timeout interval disappears automatically. You can move the mouse to stop the timeout interval. The default value is 5000 milliseconds for common, success, and info , and 10000 milliseconds for error and warn. | [Timeout interval](demo#life) | -| lifeMode | `string` | global | Optional. The default value is global or single. The default value is global, indicating that all messages use the preset timeout interval of life or the first message in a group. If this parameter is set to single, each message uses its own timeout interval. For details, see the definition of life in Message. | [Each message uses a separate timeout interval.](demo#single) | -| sticky | `boolean` | false | Optional. Indicating whether the database is permanently configured. This parameter is automatically disabled by default. | -| style | `string` | -- | Optional. Style | -| styleClass | `string` | -- | Optional. Class name | - -## d-toast event - -| Parameter | Type | Description | -| :---------: | :-----------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| closeEvent | `EventEmitter` | Optional. Indicates the content of a message that is manually closed or disappears automatically. This parameter is optional. | -| valueChange | `EventEmitter` | Optional. Indicates the array of remaining message content after the change (manually closed or automatically disappears). For details about the Message object definition, see the following description. | - -# 接口 & 类型定义 - -### Message - -```ts -export interface Message { - severity?: string; // The preset values include common, success, error, warn, and info. For details about the timeout interval, see the life description. If the timeout interval is not set or is not set, the timeout interval is 5000 ms, and the warn and error are 10000 ms. - summary?: string; // Message title. If the timeout interval is set but no title is set, the title and close button are not displayed. - detail?: string; // Message content, content replacement is recommended. - content?: string | TemplateRef; // Message content. Plain text and template are supported. Recommended. - life?: number; // Timeout interval of a single message. Set lifeMode to single. Each message uses its own timeout interval. If this mode is enabled but is not set, the timeout interval is determined based on severity. - id?: any; // Message ID. -} -``` diff --git a/devui/toast/toast.tsx b/devui/toast/toast.tsx deleted file mode 100644 index 65f6ca822b15672cc621d07f31edab911b4bcdc1..0000000000000000000000000000000000000000 --- a/devui/toast/toast.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-toast', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-toast
    - } - } -}) \ No newline at end of file diff --git a/devui/toggle/demo/toggle-demo.tsx b/devui/toggle/demo/toggle-demo.tsx deleted file mode 100644 index 4c35eae9de91880093d13a268e8700d01278b7d2..0000000000000000000000000000000000000000 --- a/devui/toggle/demo/toggle-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-toggle-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-toggle-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/toggle/demo/toggle.route.ts b/devui/toggle/demo/toggle.route.ts deleted file mode 100644 index 883b869287aa8ea7d261744e21b7cb5f4ce40891..0000000000000000000000000000000000000000 --- a/devui/toggle/demo/toggle.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ToggleDemoComponent from './toggle-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: ToggleDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/toggle/doc/api-cn.md b/devui/toggle/doc/api-cn.md deleted file mode 100644 index 418e0d2489cfcf3ac8f3b06eb8ed9d1e178de75b..0000000000000000000000000000000000000000 --- a/devui/toggle/doc/api-cn.md +++ /dev/null @@ -1,28 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { ToggleModule } from 'ng-devui/toggle'; -``` - -在页面中使用: -```html - -``` -# Toggle - -## d-toggle 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----------: | :-----------------------------: | :---: | :-------------------------------------------------------------------------- | ------------------------------------------- | -| size | `'sm'\|''\|'lg'` | '' | 可选,开关尺寸大小 | [基本用法](demo#basic-usage) | -| color | `string` | -- | 可选,开关打开时的自定义颜色 | [自定义样式](demo#custom) | -| checked | `boolean` | false | 可选,开关是否打开,默认关闭 | [基本用法](demo#basic-usage) | -| ngModel | `boolean` | false | 可选,指定当前是否打开,可双向绑定 | [双向绑定](demo#two-binding) | -| disabled | `boolean` | false | 可选,是否禁用开关 | [基本用法](demo#basic-usage) | -| beforeChange | `Function\|Promise\|()=> Observable` | -- | 可选,开关变化前的回调函数,返回 boolean 类型,返回 false 可以阻止开关的变化 | [双向绑定](demo#two-binding) | - -## d-toggle 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :----: | :---------------------: | :------------------------------------ | ------------------------------------------- | -| change | `EventEmitter` | 可选,开关打开返回 true,关闭返回 false | [回调事件](demo#callback) | diff --git a/devui/toggle/doc/api-en.md b/devui/toggle/doc/api-en.md deleted file mode 100644 index 14ee556ca2ac505c38a949dfa5865f03d428d5cf..0000000000000000000000000000000000000000 --- a/devui/toggle/doc/api-en.md +++ /dev/null @@ -1,28 +0,0 @@ -# How to use -Import into module: -```ts -import { ToggleModule } from 'ng-devui/toggle'; -``` - -In the page: -```html - -``` -# Toggle - -### d-toggle parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :----------: | :-----------------------------: | :---: | :-------------------------------------------------------------------------- | ------------------------------------------- | -| size | `'sm'\|''\|'lg'` |'' | Optional. Switch size. | [Basic Usage](demo#basic-usage) | -| color | `string` | -- | Optional. Customized color when the switch is enabled. | [Custom Style](demo#custom) | -| checked | `boolean` | false | Optional. Specifies whether to enable the function. The function is disabled by default. | [Basic Usage](demo#basic-usage) | -| ngModel | `boolean` | false | Optional. Specifies whether to enable the function. Bidirectional binding is supported. | [Two-way Binding](demo#two-binding) | -| disabled | `boolean` | false | Optional. Indicating whether to disable the function. | [Basic Usage](demo#basic-usage) | -| beforeChange | `Function\|Promise\|()=> Observable` | -- |Optional. Callback function before a switch is changed. The return value is of the boolean type. If false is returned, the switch is not changed. | [Two-way Binding](demo#two-binding) | - -### d-toggle event - -| Event | Type | Description | Jump to Demo | -| :----: | :---------------------: | :------------------------------------ | ------------------------------------------- | -| change | `EventEmitter` | Optional. If the function is enabled, true is returned. If the function is disabled, false is returned. | [Callback Event](demo#callback) | diff --git a/devui/toggle/toggle.tsx b/devui/toggle/toggle.tsx deleted file mode 100644 index d998a0f68d76e911fb8a92eb9e910758d59f0efc..0000000000000000000000000000000000000000 --- a/devui/toggle/toggle.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-toggle', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-toggle
    - } - } -}) \ No newline at end of file diff --git a/devui/tooltip/demo/tooltip-demo.tsx b/devui/tooltip/demo/tooltip-demo.tsx deleted file mode 100644 index b442322ecf68b195ea83d59b87cf71cc102ae0a9..0000000000000000000000000000000000000000 --- a/devui/tooltip/demo/tooltip-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tooltip-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tooltip-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tooltip/demo/tooltip.route.ts b/devui/tooltip/demo/tooltip.route.ts deleted file mode 100644 index 9487805e08f67e1b625d94083bb9b3f2787adcf4..0000000000000000000000000000000000000000 --- a/devui/tooltip/demo/tooltip.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TooltipDemoComponent from './tooltip-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TooltipDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/tooltip/doc/api-cn.md b/devui/tooltip/doc/api-cn.md deleted file mode 100644 index 45ed3303dcb567c33f7ed949979c8fdaf6a250b6..0000000000000000000000000000000000000000 --- a/devui/tooltip/doc/api-cn.md +++ /dev/null @@ -1,34 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { TooltipModule } from 'ng-devui/tooltip'; -``` - -在页面中使用: - -```html - - -``` - -# dTooltip - -## dTooltip 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :-------------: | :-------------------------------------------------: | :--------------------------------: | :-------------------------------------------------: | ------------------------------ | -| content | `string\|DOMString` | -- | 必选,tooltip 显示内容 | [基本用法](demo#basic-usage) | -| position | [`PositionType`](#positiontype) `\| PositionType[]` | ['top', 'right', 'bottom', 'left'] | 可选,tooltip 显示位置 | [基本用法](demo#basic-usage) | -| showAnimate | `boolean` | false | 可选,是否显示划出动画 | [基本用法](demo#basic-usage) | -| mouseEnterDelay | `number` | 150 | 可选,鼠标移入后延时多少才显示 Tooltip,单位是 `ms` | [延时触发](demo#delay-trigger) | -| mouseLeaveDelay | `number` | 100 | 可选,鼠标移出后延时多少才隐藏 Tooltip,单位是 `ms` | [延时触发](demo#delay-trigger) | - -# 接口 & 类型定义 - -### PositionType - -```ts -export type PositionType = 'left' | 'right' | 'top' | 'bottom'; -``` diff --git a/devui/tooltip/doc/api-en.md b/devui/tooltip/doc/api-en.md deleted file mode 100644 index 91b5c469d715c82f28abe4ae46af48a35485ea33..0000000000000000000000000000000000000000 --- a/devui/tooltip/doc/api-en.md +++ /dev/null @@ -1,34 +0,0 @@ -# How to use - -Import into module - -```ts -import { TooltipModule } from 'ng-devui/tooltip'; -``` - -In the page - -```html - - -``` - -# dTooltip - -### dTooltip Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------: | :-------------------------------------------------: | :--------------------------------: | :-------------------------------------------------------------------------------: | ----------------------------------- | -| content | `string\|DOMString` | -- | Required. Tooltip display content | [Basic Usage](demo#basic-usage) | -| position | [`PositionType`](#positiontype) `\| PositionType[]` | ['top', 'right', 'bottom', 'left'] | Optional. Tooltip display position | [Basic Usage](demo#basic-usage) | -| showAnimate | `boolean` | false | Optional. Whether to display the drawing animation | [Basic Usage](demo#basic-usage) | -| mouseEnterDelay | `number` | 150 | Optional. Delay for displaying Tooltip after the mouse is enter. The unit is `ms` | [Delay Trigger](demo#delay-trigger) | -| mouseLeaveDelay | `number` | 100 | Optional. Delay for hiding Tooltip after the mouse is leave, The unit is `ms` | [Delay Trigger](demo#delay-trigger) | - -# Interface & Type Definition - -### PositionType - -```ts -export type PositionType = 'left' | 'right' | 'top' | 'bottom'; -``` diff --git a/devui/tooltip/tooltip.tsx b/devui/tooltip/tooltip.tsx deleted file mode 100644 index a84a0c67629310c2a9e6c695891760f5b330a6f3..0000000000000000000000000000000000000000 --- a/devui/tooltip/tooltip.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tooltip', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tooltip
    - } - } -}) \ No newline at end of file diff --git a/devui/transfer/demo/transfer-demo.tsx b/devui/transfer/demo/transfer-demo.tsx deleted file mode 100644 index de3341b01f3761ceab28e44155d2ca77b5d13396..0000000000000000000000000000000000000000 --- a/devui/transfer/demo/transfer-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-transfer-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-transfer-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/transfer/demo/transfer.route.ts b/devui/transfer/demo/transfer.route.ts deleted file mode 100644 index 9618e4bd36f0e93b4d0cd36ab4dee9b9fcf59cad..0000000000000000000000000000000000000000 --- a/devui/transfer/demo/transfer.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TransferDemoComponent from './transfer-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TransferDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/transfer/doc/api-cn.md b/devui/transfer/doc/api-cn.md deleted file mode 100644 index 7d13f18391bb991f6f94488980a05c0ab578c2bd..0000000000000000000000000000000000000000 --- a/devui/transfer/doc/api-cn.md +++ /dev/null @@ -1,32 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { TransferModule } from 'ng-devui/transfer'; -``` -在页面中使用: -```html - -``` - -# d-transfer - -## d-transfer 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | -| sourceOption | `array` | [] | 可选参数,穿梭框源数据 | [基本用法](demo#transfer-demo-base) | -| targetOption | `array` | [] | 可选参数,穿梭框目标数据 | [基本用法](demo#transfer-demo-base) | -| titles | `array` | [] | 可选参数,穿梭框标题 | [基本用法](demo#transfer-demo-base) | -| height | `string` | 320px | 可选参数,穿梭框高度 | -| isSearch | `number` | false | 可选参数,是否可以搜索 | [搜索穿梭框](demo#transfer-demo-search) | -| isSourceDroppable | `boolean` | false | 可选参数,源是否可以拖拽 | -| isTargetDroppable | `boolean` | false | 可选参数,目标是否可以拖拽 | [排序穿梭框](demo#transfer-demo-sort) | -| disabled | `boolean` | false | 可选参数 穿梭框禁止使用 | [基本用法](demo#transfer-demo-base) | -| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | 可选参数 在transfer事件发生前判断事件是否允许触发 | [基本用法](demo#transfer-demo-base) | - -## d-transfer 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | -| transferToSource | 返回穿梭框源和目标数据 | 当点击右穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | -| transferToTarget | 返回穿梭框源和目标数据 | 当点击左穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | diff --git a/devui/transfer/doc/api-en.md b/devui/transfer/doc/api-en.md deleted file mode 100644 index dabb0e54efe57ea93480b51e43fb475bc4c4210a..0000000000000000000000000000000000000000 --- a/devui/transfer/doc/api-en.md +++ /dev/null @@ -1,32 +0,0 @@ -# How To Use -Import into module: -```ts -import { TransferModule } from 'ng-devui/transfer'; -``` -In the page: -```html - -``` - -# d-transfer - -## d-transfer parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | -| sourceOption | `array` | [] | Optional. This parameter indicates the source data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| targetOption | `array` | [] | Optional. This parameter indicates the target data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| titles | `array` | [] | Optional. Title of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| height | `string` | 320px | Optional. It indicates the height of the shuttle box. | -| isSearch | `number` | false | Optional. Specifies whether to search. | [Search Shuttle Box](demo#transfer-demo-search) | -| isSourceDroppable | `boolean` | false | Optional. Indicates whether the source can be dragged. | -| isTargetDroppable | `boolean` | false | Optional. Indicates whether the object can be dragged. | [Sorting Shuttle Box](demo#transfer-demo-sort) | -| disabled | `boolean` | false | Optional. The shuttle box cannot be used. | [Basic Usage](demo#transfer-demo-base) | -| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | Optional. Determines whether the transfer event can be triggered before the transfer event occurs. | [Basic Usage](demo#transfer-demo-base) | - -## d-transfer event - -| Event | Type | Description | Jump to Demo | -| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | -| transferToSource | Return the source and target data in the shuttle box. | When you click the right button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | -| transferToTarget | Return the source and target data in the shuttle box. | When you click the left button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | diff --git a/devui/transfer/transfer.tsx b/devui/transfer/transfer.tsx deleted file mode 100644 index 3b5ff1415559d4a5b94d4a7df5d88abad42bea8d..0000000000000000000000000000000000000000 --- a/devui/transfer/transfer.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-transfer', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-transfer
    - } - } -}) \ No newline at end of file diff --git a/devui/tree-select/demo/tree-select-demo.tsx b/devui/tree-select/demo/tree-select-demo.tsx deleted file mode 100644 index cec2c1f338fb936bb85943435e425a631b2adbe9..0000000000000000000000000000000000000000 --- a/devui/tree-select/demo/tree-select-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tree-select-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tree-select-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tree-select/demo/tree-select.route.ts b/devui/tree-select/demo/tree-select.route.ts deleted file mode 100644 index 4e2259c0122aed1502288189106d1ade1ee1334f..0000000000000000000000000000000000000000 --- a/devui/tree-select/demo/tree-select.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TreeSelectDemoComponent from './tree-select-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TreeSelectDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/tree-select/doc/api-cn.md b/devui/tree-select/doc/api-cn.md deleted file mode 100644 index af5bd33f19bc804e8f9291822dd0b4d11c224f35..0000000000000000000000000000000000000000 --- a/devui/tree-select/doc/api-cn.md +++ /dev/null @@ -1,86 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { TreeSelectModule } from 'ng-devui/treeSelect'; -``` - -在页面中使用: - -```html - -``` -# d-tree-select - -## d-tree-select 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :------------------: | :-------------------------------------: | :-------------------------------------: | :------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | -| treeData | `Array` | -- | 必选,需要展示的源数据 | [基本用法](demo#basic-usage) | -| placeholder | `string` | -- | 可选,占位字符串 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,禁止输入态 | [基本用法](demo#basic-usage) | -| expandTree | `boolean` | false | 可选,是否自动展开树 | [基本用法](demo#basic-usage) | -| multiple | `boolean` | false | 可选,多选开关 | [基本用法](demo#basic-usage) | -| treeNodeIdKey | `string` | 'id' | 可选,id 键值名 | [设置key](demo#keys) | -| treeNodeChildrenKey | `string` | 'children' | 可选,children 子节点键值名 | [设置key](demo#keys) | -| treeNodeTitleKey | `string` | 'title' | 可选,title 键值名 | [设置key](demo#keys) | -| disabledKey | `string` | 'disabled' | 可选,disabled 节点禁选键值名 | [基本用法](demo#basic-usage) | -| leafOnly | `boolean` | false | 可选,仅叶节点可选开关 | [仅叶节点可选](demo#leaf-only) | -| delimiter(废弃) | `string` | `,` | 可选,选中结果分隔符(用于多选) | -| iconParentOpen | `string` | DefaultIcons.iconParentOpen | 可选,树节点打开时图标 | [设置节点展开关闭图标](demo#icon-parent) | -| iconParentClose | `string` | DefaultIcons.iconParentClose | 可选,树节点关闭时图标 | [设置节点展开关闭图标](demo#icon-parent) | -| iconLeaf | `string` | DefaultIcons.iconLeaf | 可选,节点图标 | [设置key](demo#keys) | -| closeOnNodeSelected | `boolean` | true | 可选,选中节点时关闭下拉框的开关(仅用于单选) | [设置key](demo#keys) | -| width | `'auto' \| '~px' \| '~%'` | -- | 可选,下拉框宽度 | [基本用法](demo#basic-usage) | -| searchable | `boolean` | false | 可选,是否可搜索树 | [可简易搜索树](demo#simple-search) | -| readyEvent | `function` | (treeSelect: TreeSelectComponent) => {} | 可选,当组件初始化完成时可调用的钩子函数 | [初始化完成时调用的钩子](demo#init-hooks) | -| appendTo | `string` | -- | 可选,将下拉框附着到输入值的 DOM 选择器节点中,值为空时下拉框在此组件内 | [Append To Element 能力](demo#append-to-element) | -| allowUnselect | `boolean` | true | 可选,是否允许单选模式下反选已选中的项目 | [基本用法](demo#basic-usage) | -| iconTemplatePosition | `'before-checkbox' \| 'after-checkbox'` | 'before-checkbox' | 可选,自定义 template 的位置 | [自定义icon能力](demo#custom-icon) | -| allowClear | `boolean` | false | 可选,是否允许单选模式下点击输入框上的清除按钮来清空已选中的项目。`allowUnselect`必须为`true`,否则将破坏体验一致性规则。`enableLabelization`为`false`时才会生效 | [基本用法](demo#basic-usage) | -| enableLabelization | `boolean` | true | 可选,是否启用标签化展示效果,配合公有云视觉默认启用。 | [不使用标签化](demo#labelization) | -| iconTemplateInput | `TemplateRef` | -- | 可选,自定义 icon 的 template | [自定义icon能力](demo#custom-icon) | -| customViewTemplate | `TemplateRef` | -- | 可选,支持自定义区域显示内容定制 | [自定义区域](demo#custom-template) | -| customViewDirection | `'bottom' \| 'right'\| 'left'` | 'bottom' | 可选, customViewTemplate 所处的相对下拉列表的位置 | [自定义区域](demo#custom-template) | -| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动,常用于大数据量场景 | [虚拟滚动](demo#virtual-scroll) | -| virtualScrollHeightPx | `number` | 300 | 可选,设置虚拟滚动内容区域的高度 ,单位为`px` | [虚拟滚动](demo#virtual-scroll) | -| virtualScrollMinBufferPx | `number` | 600 | 可选,设置虚拟滚动时的最小 buffer 尺寸,单位为`px` ,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [虚拟滚动](demo#virtual-scroll) | -| virtualScrollMaxBufferPx | `number` | 900 | 可选, 设置虚拟滚动时的最大 buffer 尺寸,单位为`px` ,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [虚拟滚动](demo#virtual-scroll) | -| virtualScrollItemSize | `number` | 30 | 可选, 设置虚拟滚动内元素的尺寸,单位为`px` ,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [虚拟滚动](demo#virtual-scroll) | - -## d-tree-select 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :------------: | :------------: | :------------------------------------: | --------- | -| valueChanged | `EventEmitter>` | 可选,选择节点时触发的变化,返回值为当前选中的节点 | [基本用法](demo#basic-usage) | -| nodeToggleEvent | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,展开收起节点时触发,返回值为触发的节点 | [基本用法](demo#basic-usage) | - -# 接口 & 类型定义 - -### TreeNode - -```ts -export class TreeNode implements ITreeNodeData { - constructor(public id, public parentId, public data) {} -} - -export interface ITreeNodeData { - id?: number | string; - parentId?: number | string; - title?: string; - isOpen?: boolean; - data?: any; - isParent?: boolean; - loading?: boolean; - isMatch?: boolean; - isHide?: boolean; - isActive?: boolean; - isChecked?: boolean; - disabled?: boolean; - - [prop: string]: any; - - children?: []; -} -``` \ No newline at end of file diff --git a/devui/tree-select/doc/api-en.md b/devui/tree-select/doc/api-en.md deleted file mode 100644 index 8d754dc2a1520ce83ce3e192e4cfd5b25861c50b..0000000000000000000000000000000000000000 --- a/devui/tree-select/doc/api-en.md +++ /dev/null @@ -1,86 +0,0 @@ -# How to use - -Import into module: - -```ts -import { TreeSelectModule } from 'ng-devui/treeSelect'; -``` - -In the page: - -```html - -``` -# d-tree-select - -## d-tree-select Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :-------------------------------------: | :-------------------------------------: | :------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | -| placeholder | `string` | -- | Optional. placeholder string | [Basic usage](demo#basic-usage) | -| treeData | `Array` | -- | Required. Source data to be displayed. | [Basic usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. The input state is forbidden. | [Basic usage](demo#basic-usage) | -| expandTree | `boolean` | false | Optional. indicating whether to expand the tree automatically. | [Basic usage](demo#basic-usage) | -| multiple | `boolean` | false | Optional. It indicates the multi-choice switch. | [Basic usage](demo#basic-usage) | -| treeNodeIdKey | `string` | 'id' | Optional. ID key name | [Custom key](demo#keys) | -| treeNodeChildrenKey | `string` | 'children' | Optional. child node key name | [Custom key](demo#keys) | -| treeNodeTitleKey | `string` | 'title' | Optional. title key name | [Custom key](demo#keys) | -| disabledKey | `string` | 'disabled' | Optional. The disabled node cannot be selected. | [Basic usage](demo#basic-usage) | -| leafOnly | `boolean` | false | Optional. This parameter is optional only for leaf nodes. | [Only leaf nodes can be selected](demo#leaf-only) | -| delimiter (deprecated) | `string` | `,` | Optional. Selected result separator (used for multiple selections) | -| iconParentOpen | `string` | DefaultIcons.iconParentOpen | Optional. Icon when a tree node is opened | [Expand and close the icon](demo#icon-parent) | -| iconParentClose | `string` | DefaultIcons.iconParentClose | Optional. Icon when a tree node is closed | [Expand and close the icon](demo#icon-parent) | -| iconLeaf | `string` | DefaultIcons.iconLeaf | Optional. node icon. | [Custom key](demo#keys) | -| closeOnNodeSelected | `boolean` | true | Optional. When a node is selected, the drop-down list box is disabled (only for single selection). | [Custom key](demo#keys) | -| width | `'auto' \| '~px' \| '~%'` | -- | Optional. width of the drop-down list box | [Basic usage](demo#basic-usage) | -| searchable | `boolean` | false | Optional. indicating whether a tree can be searched. | [Simple search tree](demo#simple-search) | -| readyEvent | `function` | (treeSelect: TreeSelectComponent) => {} | Optional. Hook function that can be called when the component initialization is complete | [Hook called upon completion of initialization](demo#init-hooks) | -| appendTo | `string` | -- | Optional. Attach the drop-down list box to the DOM selector node of the input value. If the value is empty, the drop-down list box is in the component. | [Append To Element Capability](demo#append-to-element) | -| allowUnselect | `boolean` | true | Optional. Whether to allow deselecting selected items in single-select mode. | [Basic usage](demo#basic-usage) | -| iconTemplatePosition | `'before-checkbox' \|'after-checkbox'` | 'before-checkbox' | Optional. position of the customized template | [Customizing icons](demo#custom-icon) | -| allowClear | `boolean` | false | Optional. indicates whether to clear selected items by clicking the clear button in the text box in radio mode. The value of `allowUnselect` must be `true`. Otherwise, the experience consistency rule will be damaged. This parameter is valid only when the value of enableLabelization is false. | [Basic usage](demo#basic-usage) | -| enableLabelization | `boolean` | true | Optional. Indicates whether to enable the tagged display effect. This parameter is enabled by default when the public cloud visual function is used. | [Tag-based configuration](demo#labelization) | -| iconTemplateInput | `TemplateRef` | -- | Optional. Template of the customized icon | [Customizing icons](demo#custom-icon) | -| customViewTemplate | `TemplateRef` | -- | Optional. The display content of a customized region can be customized. | [Custom Area](demo#custom-template) | -| customViewDirection | `'bottom' \| 'right'\| 'left'` | 'bottom' | Optional, relative position of the customViewTemplate drop-down list box | [Custom Area](demo#custom-template) | -| virtualScroll | `boolean` | false | Optional. Specifies whether to enable virtual scrolling. This parameter is usually used in scenarios with a large amount of data. | [Virtual scrolling] (demo#virtual-scroll) | -| virtualScrollHeightPx | `number` | 300| Optional. Set the height of the virtual scrolling content area(`px`). | [Virtual scroll](demo#virtual-scroll) | -| virtualScrollMinBufferPx | `number` | 600 | Optional. Set the minimum buffer size during virtual scrolling(`px`). For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Virtual Scroll](demo#virtual-scroll) | -| virtualScrollMaxBufferPx | `number` | 900 | Optional. Set the maximum buffer size during virtual scrolling.(`px`) For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Virtual Scroll](demo#virtual-scroll) | -| virtualScrollItemSize | `number` | 30 | Optional. Set the element size in the virtual scrolling(`px`). For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Virtual Scroll](demo#virtual-scroll) | - -## d-tree-select Event - -| Event | Type | Description | Jump to Demo | -| :------------: | :------------: | :------------------------------------: | --------- | -| valueChanged | `EventEmitter>` | Optional.Changes triggered when a node is selected. The returned value is the currently selected node. | [Basic usage](demo#basic-usage) | -| nodeToggleEvent | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional.Triggered when a node is expanded or collapsed. The parameter is the triggered node. | [Basic usage](demo#basic-usage) | - - -# Interface & Type Definition -### TreeNode - -```ts -export class TreeNode implements ITreeNodeData { - constructor(public id, public parentId, public data) {} -} - -export interface ITreeNodeData { - id?: number | string; - parentId?: number | string; - title?: string; - isOpen?: boolean; - data?: any; - isParent?: boolean; - loading?: boolean; - isMatch?: boolean; - isHide?: boolean; - isActive?: boolean; - isChecked?: boolean; - disabled?: boolean; - - [prop: string]: any; - - children?: []; -} -``` \ No newline at end of file diff --git a/devui/tree-select/tree-select.tsx b/devui/tree-select/tree-select.tsx deleted file mode 100644 index 3fb1e81c10eb3662b55ea10e658a4959ca1c50a8..0000000000000000000000000000000000000000 --- a/devui/tree-select/tree-select.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tree-select', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tree-select
    - } - } -}) \ No newline at end of file diff --git a/devui/tree/demo/tree-demo.tsx b/devui/tree/demo/tree-demo.tsx deleted file mode 100644 index 96bf7a57cb012e322e909c049b05cc3e8a0c7b2c..0000000000000000000000000000000000000000 --- a/devui/tree/demo/tree-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tree-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tree-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/tree/demo/tree.route.ts b/devui/tree/demo/tree.route.ts deleted file mode 100644 index 6ae5117b538579e47b97cc3e5ef8212ae31de9e9..0000000000000000000000000000000000000000 --- a/devui/tree/demo/tree.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import TreeDemoComponent from './tree-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: TreeDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/tree/doc/api-cn.md b/devui/tree/doc/api-cn.md deleted file mode 100644 index bbc4ca294e7c070b1a719ea54729c9f5b914132b..0000000000000000000000000000000000000000 --- a/devui/tree/doc/api-cn.md +++ /dev/null @@ -1,278 +0,0 @@ -# 如何使用 - -在 module 中引入: - -```ts -import { TreeModule } from 'ng-devui/tree'; -``` - -在页面中使用: - -```html - -``` - -# d-tree - -## d-tree 参数 - -##### 基本的树,没有增删改查等操作 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-----------------: | :----------------------------------: | :-------------: | :----------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------ | -| tree | `Array<`[`ITreeItem`](#itreeitem)`>` | -- | 必选,根据传入的数据进行树的渲染 | [基本用法](demo#basic-usage) | -| treeNodeIdKey | `string` | 'id' | 可选,id 键值名,用来标识节点的唯一性 | [自定显示字段](demo#custom-display-field) | -| treeNodeChildrenKey | `string` | 'items' | 可选,子节点数组的键值名 | [自定显示字段](demo#custom-display-field) | -| treeNodeTitleKey | `string` | 'title' | 可选,节点显示数据的键值名 | [自定显示字段](demo#custom-display-field) | -| checkboxDisabledKey | `string` | 'disabled' | 可选,节点禁止点选 checkbox 的键值名 | [自定显示字段](demo#custom-display-field) | -| selectDisabledKey | `string` | 'disabled' | 可选,节点禁止选中的键值名 | [可勾选树](demo#checkable-tree) | -| toggleDisabledKey | `string` | 'disableToggle' | 可选,节点禁止展开收起的键值名 | [可勾选树](demo#checkable-tree) | -| iconParentOpen | `string` | -- | 可选,自定义父节点展开时的图标 | [自定义图标](demo#custom-icon) | -| iconParentClose | `string` | -- | 可选,自定义父节点收起时的图标 | [自定义图标](demo#custom-icon) | -| iconLeaf | `string` | -- | 可选,自定义叶子节点图标 | [自定义图标](demo#custom-icon) | -| treeNodesRef | `TemplateRef` | -- | 可选,自定义节点的显示模板 | -| loadingTemplateRef | `TemplateRef` | -- | 可选,自定义加载中的模板 | [自定义 loading 模板](demo#custom-loading) | -| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动,用于处理大数据量的情形 | [大数据量可操作树](demo#virtual-scroll) | -| virtualScrollHeight | `string` | '800px' | 可选,设置虚拟滚动时树的高度 | [大数据量可操作树](demo#virtual-scroll) | -| minBufferPx | `number` | 600 | 可选,设置虚拟滚动时的最小 buffer 尺寸,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [大数据量可操作树](demo#virtual-scroll) | -| maxBufferPx | `number` | 900 | 可选,设置虚拟滚动时的最大 buffer 尺寸,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [大数据量可操作树](demo#virtual-scroll) | -| showAnimation | `boolean` | true | 可选,是否展示动画 | [无动画](demo#without-animation) | - -## d-tree 事件 - -| 参数 | 类型 | 描述 | 跳转 Demo | -| :--------------: | :---------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| nodeSelected | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点选中的回调函数,返回当前选中节点的数据 | [基本用法](demo#basic-usage) | -| nodeDblClicked | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点双击时的回调函数,返回当前操作的节点的数据 | [自定显示字段](demo#custom-display-field) | -| nodeRightClicked | `EventEmitter<{event:MouseEvent,node:`[`TreeNode`](#treenode)`}>` | 可选,节点鼠标右键点击时的回调函数,返回当前操作的节点的数据以及鼠标事件 | [自定显示字段](demo#custom-display-field) | -| nodeToggled | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点展开收起的回调函数,返回当前操作的节点的数据 | [基本用法](demo#basic-usage) | -| afterTreeInit | `EventEmitter>` | 可选,树节点生成完毕后的回调事件,返回当前树的所有节点信息,多用于大数据量情况下需要渲染完成后执行特定操作 | 与 d-operable-tree 的[大数据量可操作树](demo#virtual-scroll)使用一致 | - -# d-operable-tree - -## d-operable-tree 参数 - -##### 鼠标滑过或者选中支持增删改按钮操作 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :-------------------: | :------------------------------------------: | :-------------: | :----------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------- | -| tree | `Array<`[`ITreeItem`](#itreeitem)`>` | -- | 必选,根据传入的数据进行树的渲染 | [可勾选树](demo#checkable-tree) | -| treeNodeIdKey | `string` | 'id' | 可选,id 键值名,用来标识节点的唯一性 | [可勾选树](demo#checkable-tree) | -| treeNodeChildrenKey | `string` | 'items' | 可选,子节点数组的键值名 | [可勾选树](demo#checkable-tree) | -| treeNodeTitleKey | `string` | 'title' | 可选,节点显示数据的键值名 | [可勾选树](demo#checkable-tree) | -| checkboxDisabledKey | `string` | 'disabled' | 可选,节点禁止点选的键值名 | [可勾选树](demo#checkable-tree) | -| selectDisabledKey | `string` | 'disabled' | 可选,节点禁止选中的键值名 | [可勾选树](demo#checkable-tree) | -| toggleDisabledKey | `string` | 'disableToggle' | 可选,节点禁止展开收起的键值名 | [可勾选树](demo#checkable-tree) | -| iconParentOpen | `string` | -- | 可选,自定义父节点展开时的图标 | [自定义图标](demo#custom-icon) | -| iconParentClose | `string` | -- | 可选,自定义父节点收起时的图标 | [自定义图标](demo#custom-icon) | -| iconLeaf | `string` | -- | 可选,自定义叶子节点图标 | [自定义图标](demo#custom-icon) | -| checkable | `boolean` | true | 可选,是否显示 checkbox,即是否为多选模式 | [操作按钮](demo#operation-button) | -| addable | `boolean` | false | 可选,是否显示新增子节点按钮 | [操作按钮](demo#operation-button) | -| editable | `boolean` | false | 可选,是否显示编辑子节点按钮 | [操作按钮](demo#operation-button) | -| deletable | `boolean` | false | 可选,是否显示删除子节点按钮 | [操作按钮](demo#operation-button) | -| draggable | `boolean` | false | 可选,树节点是否支持 drag、drop 操作 | [可拖拽树](demo#drag-and-drop-tree) | -| checkboxInput | [`ICheckboxInput`](#icheckboxinput) | {} | 可选,设置 checkbox 的相关属性 | [可勾选树](demo#checkable-tree) | -| canActivateNode | `boolean` | true | 可选,是否可以选中节点 ,false 时点击节点触发 nodeChecked 事件,不触发 nodeSelected 事件 | [操作按钮](demo#operation-button) | -| canActivateParentNode | `boolean` | true | 可选,父节点是否可选中,false 时点击节点触发 nodeChecked 事件,不触发 nodeSelected 事件 | [操作按钮](demo#operation-button) | -| iconTemplatePosition | `string` | -- | 可选,设置图标的位置,可选`'before-checkbox'`或`'after-checkbox'` | [自定义图标](demo#custom-icon) | -| checkableRelation | `'upward' \| 'downward' \| 'both' \| 'none'` | 'both' | 可选,设置父子节点的 check 规则 | [控制父子 check 关系](demo#check-control-tree) | -| beforeAddNode | `Promise` | -- | 可选,新增子节点前回调(参数为当前节点), 返回值中可指定添加节点的 index | [操作按钮](demo#operation-button) | -| beforeDeleteNode | `Promise` | -- | 可选,删除节点前回调(参数为当前节点) | [操作按钮](demo#operation-button) | -| beforeNodeDrop | `Promise` | -- | 可选,子节点内部拖动 drop 前回调(参数为当前拖动的节点,释放位置的节点,放置类型(`prev`,`inner`,`next`)) | [可拖拽树](demo#drag-and-drop-tree) | -| beforeEditNode | `Promise` | -- | 可选,子节点编辑前回调(参数为当前编辑的节点) | [操作按钮](demo#operation-button) | -| postAddNode | `Promise` | -- | 可选,新增节点后回调(参数为新增节点) | [操作按钮](demo#operation-button) | -| dropType | [`IDropType`](#idroptype) | -- | 可选,设置拖拽放置的位置,`dropPrev`为放置在节点前,`dropNext`为放置在节点后,`dropInner`为放置在节点中 | [可拖拽树](demo#drag-and-drop-tree) | -| virtualScroll | `boolean` | false | 可选,是否开启虚拟滚动,用于处理大数据量的情形 | [大数据量可操作树](demo#virtual-scroll) | -| virtualScrollHeight | `string` | '800px' | 可选,设置虚拟滚动时树的高度 | [大数据量可操作树](demo#virtual-scroll) | -| minBufferPx | `number` | 600 | 可选,设置虚拟滚动时的最小 buffer 尺寸,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [大数据量可操作树](demo#virtual-scroll) | -| maxBufferPx | `number` | 900 | 可选,设置虚拟滚动时的最大 buffer 尺寸,参考https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [大数据量可操作树](demo#virtual-scroll) | -| disableMouseEvent | `boolean` | false | 可选,设置是否禁用鼠标的移入移出事件,主要用于兼容使用 appendTobody 时无法悬停到下拉框内容的情况 | [自定义图标](demo#custom-icon) | -| showAnimation | `boolean` | true | 可选,是否展示动画 | [无动画](demo#without-animation) | - -## d-operable-tree 事件 - -| 参数 | 类型 | 描述 | 跳转 Demo | -| :----------------: | :------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -| nodeSelected | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点点击事件回调,返回当前选中节点的数据 | [可勾选树](demo#checkable-tree) | -| nodeDblClicked | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点双击时的回调函数,返回当前操作的节点的数据 | [可勾选树](demo#checkable-tree) | -| nodeRightClicked | `EventEmitter<{event:MouseEvent,node:`[`TreeNode`](#treenode)`}>` | 可选,节点鼠标右键点击时的回调函数,返回当前操作的节点的数据以及鼠标事件 | [可勾选树](demo#checkable-tree) | -| nodeDeleted | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点删除事件回调,返回当前删除节点的数据 | [操作按钮](demo#operation-button) | -| nodeToggled | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点展开收起事件回调,返回当前操作的节点的数据 | [可勾选树](demo#checkable-tree) | -| nodeChecked | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点选中事件回调,返回所有选中的节点数据 | [可勾选树](demo#checkable-tree) | -| currentNodeChecked | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点选中事件回调,返回当前选中的节点数据 | [可勾选树](demo#checkable-tree) | -| nodeEdited | `EventEmitter<`[`TreeNode`](#treenode)`>` | 可选,节点 title 编辑事件回调,返回当前编辑的节点数据 | [操作按钮](demo#operation-button) | -| editValueChange | `EventEmitter<{ value: string, callback: Function }>` | 可选,节点编辑中数据变化的回调函数,返回校验后的值;可通过对返回值中的 callback 函数的调用实现校验错误提示(callback 接收两个参数,`errTips`为错误信息,`errTipsPosition`为信息弹出位置) | [操作按钮](demo#operation-button) | -| nodeOnDrop | `EventEmitter<{ event: DragEvent, treeNode:`[`TreeNode`](#treenode)`, dropType:`[`IDropType`](#idroptype)` }>` | 可选,节点 onDrop 事件回调(任意可拖动元素 drop),返回拖拽事件,释放位置的节点数据,放置类型(`prev`,`inner`,`next`) | [可拖拽树](demo#drag-and-drop-tree) | -| afterTreeInit | `EventEmitter` | 可选,树节点生成完毕后的回调事件,返回当前树的所有节点信息,多用于大数据量情况下需要渲染完成后执行特定操作 | [大数据量可操作树](demo#virtual-scroll) | - -**注意** - -- `treeNodeIdKey`: 用来作为节点的唯一表示,默认情况下取 `id`,如果不需要异步加载节点,可以不用传入,组件会自动分配一个唯一标识 -- `treeNodeChildrenKey`: 用来表示传入数据子节点的 children 名称,默认取 `items` -- `checkboxDisabledKey`: 用来标识子节点是否可选,默认取 `disabled`作为标识 -- `treeNodeTitleKey`: 用来标识节点显示字段的键值,默认为 `title` -- `checkboxInput`: 用来给 checkbox 设置相关属性,其默认值为 `{ color: 'F38826' }`, ~~disableType 属性用来统一所有子节点的 disableType~~。 - -# 接口 & 类型定义 - -## TreeFactoryAPI - -组件提供一个 TreeFactory,你可以从 TreeFactory 的实例上拿到下列方法来进行操作: -参考:[常用TreeFactory函数](demo#tree-factory) - -```ts - -`treeRoot`: 获取整颗树 - -`mapTreeItems({treeItems,parentId, treeNodeChildrenKey = 'items',treeNodeIdKey = 'id',checkboxDisabledKey = 'disabled', - selectDisabledKey = 'disableSelect',toggleDisabledKey = 'disableToggle',treeNodeTitleKey = 'title'})`: 将原始的treeItems数据转为组件所需TreeNode后添加到指定的父节点上,常用于懒加载等功能 - -`getNodeById(id: number | string): TreeNode`: 根据 id 获取节点信息并返回 - -`getCompleteNodeById(id: number | string): TreeNode`: 根据 id 获取节点信息,包含节点的 id,parentId - -`addChildNode(parentNode:TreeNode,childNode:TreeNode,index?)`: 添加指定子节点到指定父节点上,可通过index控制子节点所处位置 - -`deleteNodeById(id: number | string)`: 根据id删除指定节点 - -`toggleNodeById(id: number | string)`: 根据id展开收起指定节点 - -`openNodesById(id: number | string) `: 根据id展开指定节点 - -`closeNodesById(id: number | string, closeChildren = false)`: 根据id收起指定节点,可根据closeChildren的值决定子节点是否需要收起 - -`disabledNodesById(id: number | string)`: 根据 id 使某个节点的 checkbox 变为不可选 - -`checkNodesById(id: number | string, checked: boolean, checkableRelation: 'upward' | 'downward' | 'both' | 'none' = 'both'): Array `: - 根据 id 决定指定节点的check状态,可传入checkableRelation控制父子节点选中关系,返回所有选中节点 - -`getCheckedNodes()`: 返回所有check状态为true的节点 - -`getDisabledNodes()`: 返回所有禁止check的节点 - -`activeNodeById(id: number | string)`: 根据 id 使指定节点的状态变为active - -`getChildrenById(id: number | string): Array `: 根据 id 获得指定节点的子节点,返回子节点的数组 - -`startLoading(id: number | string)`: 根据id使指定节点显示加载状态 - -`endLoading(id: number | string)`: 根据id关闭指定节点加载状态 - -`searchTree(target: string, hideUnmatched = false, keyword='title', pattern?:RegExp)`: - 在树中搜索是否存在匹配target字段的节点. hideUnmatched控制是否隐藏不匹配的节点;keyword控制在指定关键字中搜索;pattern控制与target匹配的方式 - -`hideNodeById(id: number | string, hide: boolean)`: 根据 id 选择隐藏或显示节点 - -`deactivateAllNodes()`: 取消所有节点的active状态 - -`checkAllNodes(checked:boolean)`: 根据checked决定所有节点的check状态 - -`mergeTreeNodes(targetNode:TreeNode)`: 传入需要合并显示的节点,默认为整个树,此操作将合并只有一个子节点的父节点,用于优化树形显示 - -`getNodeIndex(node: TreeNode)`: 获取指定节点处于父节点中位置 - -`editNodeTitle(id: number | string)`: 根据id编辑指定节点 - -`disableAllNodesChecked(disable:boolean = true)`: 禁止所有节点的check状态修改 - -`disableAllNodesSelected(disable:boolean = true)`: 禁止所有节点的select状态修改 - -`disableAllNodesToggled(disable:boolean = true)`: 禁止所有节点的展开收起状态修改 - -``` - -## 自定义模板 - -自定义额外图标相关参数如下 - -| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | -| :------------------: | :----------------: | :---------------: | :----------------------: | :-----------------------------------------------------------------------------------------------------: | -| iconTemplatePosition | `'before-checkbox' \| 'after-checkbox'` | 'after-checkbox' | 可选,设置 icon 放置的位置,`before-checkbox`为放置在 checkbox 前,`after-checkbox`为放置在 checkbox 后 | [自定义图标](demo#custom-icon) | -| iconTemplate | `TemplateRef` | -- | 可选,自定义图标的展示 | [自定义图标](demo#custom-icon) | -| nodeTemplate | `TemplateRef` | -- | 可选,自定义树节点的显示 | [自定义图标](demo#custom-icon) | -| operatorTemplate | `TemplateRef` | -- | 可选,自定义操作图标区域 | [自定义图标](demo#custom-icon) | -| statusTemplate | `TemplateRef` | -- | 可选,自定义状态等信息 | [自定义图标](demo#custom-icon) | - -```xml - - - - - - - - -``` -**Note** -The `node` parameter in `let-node="node"` in iconTemplate and nodeTemplate does not include id and parentId. Use `completeNode` in `let-completeNode="completeNode"` - -### ITreeItem - -```ts -export interface ITreeItem { - title: string; // 节点显示名称 - open?: boolean; // 节点是否展开 - loading?: boolean; // 节点是否显示加载中 - isMatch?: boolean; // 搜索场景下,节点是否匹配 - items?: ITreeItem[]; // 节点的子节点 - isParent?: boolean; // 节点是否为父节点,控制是否出现展开收起按钮 - data?: any; // 额外的节点数据存放处 - id?: any; // 节点id - isHide?: boolean; // 节点是否隐藏 - isActive?: boolean; // 节点是否为selected状态 - isChecked?: boolean; // 节点是否为checked状态 - halfChecked?: boolean; // 节点是否为半选状态 - disabled?: boolean; // 节点是否为半选状态 - disableAdd?: boolean; // 节点是否禁止check - disableEdit?: boolean; // 节点是否禁止编辑 - disableDelete?: boolean; // 节点是否禁止删除 - disableSelect?: boolean; // 节点是否禁止select - disableToggle?: boolean; // 节点是否禁止展开收起 - [prop: string]: any; -} -``` - -### ICheckboxInput - -```ts -export interface ICheckboxInput { - color?: string; -} -``` - -### IDropType - -```ts -export interface IDropType { - dropPrev?: boolean; // 是否允许放置在节点前 - dropNext?: boolean; // 是否允许放置在节点后 - dropInner?: boolean; // 是否允许放置在节点中,成为该节点的子节点 -} -``` - -### TreeNode - -```ts -export class TreeNode implements ITreeNodeData { - constructor(public id, public parentId, public data) {} -} - -export interface ITreeNodeData { - id?: number | string; - parentId?: number | string; - title?: string; - isOpen?: boolean; - data?: any; - isParent?: boolean; - loading?: boolean; - isMatch?: boolean; - isHide?: boolean; - isActive?: boolean; - isChecked?: boolean; - disabled?: boolean; - - [prop: string]: any; - - children?: []; -} -``` diff --git a/devui/tree/doc/api-en.md b/devui/tree/doc/api-en.md deleted file mode 100644 index 19b486a695f39942c860643110cea8e42fdbbcd0..0000000000000000000000000000000000000000 --- a/devui/tree/doc/api-en.md +++ /dev/null @@ -1,276 +0,0 @@ -# How to use - -Import into module: - -```ts -import { TreeModule } from 'ng-devui/tree'; -``` - -In the page: - -```html - -``` - -# d-tree - -## d-tree parameters - -##### Basic tree, without adding, deleting, modifying, and querying - -| Parameter | Type | Default | Description | Jump to Demo | -| :-----------------: | :----------------------------------: | :-------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------------- | -| tree | `Array<`[`ITreeItem`](#itreeitem)`>` | -- | Required. It is used to render the tree based on the input data. | [Basic Usage](demo#basic-usage) | -| treeNodeIdKey | `string` | 'id' | Optional. ID key value name, which uniquely identifies a node. | [Custom Display Fields](demo#custom-display-field) | -| treeNodeChildrenKey | `string` | 'items' | Optional. key value name of the subnode array | [Custom Display Fields](demo#custom-display-field) | -| treeNodeTitleKey | `string` | 'title' | Optional. This parameter indicates the key value of the data displayed on the node. | [Custom Display Fields](demo#custom-display-field) | -| checkboxDisabledKey | `string` | 'disabled' | Optional. Do not select the key value of the check box on the node. | [Customized field](demo#custom-display-field) | -| selectDisabledKey | `string` | 'disabled' | Optional. It indicates the name of a key value that cannot be selected on the node. | [Checkable Tree](demo#checkable-tree) | -| toggleDisabledKey | `string` | 'disableToggle' | Optional. Collapsed key names cannot be expanded on the node. | [Checkable Tree](demo#checkable-tree) | -| iconParentOpen | `string` | -- | Optional. Customize the icon when the parent node is expanded. | [Custom Icon](demo#custom-icon) | -| iconParentClose | `string` | -- | Optional. Customize the icon when the parent node is folded. | [Custom Icon](demo#custom-icon) | -| iconLeaf | `string` | -- | Optional. Custom leaf node icon | [Custom Icon](demo#custom-icon) | -| treeNodesRef | `TemplateRef` | -- | Optional. It specifies the display template of a customized node. | -| loadingTemplateRef | `TemplateRef` | -- | Optional. Customizing the template being loaded | [Customizing a Loading Template](demo#custom-loading) | -| virtualScroll | `boolean` | false | Optional. Whether to enable virtual scrolling. This parameter is used to process a large amount of data. | [Operation tree of large data volume](demo#virtual-scroll) | -| virtualScrollHeight | `string` | '800px' | Optional. Sets the tree height during virtual scrolling. | [Operation tree of large data volume](demo#virtual-scroll) | -| minBufferPx | `number` | 600 | Optional. Sets the minimum buffer size during virtual scrolling. For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Operation tree of large data volume](demo#virtual-scroll) | . | -| maxBufferPx | `number` | 900 | Optional. Sets the maximum buffer size during virtual scrolling. For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Operation tree of large data volume](demo#virtual-scroll) | . | -| showAnimation | `boolean` | true | Optional. Indicating whether to display animations. | [Without Animation](demo#without-animation) | - -## d-tree Event - -| Parameter | Type | Description | Jump to Demo | -| :--------------: | :---------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| nodeSelected | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback function for node selection. It returns the data of the selected node. | [Basic Usage](demo#basic-usage) | -| nodeDblClicked | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback function used when a node is double-clicked. It returns the data of the current node. | [Custom Display Fields](demo#custom-display-field) | -| nodeRightClicked | `EventEmitter<{event:MouseEvent,node:`[`TreeNode`](#treenode)`}>` | Optional. Callback function used when a node is right-clicked. It returns the data and mouse event of the current node. | [Custom Display Fields](demo#custom-display-field) | -| nodeToggled | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback function for expanding and folding a node. It returns the data of the current node. | | [Basic Usage](demo#basic-usage) | -| afterTreeInit | `EventEmitter>` | Optional. It is a callback event after tree nodes are generated. It returns information about all nodes in the current tree. This event is mainly used to perform specific operations after rendering is completed in the case of a large amount of data. | The function is the same as that of [Operation tree of large data volume](demo#virtual-scroll) in the d-operable-tree. | - -# d-operable-tree - -## d-operable-tree parameter - -##### Add, delete, and modify buttons when you move the mouse over or select them. - -| Parameter | Type | Default | Description | Jump to Demo | -| :-------------------: | :---------------------------------------: | :-------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------- | -| tree | `Array<`[`ITreeItem`](#itreeitem)`>` | -- | Required. Renders the tree based on the input data. | [Checkable Tree](demo#checkable-tree) | -| treeNodeIdKey | `string` | 'id' | Optional. ID key value name, which is used to identify the uniqueness of a node. | [Checkable Tree](demo#checkable-tree) | -| treeNodeChildrenKey | `string` | 'items' | Optional. key value name of the subnode array | [Checkable Tree](demo#checkable-tree) | -| treeNodeTitleKey | `string` | 'title' | Optional. It indicates the key value of the data displayed on the node. | [Checkable Tree](demo#checkable-tree) | -| checkboxDisabledKey | `string` | 'disabled' | Optional. Key value names that cannot be selected on a node. | [Checkable Tree](demo#checkable-tree) | -| selectDisabledKey | `string` | 'disabled' | Optional. It indicates the name of a key value that cannot be selected on the node. | [Checkable Tree](demo#checkable-tree) | -| toggleDisabledKey | `string` | 'disableToggle' | Optional. Collapsed key names cannot be expanded on the node. | [Checkable Tree](demo#checkable-tree) | -| iconParentOpen | `string` | -- | Optional. Customize the icon when the parent node is expanded. | [Custom Icon](demo#custom-icon) | -| iconParentClose | `string` | -- | Optional. Customize the icon when the parent node is folded. | [Custom Icon](demo#custom-icon) | -| iconLeaf | `string` | -- | Optional. Custom leaf node icon | [Custom Icon](demo#custom-icon) | -| checkable | `boolean` | true | Optional. Whether to display the checkbox, that is, whether the checkbox is in multi-selection mode. | [Operation button](demo#operation-button) | -| addable | `boolean` | false | Optional. indicating whether to display the button for adding a child node. | [Operation button](demo#operation-button) | -| editable | `boolean` | false | Optional. indicating whether to display the edit subnode button | [Operation button](demo#operation-button) | -| deleteable | `boolean` | false | Optional. Whether to display the button for deleting subnodes. | [Operation button](demo#operation-button) | -| draggable | `boolean` | false | Optional. indicating whether a tree node supports drag and drop operations. | [Draggable tree](demo#drag-and-drop-tree) | -| checkboxInput | `ICheckboxInput` | {} | Optional. Sets the attributes of the checkbox. | [Checkable Tree](demo#checkable-tree) | -| canActivateNode | `boolean` | true | : indicates whether a node can be selected. If the value is false, the nodeChecked event is triggered when a node is clicked. | [Operation button](demo#operation-button) | -| canActivateParentNode | `boolean` | true | Optional. indicates whether a parent node is optional. If the value is false, the nodeChecked event is triggered when a node is clicked. | [Operation button](demo#operation-button) | -| iconTemplatePosition | `string` | -- | Optional. Sets the position of the icon, which can be `before-checkbox'` or `after-checkbox'` | [Custom Icon](demo#custom-icon) | -| checkableRelation | `'upward' \|'downward' \|'both' \|'none'` | 'both' | Optional. Sets the check rule of the parent-child node | [Control the parent-child check relationship](demo#check-control-tree) | -| beforeAddNode | `Promise` | -- | Optional. Call back before adding a subnode (the parameter is the current node). The return value can specify the index of the added node. | [Operation button](demo#operation-button) | -| beforeDeleteNode | `Promise` | -- | Optional. Callback before deleting a node (parameter: current node) | [Operation button](demo#operation-button) | -| beforeNodeDrop | `Promise` | -- | Optional. Callback before dragging a subnode (parameters are the currently dragged node, release node, and placement type (`prev`, `inner`, and `next`)) | [drragable tree](demo#drag-and-drop-tree) | -| beforeEditNode | `Promise` | -- | Optional. callback before editing a subnode (parameters are the currently edited node) | [Operation button](demo#operation-button) | -| postAddNode | `Promise` | -- | Optional. Callback after a node is added (parameters are added) | [Operation button](demo#operation-button) | -| dropType | `IDropType` | -- | Optional. Sets the position where a node is to be dragged. `dropPrev` indicates to be placed before a node, `dropNext` indicates to be placed after a node, and `dropInner` indicates to be placed in a node. | [Draggable tree](demo#drag-and-drop-tree) | -| virtualScroll | `boolean` | false | Optional. Whether to enable virtual scrolling. This parameter is used to process a large amount of data. | [Operation tree of large data volume](demo#virtual-scroll) | -| virtualScrollHeight | `string` | '800px' | Optional. Sets the tree height during virtual scrolling. | [Operation tree of large data volume](demo#virtual-scroll) | -| minBufferPx | `number` | 600 | Optional. Sets the minimum buffer size during virtual scrolling. For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Operation tree of large data volume](demo#virtual-scroll) | . | -| maxBufferPx | `number` | 900 | Optional. Sets the maximum buffer size during virtual scrolling. For details, see https://material.angular.io/cdk/scrolling/overview#scrolling-over-fixed-size-items | [Operation tree of large data volume](demo#virtual-scroll) | . | -| disableMouseEvent | `boolean` | false | Optional. Sets whether to disable the mouse move-in event. This parameter is used when the appendTobody function is used and the content in the drop-down list box cannot be hovered. | [Custom Icon](demo#custom-icon) | -| showAnimation | `boolean` | true | Optional. Indicating whether to display animations. | [Without Animation](demo#without-animation) | - -## d-operable-tree event - -| Parameter | Type | Description | Jump to Demo | -| :----------------: | :------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----| -| nodeSelected | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. The node click event is called back to return the data of the currently selected node. | [Checkable Tree](demo#checkable-tree) | -| nodeDblClicked | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback function used when a node is double-clicked. It returns the data of the current node. | [Checkable Tree](demo#checkable-tree) | -| nodeRightClicked | `EventEmitter<{event:MouseEvent,node:`[`TreeNode`](#treenode)`}>` | Optional. Callback function used when a node is right-clicked. It returns the data and mouse event of the current node. | [Checkable Tree](demo#checkable-tree) | -| nodeDeleted | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback of the node deletion event to return the data of the deleted node. | [Operation button](demo#operation-button) | -| nodeToggled | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. It is the callback function of the node expansion and collapse event. The data of the current node is returned. | [Checkable Tree](demo#checkable-tree) | -| nodeChecked | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback of the node selection event to return data of all selected nodes. | [Checkable Tree](demo#checkable-tree) | -| currentNodeChecked | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. Callback of the node selection event to return the data of the currently selected node. | [Checkable Tree](demo#checkable-tree) | -| nodeEdited | `EventEmitter<`[`TreeNode`](#treenode)`>` | Optional. This parameter is used to call back the node title editing event to return the currently edited node data. | [Operation button](demo#operation-button) | -| editValueChange | `EventEmitter<{ value: string, callback: Function }>` | Optional. Callback function for data changes during node editing. It returns the verified value. The callback function in the return value can be invoked to verify the error message. (The callback function receives two parameters, where `errTips` indicates the error information and `errTipsPosition` indicates the information pop-up position.) | [Operation button](demo#operation-button) | -| nodeOnDrop | `EventEmitter<{ event: DragEvent, treeNode:`[`TreeNode`](#treenode)`, dropType:`[`IDropType`](#idroptype)` }>` | Optional. It is the node onDrop event callback function (drop any dragable element). It returns the drag event and releases the node data in the position. The placement type is (`prev`, `inner`, `next`) | [Draggable tree](demo#drag-and-drop-tree) | -| afterTreeInit | `EventEmitter` | Optional. This is a callback event after tree nodes are generated. It returns information about all nodes in the current tree. This event is mainly used when a large amount of data needs to be rendered and specific operations need to be performed after the rendering is complete. | [Large-volume-data-operable tree](demo#virtual-scroll) | - -**Note** - -- `treeNodeIdKey`: Unique ID of a node. The default value is `id`. If the node does not need to be loaded asynchronously, you do not need to transfer this parameter. The component automatically allocates a unique ID. -- `treeNodeChildrenKey`: indicates the child name of the transferred data child node. The default value is `items`. -- `checkboxDisabledKey`: indicates whether a subnode is optional. The default value is Disabled. -- `treeNodeTitleKey`: key value of the node display field. The default value is `title`. -- `checkboxInput`: Sets related attributes for the checkbox. The default value is `{color: 'F38826'}`. ~~disableType is used to unify disableType of all subnodes. - -# Interface & Type Definition - -## **TreeFactoryAPI** - -The component provides a TreeFactory. You can perform the following operations on the TreeFactory instance: -see: [Common treeFactory functions](demo#tree-factory) - -```ts - -`treeRoot`: Obtains the entire tree data. - -`mapTreeItems({treeItems,parentId, treeNodeChildrenKey = 'items',treeNodeIdKey ='id',checkboxDisabledKey ='disabled', -selectDisabledKey = 'disableSelect', toggleDisabledKey = 'disableToggle', treeNodeTitleKey = 'title'})`: Converts the original treeItems data to the tree node required by the component and adds the tree node to the specified parent node. This method is used for lazy loading and other functions. - -The `getNodeById(id: number | string): TreeNode`: obtains the node information based on the node ID and returns the information. - -`getCompleteNodeById(id: number | string): TreeNode`: Obtains node information based on the node ID, including the node ID and parent ID. - -`addChildNode(parentNode:TreeNode, childNode:TreeNode, index?)`: Adds a specified child node to a specified parent node. The location of the child node can be controlled by index. - -`deleteNodeById(id: number | string)`: Deleting a Specified Node by ID - -`toggleNodeById(id: number | string)`: Expands and collapses specified nodes based on IDs. - -`openNodesById(id: number | string) `: Expanding a Specified Node by ID - -`closeNodesById(id: number | string, closeChildren = false)`: Collapses specified nodes based on IDs and determines whether to collapse subnodes based on the value of closeChildren. - -The `disabledNodesById(id: number | string)`: disables the checkbox of a node based on the node ID. - -`checkNodesById(id: number | string, checked: boolean, checkableRelation:'upward '|'downward '| 'both' | 'none' = 'both'): Array `: -Determines the check status of a specified node based on the id. CheckableRelation can be transferred to control the parent-child node selection relationship and return all selected nodes. - -`getCheckedNodes()`: Returns all nodes whose check status is true. - -`getDisabledNodes()`: Returns all nodes whose check is forbidden. - -The `activeNodeById(id: number | string)`: changes the status of a specified node to active based on the node ID. - -`getChildrenById(id: number | string): Array `: Obtains the subnodes of a specified node based on the ID and returns the array of the subnodes. - -`startLoading(id: number | string)`: Displays the loading status of a specified node based on the node ID. - -`endLoading(id: number | string)`: Disables the loading status of a specified node based on the ID. - -`searchTree(target: string, hideUnmatched = false, keyword='title', pattern?:RegExp)`: -Searches for nodes that match the target field in the tree. hideUnmatched controls whether to hide unmatched nodes. The keyword parameter specifies the keyword to be searched. Pattern Controls the Mode of Matching Targets - -`hideNodeById(id: number | string, hide: boolean)`: Hide or Display Nodes by ID - -`deactivateAllNodes()`: cancels the active state of all nodes. - -The `checkAllNodes(checked:boolean)`: determines the check status of all nodes based on the checked value. - -`mergeTreeNodes(targetNode:TreeNode)`: indicates the node to be combined. The default value is the entire tree. This operation combines the parent node with only one child node to optimize the tree display. - -`getNodeIndex(node: TreeNode)`: Obtains the position of a specified node in the parent node. - -`editNodeTitle(id: number | string)`: Editing a Specified Node by ID - -`disableAllNodesChecked(disable:boolean = true)`: Do not change the check status of all nodes. - -`disableAllNodesSelected(disable:boolean = true)`: Do not change the select status of all nodes. - -`disableAllNodesToggled(disable:boolean = true)`: Do not change the expand and collapse status of all nodes. - -``` - -## Customizing a Template - -Parameters for customizing extra icons are as follows: - -| Parameter | Type | Default | Description | Jump to Demo | -| :------------------: | :------------------------------------: | :--------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------: | -| iconTemplatePosition | `'before-checkbox' \|'after-checkbox'` | 'after-checkbox' | Optional. Sets the position where the icon is placed. `before-checkbox` indicates that the icon is placed before the checkbox, `after-checkbox` is placed after the checkbox | [Custom Icon](demo#custom-icon) | -| iconTemplate | `TemplateRef` | -- | Optional. Custom icon display | [Custom Icon](demo#custom-icon) | -| nodeTemplate | `TemplateRef` | -- | Optional. Custom tree node display | [Custom Icon](demo#custom-icon) | -| operatorTemplate | `TemplateRef` | -- | : Optional. customized operation icon area | [Custom Icon](demo#custom-icon) | -| statusTemplate | `TemplateRef` | -- | : Optional. customized status information | [Custom Icon](demo#custom-icon) | - -```xml - - - - - - - - -``` - -### ITreeItem - -```ts -export interface ITreeItem { - title: string; // Display name of the node. - open?: boolean; // Indicates whether the node is expanded. - loading?: boolean; //Whether the node is being loaded - isMatch?: boolean; // Whether the node is matched in the search scenario. - items?: ITreeItem[]; // Subnode of the node - isParent?: boolean; // Indicates whether a node is a parent node and whether to display the expand and collapse button. - data?: any; // Stores extra node data. - id?: any; // Node ID. - isHide?: boolean; // Indicates whether the node is hidden. - isActive?: boolean; // Check whether the node is in the selected state. - isChecked?: boolean; // Check whether the node is in the checked state. - halfChecked?: boolean; //Whether the node is in the half-selected state - disabled?: boolean; //Whether the node is in the half-selected state - disableAdd?: boolean; // Indicates whether to disable the check function on the node. - disableEdit?: boolean; // Indicates whether the node cannot be edited. - disableDelete?: boolean; // Indicates whether the node cannot be deleted. - disableSelect?: boolean; // Indicates whether to disable the select function on the node. - disableToggle?: boolean; // Indicates whether the node is not expanded or collapsed. - [prop: string]: any; -} -``` - -### ICheckboxInput - -```ts -export interface ICheckboxInput { - color?: string; -} -``` - -### IDropType - -```ts -export interface IDropType { - dropPrev?: boolean; // Indicates whether to allow the node to be placed before the node. - dropNext?: boolean; // Indicates whether to allow placement after a node. - dropInner?: boolean; // Indicates whether to allow the node to be placed in the node and become the child node of the node. -} -``` - -### TreeNode - -```ts -export class TreeNode implements ITreeNodeData { - constructor(public id, public parentId, public data) {} -} - -export interface ITreeNodeData { - id?: number | string; - parentId?: number | string; - title?: string; - isOpen?: boolean; - data?: any; - isParent?: boolean; - loading?: boolean; - isMatch?: boolean; - isHide?: boolean; - isActive?: boolean; - isChecked?: boolean; - disabled?: boolean; - - [prop: string]: any; - - children?: []; -} -``` diff --git a/devui/tree/tree.tsx b/devui/tree/tree.tsx deleted file mode 100644 index 1a2a5bb9a820df63745bf480464b26e2559bb60f..0000000000000000000000000000000000000000 --- a/devui/tree/tree.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-tree', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-tree
    - } - } -}) \ No newline at end of file diff --git a/devui/upload/demo/upload-demo.tsx b/devui/upload/demo/upload-demo.tsx deleted file mode 100644 index 520eecc941f2a0f05f2601c78fb07aadf1443f10..0000000000000000000000000000000000000000 --- a/devui/upload/demo/upload-demo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-upload-demo', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-upload-demo
    - } - } -}) \ No newline at end of file diff --git a/devui/upload/demo/upload.route.ts b/devui/upload/demo/upload.route.ts deleted file mode 100644 index 0c831473394cfa7c67b4312087d56e3e0d93f735..0000000000000000000000000000000000000000 --- a/devui/upload/demo/upload.route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import UploadDemoComponent from './upload-demo' -import DevUIApiComponent from '../../shared/devui-api/devui-api' - -import ApiCn from '../doc/api-cn.md' -import ApiEn from '../doc/api-en.md' -const routes = [ - { path: '', redirectTo: 'demo' }, - { path: 'demo', component: UploadDemoComponent}, - { path: 'api', component: DevUIApiComponent, meta: { - 'zh-cn': ApiCn, - 'en-us': ApiEn - }} -] - -export default routes diff --git a/devui/upload/doc/api-cn.md b/devui/upload/doc/api-cn.md deleted file mode 100644 index 746a37d6274384e536b317067ae22f2536b44c18..0000000000000000000000000000000000000000 --- a/devui/upload/doc/api-cn.md +++ /dev/null @@ -1,181 +0,0 @@ -# 如何使用 - -在module中引入: - -```ts -import { UploadModule } from 'ng-devui/upload'; -``` - -在页面中使用: - -```xml -//单文件上传 - -//多文件上传 - -//使用dUpload指令 -
    -``` -# d-single-upload -## d-single-upload 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------: | :--------------------------------------------------: | :--------: | :--------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions) | -- | 必选,待上传文件配置 | [基本用法](demo#basic-usage) | -| filePath | `string` | -- | 必选,文件路径 | [基本用法](demo#basic-usage) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | 必选,上传配置 | [基本用法](demo#basic-usage) | -| autoUpload | `boolean` | false | 可选,是否自动上传 | [基本用法](demo#basic-usage) | -| placeholderText | `string` | '选择文件' | 可选,上传输入框中的 Placeholder 文字 | [基本用法](demo#basic-usage) | -| preloadFilesRef | `TemplateRef` | -- | 可选,用于创建自定义 已选择文件列表模板 | [自定义](demo#custom) | -| uploadText | `string` | '上传' | 可选,上传按钮文字 | [基本用法](demo#basic-usage) | -| uploadedFiles | `Array` | [] | 可选,获取已上传的文件列表 | [基本用法](demo#basic-usage) | -| uploadedFilesRef | `TemplateRef` | -- | 可选,用于创建自定义 已上传文件列表模板 | [自定义](demo#custom) | -| withoutBtn | `boolean` | false | 可选,是否舍弃按钮 | [基本用法](demo#basic-usage) | -| enableDrop | `boolean` | false | 可选,是否支持拖拽 | [基本用法](demo#basic-usage) | -| beforeUpload | `boolean \| Promise \| Observable` | -- | 可选,上传前的回调,通过返回`true` or `false` ,控制文件是否上传,参数为文件信息及上传配置 | [基本用法](demo#basic-usage) | -| dynamicUploadOptionsFn | [`IUploadOptions`](#iuploadoptions) | -- | 为文件动态设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [基本用法](demo#basic-usage) | -| disabled | `boolean` | false | 可选,是否禁用上传组件 | [基本用法](demo#basic-usage) | -| showTip | `boolean` | false | 可选,是否显示上传提示信息 | [自动上传](demo#auto-upload) | - -## d-single-upload 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOver | `EventEmitter` | 支持拖拽上传时,文件移动到可拖放区域触发事件,可拖动的元素移出放置目标时返回`false`,元素正在拖动到放置目标时返回`true` | [基本用法](demo#basic-usage) | -| fileDrop | `EventEmitter` | 支持拖拽上传时,当前拖拽的文件列表回调,单文件上传默认返回第一个文件 | [基本用法](demo#basic-usage) | -| successEvent | `EventEmitter>` | 上传成功时的回调函数,返回文件及 xhr 的响应信息 | [基本用法](demo#basic-usage) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | 上传错误时的回调函数,返回上传失败的错误信息 | [基本用法](demo#basic-usage) | -| deleteUploadedFileEvent | `EventEmitter` | 删除上传文件的回调函数,返回删除文件的路径信息 | [基本用法](demo#basic-usage) | -| fileSelect | `EventEmitter` | 文件选择后的回调函数,返回已选择文件信息 | [基本用法](demo#basic-usage) | - -# d-multiple-upload -## d-multiple-upload 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------------: | :--------------------------------------------------: | :------------: | :--------------------------------------------------------------------------------- | -------------------------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions) | -- | 必选,待上传文件配置 | [多文件上传](demo#multi-files) | -| filePath | `string` | -- | 必选,文件路径 | [多文件上传](demo#multi-files) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | 必选,上传配置 | [多文件上传](demo#multi-files) | -| autoUpload | `boolean` | false | 可选,是否自动上传 | [自动上传](demo#auto-upload) | -| placeholderText | `string` | '选择多个文件' | 可选,上传输入框中的 Placeholder 文字 | [基本用法](demo#basic-usage) | -| preloadFilesRef | `TemplateRef` | -- | 可选,用于创建自定义 已选择文件列表模板 | [自定义](demo#custom) | -| uploadText | `string` | '上传' | 可选,上传按钮文字 | [基本用法](demo#basic-usage) | -| uploadedFiles | `Array` | [] | 可选,获取已上传的文件列表 | [多文件上传](demo#multi-files) | -| uploadedFilesRef | `TemplateRef` | -- | 可选,用于创建自定义 已上传文件列表模版 | [自定义](demo#custom) | -| withoutBtn | `boolean` | false | 可选,是否舍弃按钮 | [自定义](demo#custom) | -| enableDrop | `boolean` | false | 可选,是否支持拖拽 | [多文件上传](demo#multi-files) | -| beforeUpload | `boolean \| Promise \| Observable` | -- | 上传前的回调,通过返回`true` or `false` ,控制文件是否上传,参数为文件信息及上传配置 | [动态上传参数](demo#dynamic-upload-options) | -| setCustomUploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | 为每个文件设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [自定义](demo#custom) | -| oneTimeUpload | `boolean` | false | 可选,是否只调用一次接口上传所有文件 | [多文件上传](demo#multi-files) | -| disabled | `boolean` | false | 可选,是否禁用上传组件 | [多文件上传](demo#multi-files) | -| showTip | `boolean` | false | 可选,是否显示上传提示信息 | [多文件上传](demo#multi-files) | - -## d-multiple-upload 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -| fileOver | `EventEmitter` | 支持拖拽上传时,文件移动到可拖放区域触发事件,可拖动的元素移出放置目标时返回`false`,元素正在拖动到放置目标时返回`true` | [多文件上传](demo#multi-files) | -| fileDrop | `EventEmitter` | 支持拖拽上传时,当前拖拽的文件列表回调,单文件上传默认返回第一个文件 | [多文件上传](demo#multi-files) | -| successEvent | `EventEmitter>` | 上传成功时的回调函数,返回文件及 xhr 的响应信息 | [多文件上传](demo#multi-files) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | 上传错误时的回调函数,返回上传失败的错误信息 | [多文件上传](demo#multi-files) | -| deleteUploadedFileEvent | `EventEmitter` | 删除上传文件的回调函数,返回删除文件的路径信息 | [多文件上传](demo#multi-files) | -| fileSelect | `EventEmitter` | 文件选择后的回调函数,返回已选择文件信息 | [多文件上传](demo#multi-files) | - -# dUpload -## dUpload 指令 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :--------------: | :--------------------------------------------------: | :--------: | :--------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions) | -- | 必选,待上传文件配置 | [任意区域上传](demo#customize-area-upload) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | 必选,上传配置 | [任意区域上传](demo#customize-area-upload) | -| uploadedFiles | `Array` | [] | 可选,获取已上传的文件列表 | [任意区域上传](demo#customize-area-upload) | -| fileUploaders | `Array` | [] | 可选,获取已选择的文件列表 | [任意区域上传](demo#customize-area-upload) | -| enableDrop | `boolean` | false | 可选,是否支持拖拽 | [任意区域上传](demo#customize-area-upload) | -| dynamicUploadOptionsFn | [`IUploadOptions`](#iuploadoptions) | -- | 为文件动态设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [任意区域上传](demo#customize-area-upload) | - -## dUpload 事件 - -| 参数 | 类型 | 说明 | 跳转 Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -| fileOver | `EventEmitter` | 支持拖拽上传时,文件移动到可拖放区域触发事件,可拖动的元素移出放置目标时返回`false`,元素正在拖动到放置目标时返回`true` | [任意区域上传](demo#customize-area-upload) | -| fileDrop | `EventEmitter` | 支持拖拽上传时,当前拖拽的文件列表回调,单文件上传默认返回第一个文件 | [任意区域上传](demo#customize-area-upload) | -| successEvent | `EventEmitter>` | 上传成功时的回调函数,返回文件及 xhr 的响应信息 | [任意区域上传](demo#customize-area-upload) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | 上传错误时的回调函数,返回上传失败的错误信息 | [任意区域上传](demo#customize-area-upload) | -| alertMsgEvent | `EventEmitter` | 上传文件不符合上传文件配置uploadOptions时的回调函数,返回错误提示信息息 | [任意区域上传](demo#customize-area-upload) | -| fileSelect | `EventEmitter` | 文件选择后的回调函数,返回已选择文件信息 | [任意区域上传](demo#customize-area-upload) | - -### preloadFilesRef 模板参数 - -```xml - - -``` - -其中每项值代表: - -`fileUploaders`:FileUploader 类型的数组,FileUploader中包含 send(), cancel()方法 - -`UploadStatus`:上传状态,存在 preLoad = 0,uploading,uploaded,failed 四种状态 - -`deleteFile`: 传入需要删除的上传文件 - -### uploadedFilesRef 模板参数 - -```xml - - -``` - -其中每项值代表: - -`uploadedFiles`:上传的文件列表 - -`filePath`:文件路径 - -`deleteFile`: 传入需要删除的上传文件 - -# 接口 & 类型定义 -### IUploadOptions - -```ts -export class IUploadOptions { - // 上传接口地址 - uri: string; - // http 请求方法 - method?: string; - // 上传文件大小限制 - maximumSize?: number; - // 自定义请求headers - headers?: {[key: string]: any}; - // 认证token - authToken?: string; - // 认证token header标示 - authTokenHeader?: string; - // 上传额外自定义参数 - additionalParameter?: {[key: string]: any}; - // 上传文件字段名称,默认file - fileFieldName?: string; - // 多文件上传,是否检查文件重名,设置为true,重名文件不会覆盖,否则会覆盖上传 - checkSameName?: boolean; - // 指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求 - withCredentials?: boolean; - // 手动设置返回数据类型 - responseType?: 'arraybuffer' | 'blob' | 'json' | 'text'; -} -``` -### IFileOptions - -```ts -export class IFileOptions { - // 规定能够通过文件上传进行提交的文件类型,例如 accept: '.xls,.xlsx,.pages,.mp3,.png' - accept?: string; - // 输入字段可选择多个值 - multiple?: boolean; -} -``` \ No newline at end of file diff --git a/devui/upload/doc/api-en.md b/devui/upload/doc/api-en.md deleted file mode 100644 index bf9fcc07891375ab7c09cfef0e602102f78e2299..0000000000000000000000000000000000000000 --- a/devui/upload/doc/api-en.md +++ /dev/null @@ -1,179 +0,0 @@ -# How to use - -Import into module: - -```ts -import { UploadModule } from 'ng-devui/upload'; -``` - -In the page: - -```xml -//Single file upload - -//Multiple files upload - -//use dUpload directive -
    -``` -# d-single-upload -## d-single-upload Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------: | :--------------------------------------------------: | :--------: | :--------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions) | -- | Required. Configuration of the file to be uploaded | [Basic Usage](demo#basic-usage) | -| filePath | `string` | -- | Required. File path | [Basic Usage](demo#basic-usage) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | Required. Upload configuration | [Basic Usage](demo#basic-usage) | -| autoUpload | `boolean` | false | Optional. Indicating whether to automatically upload files | [Basic Usage](demo#basic-usage) | -| placeholderText | `string` |'Select file' | Optional. This parameter is used to upload the Placeholder text in the text box | [Basic Usage](demo#basic-usage) | -| preloadFilesRef | `TemplateRef` | -- | Optional. Used to create a customized template of the selected file list | [Customize](demo#custom) | -| uploadText | `string` | 'Upload' | Optional. This parameter specifies the text of the upload button | [Basic Usage](demo#basic-usage) | -| uploadedFiles | `Array` | [] | Optional. Obtains the list of uploaded files | [Basic Usage](demo#basic-usage) | -| uploadedFilesRef | `TemplateRef` | -- | Optional. Used to create a customized template for the list of uploaded files | [Customize](demo#custom) | -| withoutBtn | `boolean` | false | Optional. Whether to discard the button | [Basic Usage](demo#basic-usage) | -| enableDrop | `boolean` | false | Optional. Indicating whether drag is supported | [Basic Usage](demo#basic-usage) | -| beforeUpload | `boolean \| Promise \| Observable` | -- | Optional. It is a callback before upload. The return value is true or false to control whether to upload a file, file information and upload configuration | [Basic Usage](demo#basic-usage) | -| dynamicUploadOptionsFn | [`IUploadOptions`](#iuploadoptions) | -- | Set upload parameters dynamically for file. The parameters are the currently selected file and the value of `uploadOptions` | [Basic Usage](demo#basic-usage) | -| disabled | `boolean` | false | Optional. Specifies whether to disable the upload component. | [Basic Usage](demo#basic-usage) | -| showTip | `boolean` | false | Optional. Indicating whether to display the upload message. | [Automatic Upload](demo#auto-upload) | - -## d-single-upload event - -| Parameter | Type | Description | Jump to Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOver | `EventEmitter` | Supports drag-and-drop upload. When a file is moved to a drag-and-drop area, an event is triggered. If a drag-and-drop element is moved out of the target, `false` is returned. If an element is being dragged to the target, `true` is returned | [Basic Usage](demo#basic-usage) | -| fileDrop | `EventEmitter` | Supports the callback of the list of dragged files during upload. The first file is returned by default when a single file is uploaded | [Basic Usage](demo#basic-usage) | -| successEvent | `EventEmitter>` | Callback function when the upload is successful. It returns the file and Xhr response information | [Basic Usage](demo#basic-usage) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | Callback function when an upload error occurs. The error information about the upload failure is returned | [Basic Usage](demo#basic-usage) | -| deleteUploadedFileEvent | `EventEmitter` | Callback function for deleting uploaded files. The callback function returns the path information of the deleted files | [Basic Usage](demo#basic-usage) | -| fileSelect | `EventEmitter` | Callback function for selecting files. The callback function returns the path information of the selected files | [Basic Usage](demo#basic-usage) | - -# d-multiple-upload -## d-multiple-upload Parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------------: | :--------------------------------------------------: | :------------: | :--------------------------------------------------------------------------------- | -------------------------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions) | -- | Required. Configuration of the file to be uploaded | [Upload Multiple Files](demo#multi-files) | -| filePath | `string` | -- | Required. File path | [Multiple file upload](demo#multi-files) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions)| -- | Required. Upload configuration | [Upload Multiple Files](demo#multi-files) | -| autoUpload | `boolean` | false | Optional. Indicating whether to automatically upload the file | [Automatic Upload](demo#auto-upload) | -| placeholderText | `string` |'Select multiple files' | Optional. Upload the Placeholder text in the text box | [Basic Usage](demo#basic-usage) | -| preloadFilesRef | `TemplateRef` | -- | Optional. Used to create a customized template of the selected file list | [Customize](demo#custom) | -| uploadText | `string` | 'Upload' | Optional. This parameter specifies the text of the upload button | [Basic Usage](demo#basic-usage) | -| uploadedFiles | `Array` | [] | Optional. Obtains the list of uploaded files | [Upload Multiple Files](demo#multi-files) | -| uploadedFilesRef | `TemplateRef` | -- | Optional. Used to create a customized template for the list of uploaded files | [Customize](demo#custom) | -| withoutBtn | `boolean` | false | Optional. Whether to discard the button | [Customize](demo#custom) | -| enableDrop | `boolean` | false | Optional. Indicating whether dragging is supported | [Upload Multiple Files](demo#multi-files) | -| beforeUpload |`boolean \| Promise \| Observable` | -- | Callback before upload. The return value `true` or `false` determines whether to upload a file, the parameters are file information and upload configuration | [Dynamic Upload Parameters](demo#dynamic-upload-options) | -| setCustomUploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | Set customized upload parameters for each file. The parameters are the currently selected file and the value of `uploadOptions` | [Customize](demo#custom) | -| oneTimeUpload | `boolean` | false | Optional. Indicates whether to invoke the interface only once to upload all files| [Upload Multiple Files](demo#multi-files) | -| disabled | `boolean` | false | Optional. Specifies whether to disable the upload component | [Upload Multiple Files](demo#multi-files) | -| showTip | `boolean` | false | Optional. indicating whether to display the upload message | [Upload Multiple Files](demo#multi-files) | - -## d-multiple-upload event - -| Parameter | Type | Description | Jump to Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -| fileOver | `EventEmitter` | Supports dragging and uploading. When a file is moved to a dragable area, an event is triggered. If a dragable element is moved out of the target, the value `false` is returned. If an element is being dragged to the target, the value `true` is returned | [Upload Multiple Files](demo#multi-files) | -| fileDrop | `EventEmitter` | Supports the callback of the list of dragged files during upload. The first file is returned by default when a single file is uploaded | [Upload Multiple Files](demo#multi-files) | -| successEvent | `EventEmitter>` | Callback function when the upload is successful, which returns the file and Xhr response information | [Upload Multiple Files](demo#multi-files) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | Callback function when an upload error occurs. The error information about the upload failure is returned | [Upload Multiple Files](demo#multi-files) | -| deleteUploadedFileEvent | `EventEmitter` | Callback function for deleting uploaded files. The file path information is returned | [Upload Multiple Files](demo#multi-files) | -| fileSelect | `EventEmitter` | Callback function for selecting files. The callback function returns the path information of the selected files | [Upload Multiple Files](demo#multi-files) | - -# dUpload -## dUpload Directive - -| Parameter | Type | Default | Description | Jump to Demo | -| :--------------: | :--------------------------------------------------: | :--------: | :--------------------------------------------------------------------------------------- | ----------------------------------------------- | -| fileOptions | [`IFileOptions`](#ifileoptions)| -- | Required. Configuration of the file to be uploaded | [Customize Area to Upload](demo#customize-area-upload) | -| uploadOptions | [`IUploadOptions`](#iuploadoptions) | -- | Required. Upload configuration | [Customize Area to Upload](demo#customize-area-upload) | -| uploadedFiles | `Array` | [] | Optional. Obtain the list of uploaded files | [Customize Area to Upload](demo#customize-area-upload) | -| fileUploaders | `Array` | [] | Optional. Obtain the list of selected files | [Customize Area to Upload](demo#customize-area-upload) | -| enableDrop | `boolean` | false | Optional. Indicating whether drag is supported | [Customize Area to Upload](demo#customize-area-upload) | -| dynamicUploadOptionsFn | [`IUploadOptions`](#iuploadoptions) | -- | Set upload parameters dynamically for each file. The parameters are the currently selected file and the value of `uploadOptions` | [Customize Area to Upload](demo#customize-area-upload) | - -## dUpload Event - -| Parameter | Type | Description | Jump to Demo | -| :---------------------: | :-----------------: | :--------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -| fileOver | `EventEmitter` | Supports dragging and uploading. When a file is moved to a dragable area, an event is triggered. If a dragable element is moved out of the target area, the value `false` is returned. If an element is being dragged to the target area, the value `true` is returned | [Customize Area to Upload](demo#customize-area-upload) | -| fileDrop | `EventEmitter` | Supports the callback of the list of dragged files during upload. The first file is returned by default when a single file is uploaded | [Customize Area to Upload](demo#customize-area-upload) | -| successEvent | `EventEmitter>` | Callback function when the upload is successful, which returns the file and Xhr response information | [Customize Area to Upload](demo#customize-area-upload) | -| errorEvent | `EventEmitter<{file: File; response: any}>` | Callback function when an upload error occurs. An upload failure error message is returned | [Customize Area to Upload](demo#customize-area-upload) | -| alertMsgEvent | `EventEmitter` | The file to be uploaded does not comply with the callback function used when uploadOptions is configured for the file to be uploaded. An error message is returned | [Customize Area to Upload](demo#customize-area-upload) | -| fileSelect | `EventEmitter` | Callback function for selecting files. The callback function returns the path information of the selected files | [Customize Area to Upload](demo#customize-area-upload) | - -### preloadFilesRef Template parameters - -```xml - - -``` - -Each value represents: - -`fileUploaders`: array of the FileUploader type. FileUploader contains the send() and cancel() methods. - -`UploadStatus`: upload status, which can be preLoad = 0,uploading,uploaded,failed'. - -`deleteFile`: transfer the file to be deleted. - -### uploadedFilesRef Template parameters - -```xml - - -``` - -Each value represents: - -`uploadedFiles`: list of uploaded files - -`filePath`: file path - -`deleteFile`: transfer the file to be deleted. - -# Interface & Type Definition -### IUploadOptions - -```ts -export class IUploadOptions { - // Upload interface address. - uri: string; - // HTTP request method - method? : string; - // Maximum size of the file to be uploaded. - maximumSize? : number; - // Customize request headers. - headers? : {[key: string]: any}; - // Authenticate the token. - authToken? : string; - // Authentication token header ID. - authTokenHeader? : string; - // Upload additional customized parameters. - additionalParameter? : {[key: string]: any}; - // Field name of the file to be uploaded. The default value is file. - fileFieldName? : string; - // Indicates whether to check whether duplicate files are uploaded. If this parameter is set to true, duplicate files are not overwritten. Otherwise, duplicate files are overwritten. - checkSameName? : boolean; - // Indicates whether to use a certificate such as cookies, authorization headers (header authorization), or TLS client certificate to create a cross-site access-control request. - withCredentials? : boolean; -} -``` -### IFileOptions - -```ts -export class IFileOptions { - // Specify the type of files that can be submitted through file upload, for example, accept:' .xls, .xlsx, .pages, .mp3, .png'. - accept?: string; - // Multiple values can be selected for the input field. - multiple?: boolean; -} -``` diff --git a/devui/upload/upload.tsx b/devui/upload/upload.tsx deleted file mode 100644 index 4fc9f7e349a9e0766862f47b2fd05a17b826158d..0000000000000000000000000000000000000000 --- a/devui/upload/upload.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'd-upload', - props: { - }, - setup(props, ctx) { - return () => { - return
    devui-upload
    - } - } -}) \ No newline at end of file diff --git a/docs/component.route.ts b/docs/component.route.ts deleted file mode 100755 index b91ce5401c5cdbe75a1785bc22846e4806c89b43..0000000000000000000000000000000000000000 --- a/docs/component.route.ts +++ /dev/null @@ -1,668 +0,0 @@ -import { ExamplePanelComponent } from './example-panel.component'; -import { GetStartedComponent } from './get-started.component'; -import { ColorComponent } from './color/color.component'; -import { ThemeGuideComponent } from './theme-guide.component'; - -export const routesConfig = [ - { - path: '', - redirectTo: 'get-start', - pathMatch: 'full', - data: {}, - }, - { - path: 'get-start', - component: GetStartedComponent, - data: { nodisplay: true }, - }, - { - path: 'color', - component: ColorComponent, - data: {nodisplay: true} - }, - { - path: 'theme-guide', - component: ThemeGuideComponent, - data: { nodisplay: true }, - }, - { - path: 'accordion', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/accordion/demo/accordion-demo.moudule').then((m) => m.AccordionDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'Accordion', - cnName: '手风琴', - }, - }, - { - path: 'alert', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/alert/demo/alert-demo.module').then((m) => m.AlertDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Alert', - cnName: '警告', - }, - }, - { - path: 'anchor', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/anchor/demo/anchor-demo.module').then((m) => m.AnchorDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'Anchor', - cnName: '锚点', - }, - }, - { - path: 'auto-complete', - component: ExamplePanelComponent, - loadChildren: () => - import('../../../devui/auto-complete/demo/auto-complete-demo.module').then((m) => m.AutoCompleteDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'AutoComplete', - cnName: '自动补全', - }, - }, - { - path: 'avatar', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/avatar/demo/avatar-demo.module').then((m) => m.AvatarDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Avatar', - cnName: '头像', - }, - }, - { - path: 'ImagePreview', - component: ExamplePanelComponent, - loadChildren: () => - import('../../../devui/image-preview/demo/image-preview-demo.module').then((m) => m.ImagePreviewDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'ImagePreview', - cnName: '图片预览', - }, - }, - { - path: 'breadcrumb', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/breadcrumb/demo/breadcrumb-demo.module').then((m) => m.BreadCrumbDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'Breadcrumb', - cnName: '面包屑', - }, - }, - { - path: 'back-top', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/back-top/demo/back-top-demo.module').then((m) => m.BackTopDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'BackTop', - cnName: '回到顶部', - }, - }, - { - path: 'button', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/button/demo/button-demo.module').then((m) => m.ButtonDemoModule), - data: { - name: 'Button', - cnName: '按钮', - }, - }, - { - path: 'badge', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/badge/demo/badge-demo.module').then((m) => m.BadgeDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Badge', - cnName: '徽标', - }, - }, - { - path: 'card', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/card/demo/card-demo.module').then((m) => m.CardDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Card', - cnName: '卡片', - }, - }, - { - path: 'carousel', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/carousel/demo/carousel-demo.module').then((m) => m.CarouselDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Carousel', - cnName: '走马灯', - }, - }, - { - path: 'checkbox', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/checkbox/demo/checkbox-demo.module').then((m) => m.CheckBoxDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'CheckBox', - cnName: '复选框', - }, - }, - { - path: 'common', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/common/demo/common-demo.module').then((m) => m.CommonDemoModule), - data: { - name: 'Common', - cnName: '公共方法', - }, - }, - { - path: 'datatable', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/data-table/demo/data-table-demo.module').then((m) => m.DataTableDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'DataTable', - cnName: '表格', - }, - }, - { - path: 'datepicker', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/datepicker/demo/datepicker-demo.module').then((m) => m.DatepickerDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'DatePicker', - cnName: '日期选择器', - }, - }, - { - path: 'multi-auto-complete', - component: ExamplePanelComponent, - loadChildren: () => - import('../../../devui/multi-auto-complete/demo/multi-auto-complete-demo.module').then((m) => m.MultiAutoCompleteDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'MultiAutoComplete', - cnName: '多项自动补全', - }, - }, - { - path: 'form', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/form/demo/form-demo.module').then((m) => m.FormDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Form', - cnName: '表单', - }, - }, - { - path: 'fullscreen', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/fullscreen/demo/fullscreen-demo.module').then((m) => m.FullscreenDemoModule), - data: { - name: 'Fullscreen', - cnName: '全屏', - }, - }, - { - path: 'transfer', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/transfer/demo/transfer-demo.module').then((m) => m.TransferDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Transfer', - cnName: '穿梭框', - }, - }, - { - path: 'dragdrop', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/dragdrop/demo/dragdrop-demo.module').then((m) => m.DragDropDemoModule), - data: { - name: 'DragDrop', - cnName: '拖拽', - }, - }, - { - path: 'drawer', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/drawer/demo/drawer-demo.module').then((m) => m.DrawerDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Drawer', - cnName: '抽屉板', - }, - }, - { - path: 'dropdown', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/dropdown/demo/dropdown-demo.module').then((m) => m.DropdownDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'DropDown', - cnName: '下拉菜单', - }, - }, - { - path: 'editable-select', - component: ExamplePanelComponent, - loadChildren: () => - import('../../../devui/editable-select/demo/editable-select-demo.module').then((m) => m.EditableSelectDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'EditableSelect', - cnName: '可输入下拉选择框', - }, - }, - { - path: 'loading', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/loading/demo/loading-demo.module').then((m) => m.LoadingDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Loading', - cnName: '加载提示', - }, - }, - { - path: 'modal', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/modal/demo/modal-demo.module').then((m) => m.ModalDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Modal', - cnName: '模态弹窗', - }, - }, - { - path: 'pagination', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/pagination/demo/pagination-demo.module').then((m) => m.PaginationDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'Pagination', - cnName: '分页', - }, - }, - { - path: 'panel', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/panel/demo/panel-demo.module').then((m) => m.PanelDemoModule), - data: { - name: 'Panel', - cnName: '面板', - }, - }, - { - path: 'popover', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/popover/demo/popover-demo.module').then((m) => m.PopoverDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Popover', - cnName: '悬浮提示', - }, - }, - { - path: 'progress', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/progress/demo/progress-demo.module').then((m) => m.ProgressDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Progress', - cnName: '进度条', - }, - }, - { - path: 'quadrant-diagram', - component: ExamplePanelComponent, - loadChildren: () => - import('../../../devui/quadrant-diagram/demo/quadrant-diagram-demo.module').then((m) => m.QuadrantDiagramDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Quadrant Diagram', - cnName: '象限图', - }, - }, - { - path: 'radio', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/radio/demo/radio-demo.module').then((m) => m.RadioDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Radio', - cnName: '单选框', - }, - }, - { - path: 'rate', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/rate/demo/rate-demo.module').then((m) => m.RateDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Rate', - cnName: '等级评估', - }, - }, - { - path: 'search', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/search/demo/search-demo.module').then((m) => m.SearchDemoModule), - data: { - name: 'Search', - cnName: '搜索框', - }, - }, - { - path: 'select', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/select/demo/select-demo.module').then((m) => m.SelectDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Select', - cnName: '下拉选择框', - }, - }, - { - path: 'cascader', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/cascader/demo/cascader-demo.module').then((m) => m.CascaderDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Cascader', - cnName: '级联菜单', - }, - }, - { - path: 'status', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/status/demo/status-demo.module').then((m) => m.StatusDemoModule), - data: { - name: 'Status', - cnName: '状态', - }, - }, - { - path: 'sticky', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/sticky/demo/sticky-demo.module').then((m) => m.StickyDemoModule), - data: { - name: 'Sticky', - cnName: '便贴', - }, - }, - { - path: 'tabs', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tabs/demo/tabs-demo.module').then((m) => m.TabsDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'Tabs', - cnName: '选项卡切换', - }, - }, - { - path: 'tags', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tags/demo/tags-demo.module').then((m) => m.TagsDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Tags', - cnName: '标签', - }, - }, - { - path: 'tags-input', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tags-input/demo/tags.input-demo.module').then((m) => m.TagsInputDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'TagsInput', - cnName: '标签输入', - }, - }, - { - path: 'time-axis', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/time-axis/demo/time-axis-demo.module').then((m) => m.TimeAxisDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'TimeAxis', - cnName: '时间轴', - }, - }, - { - path: 'toast', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/toast/demo/toast-demo.module').then((m) => m.ToastDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Toast', - cnName: '全局通知', - }, - }, - { - path: 'tooltip', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tooltip/demo/tooltip-demo.module').then((m) => m.TooltipDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'Tooltip', - cnName: '提示', - }, - }, - { - path: 'read-tip', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/read-tip/demo/read-tip-demo.module').then((m) => m.ReadTipDemoModule), - data: { - type: '反馈', - enType: 'Feedback', - name: 'ReadTip', - cnName: '阅读提示', - description: '阅读提示组件。', - tmw: `当html文档中需要对特定内容进行提示时使用。`, - }, - }, - { - path: 'toggle', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/toggle/demo/toggle-demo.module').then((m) => m.ToggleDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Toggle', - cnName: '开关', - }, - }, - { - path: 'tree', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tree/demo/tree-demo.module').then((m) => m.TreeDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Tree', - cnName: '树', - }, - }, - { - path: 'upload', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/upload/demo/upload-demo.module').then((m) => m.UploadDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Upload', - cnName: '上传', - }, - }, - { - path: 'input-number', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/input-number/demo/input-number-demo.module').then((m) => m.InputNumberDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'InputNumber', - cnName: '数字输入框', - }, - }, - { - path: 'tree-select', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/tree-select/demo/tree-select-demo.module').then((m) => m.TreeSelectDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'TreeSelect', - cnName: '树形选择框', - }, - }, - { - path: 'slider', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/slider/demo/slider-demo.module').then((m) => m.SliderDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Slider', - cnName: '滑动输入条', - }, - }, - { - path: 'splitter', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/splitter/demo/splitter-demo.module').then((m) => m.SplitterDemoModule), - data: { - type: '布局', - enType: 'Layout', - name: 'Splitter', - cnName: '分割器', - }, - }, - { - path: 'layout', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/layout/demo/layout-demo.module').then((m) => m.LayoutDemoModule), - data: { - type: '布局', - enType: 'Layout', - name: 'Layout', - cnName: '布局', - }, - }, - { - path: 'gantt', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/gantt/demo/gantt-demo.module').then((m) => m.GanttDemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'Gantt', - cnName: '甘特图', - }, - }, - { - path: 'text-input', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/text-input/demo/text-input-demo.module').then((m) => m.TextInputDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'TextInput', - cnName: '文本框', - }, - }, - { - path: 'textarea', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/textarea/demo/text-demo.module').then((m) => m.TextDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'Textarea', - cnName: '多行文本框', - }, - }, - { - path: 'steps-guide', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/steps-guide/demo/steps-guide-demo.module').then((m) => m.StepsGuideDemoModule), - data: { - type: '导航', - enType: 'Navigation', - name: 'StepsGuide', - cnName: '操作指引', - }, - }, - { - path: 'time-picker', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/time-picker/demo/time-picker-demo.module').then((m) => m.TimePickerDemoModule), - data: { - type: '数据录入', - enType: 'Data Entry', - name: 'TimePicker', - cnName: '时间选择器', - }, - }, - { - path: 'relative-time', - component: ExamplePanelComponent, - loadChildren: () => import('../../../devui/relative-time/demo/demo.module').then((m) => m.DemoModule), - data: { - type: '数据展示', - enType: 'Data Display', - name: 'RelativeTime', - cnName: '人性化时间转换', - }, - }, -]; diff --git a/docs/i18n/en-us.json b/docs/i18n/en-us.json deleted file mode 100644 index 6f1a42cfc06dbe4709209a272acc6de28d07d1b2..0000000000000000000000000000000000000000 --- a/docs/i18n/en-us.json +++ /dev/null @@ -1,3277 +0,0 @@ -{ - "mainNav": { - "design": "DevUI Design", - "components": "Components", - "icons": "Icon Sets", - "versions": "Versions" - }, - "themePicker": { - "theme": "Theme", - "color": "Theme Color", - "mode": "Theme Mode", - "light": "Light Theme", - "dark": "Dark Theme", - "follow": "Follow System", - "largeSize": "Large FontSize", - "default":"Default", - "extend":"Extend", - "infinity": "Infinity", - "sweet": "Sweet", - "deep": "Deep", - "provence": "Provence" - }, - "public": { - "start": "Getting Started", - "themeDoc": "Customize Theme Docs", - "plus": "DevUI Plus", - "whenToUse": "When To Use", - "goTo": "Go To" - }, - "codebox": { - "showCode": "Show Code", - "hideCode": "Hide Code", - "copyCode": "Copy Code", - "success": "Success" - }, - "components": { - "accordion": { - "name": "Accordion", - "type": "Navigation", - "path": "accordion", - "description": "Navigation for your websites.", - "tmw": "Accordion is used when you need to set a menu list navigation.", - "basicDemo": { - "title": "Basic Usage", - "description": "Transfer a menu to listen to the open/close event (menuToggle) or click event (itemClick) of an expandable menu that contains sub-items. By default, the open attribute is used for expandable menus, the active attribute is used for clicking menus, and the disabled attribute is used for disabled items. Set restrictOneOpen to specify whether to display only one level-1 menu.", - "Only one level-1 menu can be expanded.": "Only one level-1 menu can be expanded.", - "Embedded menu (no shadow)": "Embedded menu (no shadow)", - "Content 1": "Content 1", - "Subcontent 1": "Subcontent 1", - "Subcontent 2": "Subcontent 2", - "Subcontent 3": "Subcontent 3", - "Content 2 (overlong, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long": "Content 2 (overlong, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long", - "Subcontent 1 (Extremely long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long,": "Subcontent 1 (Extremely long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long,", - "Content 3 (expanded by default)": "Content 3 (expanded by default)", - "Subcontent 1 (disabled)": "Subcontent 1 (disabled)", - "Subcontent 2 (activated by default)": "Subcontent 2 (activated by default)", - "Content 4 (no sub-item)": "Content 4 (no sub-item)", - "Content 5 (Disabled)": "Content 5 (Disabled)", - "Content 6 (dynamic loading)": "Content 6 (dynamic loading)" - }, - "changeKeyDemo": { - "title": "Changing key value", - "description": "Change the array key value through titleKey,childrenKey,disabledKey,activeKey to adapt to different interface types.", - "Content 1": "Content 1", - "Content 2 (expanded)": "Content 2 (expanded)", - "Subcontent 1 (disabled)": "Subcontent 1 (disabled)", - "Subcontent 2 (selected)": "Subcontent 2 (selected)", - "Subcontent 3": "Subcontent 3" - }, - "innerListTemplateDemo": { - "title": "Using List Templates", - "description": "Internal lists are used by developing innerListTemplate.", - "test": "Content of content 2" - }, - "linkDemo": { - "title": "Built-in route and link type", - "description": "Set linkType to switch the built-in route and link type. The default type is ''; Route type'routerLink' External link type:'hrefLink'; Determine the route or link type based on data: 'dependOnLinkTypeKey'.", - "Route Link (Recommended)": "Route Link (Recommended)", - "Native hyperlink (used in cross-site scenarios)": "Native hyperlink (used in cross-site scenarios)", - "Hybrid link (used in some cross-site scenarios)": "Hybrid link (used in some cross-site scenarios)", - "Basic components": "Basic components", - "accordion": "accordion", - "Anchor": "Anchor", - "Button": "Button", - "Advanced Component": "Advanced Component", - "Table (Disabled)": "Table (Disabled)", - "Dragging (Parameter Example)": "Dragging (Parameter Example)", - "Others": "Others", - "Icon Library": "Icon Library", - "Home page": "Home page", - "dragging": "dragging", - "Home page (new window)": "Home page (new window)", - "Home page (external link and open this window)": "Home page (external link and open this window)" - }, - "multiLevelDemo": { - "title": "Composite Hierarchy and Auto Expand", - "description": "Multiple levels and no restriction on nesting levels are supported. You can use autoOpenActiveMenu independently to automatically expand the parent level of an activated menu.", - "Automatically expand activated menus": "Automatically expand activated menus", - "Content 1 (menu only)": "Content 1 (menu only)", - "Content 2 (menu and content)": "Content 2 (menu and content)", - "Subcontent 1": "Subcontent 1", - "Subcontent 2": "Subcontent 2", - "Subcontent 3": "Subcontent 3", - "Content 3 (menu and content)": "Content 3 (menu and content)", - "Subcontent 1 (with sublists)": "Subcontent 1 (with sublists)", - "Subcontent 2 (with sublists)": "Subcontent 2 (with sublists)", - "Sub-sub-content 1": "Sub-sub-content 1", - "Sub-sub-content 2": "Sub-sub-content 2", - "Sub-content 3": "Sub-content 3", - "Content 4 (no content in the sublist)": "Content 4 (no content in the sublist)" - }, - "templateDemo": { - "title": "Using a Template", - "description": "Expandable menus and clickable menus use different templates. You can expand the menuItemTemplate or click the menu to specify an itemTemplate. No contentTemplate is specified for the data template. You can run the showNoContent command to control whether to expand the content when there is no data. The loadingTemplate parameter is specified in the loading template. The value of loadingKey of an item controls whether to display the loading status.", - "Reset": "Reset", - "Number of clicks:": "Number of clicks:", - "Not open yet. Please wait...": "Not open yet. Please wait...", - "It's loading hard.": "It's loading hard.", - "Content 1": "Content 1", - "Content 2": "Content 2", - "Content 3": "Content 3", - "Content 4 (customized template without data)": "Content 4 (customized template without data)", - "Content 5 (Customizing the Template Being Loaded)": "Content 5 (Customizing the Template Being Loaded)", - "The expandable menu node must have a non-undefined child.": "The expandable menu node must have a non-undefined child.", - "Subcontent 1": "Subcontent 1", - "Subcontent 2": "Subcontent 2", - "Subcontent 3": "Subcontent 3", - "Subcontent 4": "Subcontent 4", - "Subcontent 5": "Subcontent 5", - "Subcontent 6": "Subcontent 6", - "Subcontent 7": "Subcontent 7" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "use-built-in-routing-and-link-types": "Built-in route and link type", - "using-templates": "Using a Template", - "compound-level-and-auto-expand": "Composite Hierarchy and Auto Expand", - "change-values": "Change key value" - } - }, - "alert": { - "name": "Alert", - "type": "Feedback", - "path": "alert", - "description": "Display warnings to users.", - "tmw": "When the page needs to send a warning message to users.", - "basicDemo": { - "title": "Basic Usage", - "description": "There are 4 types of Alert: success, danger, warning, info." - }, - "closableDemo": { - "title": "Closable Prompt", - "description": "The close button is displayed. Click to close the prompt." - }, - "withoutIconDemo": { - "title": "Without Icon", - "description": "Without default icon." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "tips-to-close": "Closable Prompt", - "without-icon": "Without Icon" - } - }, - "anchor": { - "name": "Anchor", - "type": "Navigation", - "path": "anchor", - "description": "Go to one part of the page that in a specified location of a page.", - "tmw": "When you need to quickly jump to parts of a page.", - "basicDemo": { - "title": "Basic Usage", - "description": "For details about the scrolling effect, see sticky.", - "attention": "The component implements only the anchor function and can be used with sticky. For details about the scrolling effect, see sticky.", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here." - }, - "asyncDemo": { - "title": "Asynchronous Loading", - "description": "Asynchronous loading is supported. You can load menus or contents first, and then click the button to switch the loading.", - "Click to switch to asynchronous loading content.": "Click to switch to asynchronous loading content.", - "Asynchronous loading menu": "Asynchronous loading menu", - "Asynchronous loading of content": "Asynchronous loading of content", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here." - }, - "hashDemo": { - "title": "URL Hash Anchor", - "description": "Hash link for URL anchors and update hash.", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here.", - "Activating an anchor": "The address hash value is updated during anchor activation.", - "Refresh Hash Address": "Refresh the address hash value to take effect.", - "Click the anchor link in the Case List area.": "Click the anchor link in the Case List area.", - "Click the Quality Evaluation anchor.": "Click the Quality Evaluation anchor.", - "Initialize scrolling to the corresponding anchor point.": "Scroll to the corresponding anchor point only during initialization", - "Scroll to the corresponding anchor to take effect": "Scroll to the corresponding anchor to take effect", - "Jump to Requirements List via Hash and initialize": "Jump to Requirements List via Hash and reinitialize", - "Jump to the Requirement List via Hash": "Jump to the Requirement List via Hash" - }, - "scrollTargetDemo": { - "title": "Replace Rolling Container", - "description": "Replacing a Rolling Container Using ScrollTarget.", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "asynchronous-loading": "Asynchronous Loading", - "scroll-target": "Replace Rolling Container", - "support-hash": "URL Hash Anchor" - } - }, - "auto-complete": { - "name": "AutoComplete", - "type": "Data entry", - "path": "auto-complete", - "description": "Guess what users may need when entering.", - "tmw": "When you need to deduce the content that a user may want to enter according to some characters entered by the user.", - "basicDemo": { - "title": "Basic usage", - "description": "Set source to the data source that is automatically completed." - }, - "objectDemo": { - "title": "Customized data matching method", - "description": "You can use searchFn to customize the data matching method and the returned data format." - }, - "customDemo": { - "title": "Customized template display", - "description": "Use itemTemplate and noResultItemTemplate to customize the drop-down list box and display no matching message." - }, - "disabledDemo": { - "title": "Disabled", - "description": "You can set the disabled parameter to disable it in the text box and disable the options in the drop-down list box by using the disabledKey parameter.", - "Search Results": "Search Results" - }, - "latestDemo": { - "title": "Latest input", - "description": "Set latestSource to the latest input." - }, - "lazyLoadDemo": { - "title": "Enable lazy load", - "description": "enableLazyLoad: enables lazy loading." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "auto-object": "Customized data matching method", - "auto-custom": "Customized template display", - "auto-disable": "Disabled", - "auto-latest": "Latest input", - "auto-lazy-load": "Enable lazy load" - } - }, - "editormd": { - "name": "Markdown", - "type": "Data entry", - "path": "editormd", - "description": "Markdown Editor.", - "tmw": "When you need to edit Markdown files.", - "defaultDemo": { - "title": "Basic usage", - "description": "Displays the default basic functions of editor-md and supports bidirectional binding.", - "Current value of content.": "Current value of content:", - "Switching Modes": "Switching Modes", - "The input cannot be empty.": "The input cannot be empty.", - "Initialization Title": "Initialize the header. Do not use bidirectional binding to transfer values.", - "Bidirectional binding": "Bidirectional binding" - }, - "toolbarDemo": { - "title": "Customized toolbar", - "description": "Change the toolbar order and add custom buttons. The custom buttons support multiple input modes. (In this example, the Reference and Preview buttons are added.).", - "Open Preview": "Open Preview", - "Turn off preview": "Turn off preview", - "Customizing Button Sequence and Display": "Customizing Button Sequence and Display and Reference Buttons", - "Initialize when init": "Initialization is required during initialization to obtain the template reference.", - "Default toolbarConfig of the editor": "The default toolbarConfig of the editor is as follows:", - "quoting": "quoting" - }, - "xssDemo": { - "title": "Customized XSS filtering rules", - "description": "Customizing a specified tag filtering rule.", - "This is the input content.": "This is the input content.", - "Defines a custom attribute.": "A custom attribute is defined here. This attribute is added to the custom trustlist in XSS. You can see that this attribute is rendered when you view the elements on the console.", - "Another custom property is defined": "Another custom attribute is defined here. This attribute is not added to the XSS trustlist. The console displays that this attribute is not rendered.", - "Tag name.": "Tag name.", - "Current tag trustlist attribute array": "Current tag trustlist attribute array" - }, - "renderDemo": { - "title": "Render md text separately", - "description": "Render md text separately.The content added by CustomParse will not enter the XSS filtering.", - "This is the input content.": "This is the input content.", - "Defines a custom attribute.": "A custom attribute is defined here. This attribute is added to the custom trustlist in XSS. You can see that this attribute is rendered when you view the elements on the console.", - "Another custom property": "Another custom attribute is defined here. This attribute is not added to the XSS trustlist. The console displays that this attribute is not rendered.", - "relative link": "relative link", - "Tag name.": "Tag name.", - "Current tag trustlist attribute array": "Current tag trustlist attribute array", - "Added Text": "Here is the text added by the customized parse method,", - "The content is not filtered by the trustlist.": "This command will be executed after the markdown is parsed. The content will not be filtered by the trustlist." - }, - "parseDemo": { - "title": "Customized parse method", - "description": "The customized parse method processes the final output HTML.", - "Initialization Content": "Initialization Content", - "Added Text": "I am customizing what I add in the parse method, and I will be at the end anyway." - }, - "imageDemo": { - "title": "Configure image file upload", - "description": "Configuring Image File Upload.After setting imageUploadToServer, the editor will also monitor the paste operation, and if there are pictures, the imageUpload event will also be triggered.", - "Select an image to upload.": "Select an image and upload it to the server.", - "After imageUploadToServer is set": "After imageUploadToServer is set, the editor listens on the paste operation. If an image exists, the imageUpload event is triggered.", - "Open the file upload entry.": "Open the file upload entry.", - "Selecting a picture type": "Select an image of the bmp/jpg/jpeg/png/gif/tiff type.", - "Limit the image size.": "Select an image whose size is less than 1 MB.", - "Uploading a file": "Uploading a file", - "Failed to upload the image.": "Failed to upload the image." - }, - "hintDemo": { - "title": "Quick tips (@user)", - "description": "This parameter can be used in scenarios such as @selecting users.", - "Associated Member": "You can enter @ to associate a member and enter # to associate an order number.", - "Set Search": "Sets the search time.", - "User": "User", - "Order No.": "Order No." - }, - "markedDemo": { - "title": "Customized rendering", - "description": "Customizing the rendering rule from MD to HTML.", - "Level-1 Title": "Level-1 Title", - "Level-2 Title": "Level-2 Title", - "Level-3 Title": "Level-3 Title", - "Level-4 Title": "Level-4 Title", - "Level-5 Title": "Level-5 Title", - "Level 6 Title": "Level 6 Title" - }, - "enormousTextDemo": { - "title": "Processing a large amount of data", - "description": "Manually obtain content, instead of sending back events in real time. Currently, no frame freezing occurs during editing. The rendering is delayed (experimental function).", - "Generate 10,000 lines of data.": "Generate 10,000 lines of data.", - "Output the content in the editing area.": "Contents in the editing area of the console output", - "Initialization Title": "Initialize the header. Do not use bidirectional binding to transfer values.", - "Incoming Initialization": "The value of initial content can be transferred.", - "The change event is closed.": "If the change event is disabled, the content in the editing area is changed, and the event will not be triggered.", - "For details, see codemirror.": "For details about the editorRef method, see the official codemirror document.", - "Data": "This is the data in line ${i}." - }, - "anchorLinkValues": { - "basic-usage": "Basic usage", - "custom-toolbar": "Customized toolbar", - "custom-xss": "Customized XSS filtering rules", - "custom-render": "Customized rendering", - "custom-parse": "Customized parse method", - "img-upload": "Configure image file upload", - "quick-suggestion": "Quick tips (@user)", - "single-render-md": "Render md text separately", - "big-data-process": "Processing a large amount of data" - } - }, - "avatar": { - "name": "Avatar", - "type": "Data display", - "path": "avatar", - "description": "Display user's avatar.", - "tmw": "When users want to display their own profile avatar.", - "basicDemo": { - "title": "Basic Rules", - "description": "When the profile picture gadget transfers the name attribute, the profile picture field is displayed based on certain rules. For details, please see API.", - "cnStart": "If the value starts with Chinese, the last two characters are used.", - "enStart": "If the value starts with English, the first two characters are used.", - "multi": "If there are multiple English names, use the first two letters of the name.", - "others": "If the value does not start with Chinese or English, the first two characters are used." - }, - "configDemo": { - "title": "Basic Configuration", - "description": "The width, height, and whether the avatar is a circular can be set. In addition, the display fields of the avatar can be customized, and the customized image can be transferred.", - "smaller": "Sets the width. If the height is less than 30px, only one character is displayed.", - "custome": "The customText field is transferred.", - "img": "Import imgSrc:" - }, - "specialDemo": { - "title": "Special Display", - "description": "The avatar component processes some special situations, for example, the user does not exist or the default avatar is displayed. For details, please see API.", - "notExist": "If name, customText, and imgSrc are not transferred, the user who uses the avatar does not exist.", - "beNull": "If the values of name, customText, and imgSrc are empty, the user who uses the avatar does not have a nickname and the default avatar is used." - }, - "anchorLinkValues": { - "basic-rules": "Basic Rules", - "basic-configuration": "Basic Configuration", - "special-display": "Special Display" - } - }, - "ImagePreview": { - "name": "ImagePreview", - "type": "Data display", - "path": "ImagePreview", - "description": "Preview one or more pictures.", - "tmw": "Preview images or images in containers based on user input.", - "basicDemo": { - "title": "Basic Usage", - "description": "Run the image-preview command to preview images in the container." - }, - "customDemo": { - "title": "Customizing the preview window", - "description": "Transfer subject to enable preview when next is triggered.", - "previewImage": "Preview Picture" - }, - "zIndexDemo": { - "title": "Setting zIndex", - "description1": "Set zIndex to control the level of the pop-up effect.Set backDropZIndex to control the level of the back drop effect of the pop-up.", - "description2": "When zIndex is set to a value smaller than backDropZIndex, imagePreview is displayed below the back drop.", - "description3": "You can disable imagePreview by Esc.", - "previewImage": "Preview Picture" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "custom-usage": "Customizing the preview window", - "z-index-usage": "Setting zIndex" - } - }, - "breadcrumb": { - "name": "Breadcrumb", - "type": "Navigation", - "path": "breadcrumb", - "description": "Show the current hierarchy of pages.", - "tmw": "
    1. When users want to know the current hierarchy.
    2. When Users want to quickly return to the previous page.
    3. When users want to navigate to any page at the same level.
    ", - "basicDemo": { - "title": "Basic Breadcrumbs", - "itemText": "Define the display content through d-breadcrumb-item.", - "sourceText": "Display default breadcrumbs by inputting source.", - "content": "breadcrumbs" - }, - "menuDemo": { - "title": "Breadcrumbs with Dropdown menu" - }, - "customDemo": { - "title": "Customize", - "breadText": "breadcrumbs", - "anchorText": "Anchor", - "btnText": "Button" - }, - "sourceDemo": { - "title": "Source Config" - }, - "anchorLinkValues": { - "basic-breadcrumbs": "Basic Breadcrumbs", - "source-config-breadcrumbs": "Source Config", - "drop-down-breadcrumbs": "Breadcrumbs with Dropdown menu", - "self-defined-breadcrumbs": "Customize" - } - }, - "back-top": { - "name": "BackTop", - "type": "Navigation", - "path": "back-top", - "description": "A button for returning to the top of the page.", - "tmw": "When the page is too long, and the user wants to frequently return to the top to view related content.", - "basicDemo": { - "title": "Basic Usage", - "description": "Returns to the default style of the top button, 50px from the bottom, 30px on the right.", - "default": "Default Style", - "text": "After the function is enabled, slide down the scroll bar to view the default button on the top." - }, - "customizeDemo": { - "title": "Customize", - "description": "You can customize the button style for the backTop. The width and height are limited to 40 px * 40 px. In addition, you can set the scrolling height of the button by setting visibleHeight.", - "customizeStyle": "Customize the style of the back to top button. The width and height are limited to 40px * 40px.", - "text": "Enable the switch and slide down the scroll bar to display the button.", - "scrollHeight": "When the scrolling height reaches the value of visibleHeight, the button is displayed to the top." - }, - "scrollDemo": { - "title": "Scrolling Container", - "description": "You can set the scrollTarget parameter to return to the top of a specified container." - }, - "anchorLinkValues": { - "back-top-basic": "Basic Usage", - "back-top-customize": "Customize", - "back-top-scroll-container": "Scrolling Container" - } - }, - "button": { - "name": "Button", - "type": "General", - "path": "button", - "description": "The button is used to start an instant operation.", - "tmw": "When users want to mark or encapsulate a group of operation commands that respond to user clicks, and trigger the corresponding logic.", - "button-primary": { - "title": "Primary Buttons", - "ok": "Confirm", - "disabled": "Disabled" - }, - "button-common": { - "title": "Common Buttons", - "cancel": "cancels", - "disabled": "Disabled" - }, - "button-primary-and-common": { - "title": "Combinations of Primary & Common Buttons", - "description": "When a primary button is combined with a secondary button, a scene usually has only one primary button.", - "ok": "ok", - "cancel": "cancels", - "last": "Previous", - "next": "Next step" - }, - "button-left-right": { - "title": "Left & Right Buttons", - "left": "Left button", - "right": "Right button" - }, - "button-text": { - "title": "Text Buttons", - "ok": "ok", - "cancel": "cancels", - "disabled": "Disabled" - }, - "button-danger": { - "title": "Danger Buttons", - "description": "Indicates key operations in the system, such as purchase scenarios.", - "purchase": "Buy" - }, - "button-loading": { - "title": "Loading Buttons" - }, - "button-auto-focus": { - "title": "Auto-focus Buttons", - "description": "The autofocus button is used to automatically obtain the focus.", - "ok": "ok", - "cancel": "cancels" - }, - "button-icon": { - "title": "Icon Buttons", - "new": "Newly created", - "filter": "filtration", - "newDisabled": "New Disabled", - "filterDisabled": "Filter Disabled", - "connect": "correlative", - "run": "Execute", - "connectDisabled": "Association Disabled", - "runDisabled": "Execute Disable", - "select": "Please select", - "drop": "Select from the drop-down list box" - }, - "button-size": { - "title": "Button Size", - "description": "There are four sizes of buttons. You can select a proper size based on the service scenario.", - "tiny": "supersmall", - "small": "trumpet", - "normal": "Normal", - "large": "large" - }, - "button-groups": { - "title": "Button Group", - "description": "Put multiple buttons as a group into the button group container. The size of the button group can be set by size and mixed with the drop-down menu.", - "text": "The button group has four sizes. You can set the size of all elements by setting the size.", - "filter": "filtration", - "new": "Newly created", - "delete": "Deleted", - "drop": "Click the drop-down button.", - "itemOne": "Menu 1", - "itemTwo": "Menu 2", - "itemThree": "Menu 3" - }, - "anchorLinkValues": { - "button-primary": "Primary Buttons", - "button-common": "Common Buttons", - "button-primary-and-common": "Combinations of Primary & Common Buttons", - "button-left-right": "Left & Right Buttons", - "button-danger": "Danger Buttons", - "button-text": "Text Buttons", - "button-loading": "Loading Buttons", - "button-auto-focus": "Auto-focus Buttons", - "button-icon": "Icon Buttons", - "button-size": "Button Size", - "button-groups": "Button Group" - } - }, - "badge": { - "name": "Badge", - "type": "Data display", - "path": "badge", - "description": "Round logo of number in the upper right corner of the icon.", - "tmw": "The badge is appeared at the upper right corner of the icon or the right of a list item. It's usually an icon that shows a message with a number to tell user what need to be handled.", - "basicDemo": { - "title": "Basic Badge", - "description": "Basic badge type. When there is a package element, the badge and number are displayed in the upper right corner.", - "basic": "Standard badge. The count parameter specifies the number of badges to be displayed. The status parameter specifies the status color of the badge.", - "maxCount": "The maxCount parameter is used to set the maximum number of badges to be displayed. The default value is 99.", - "statusColor": "The bgColor parameter is used to set the status color of the badge. The offsetXY parameter is used to set the badge offset.", - "position": "Set badgePos to set the badge position.", - "unread": "Unread messages" - }, - "dotDemo": { - "title": "Dotted Badge", - "description": "Point badge type. When there is a package element and showDot is set to true, the dot is displayed in the upper right corner by default." - }, - "countDemo": { - "title": "Count Badge", - "description": "When the badge is used independently and does not enclose any elements, only the badge status color and number are displayed.", - "myCodeHub": "My Code Library", - "myFocus": "My Concerns", - "myManaged": "My Managed", - "customFontColor": "Customizing text and background colors using textColor and bgColor", - "code": "coded" - }, - "statusDemo": { - "title": "Status Badge", - "description": "When the badge is used independently, does not contain any elements, and the showDot parameter is set to true, the badge is a status badge. Different color dots are displayed for different statuses." - }, - "positionDemo": { - "title": "Badge Position", - "description": "Set badgePos to set the badge position." - }, - "customDemo": { - "title": "Custom", - "description": "The bgColor parameter is used to set the badge status color (the badge status color specified by status is invalid). The offsetXY parameter is used to set the badge offset relative to the badgePos.Customizing text and background colors using textColor and bgColor." - }, - "anchorLinkValues": { - "badge-basic": "Basic Badge", - "badge-dot": "Dotted Badge", - "badge-count": "Count Badge", - "badge-status": "Status Badge", - "position": "Badge Position", - "custom": "Custom" - } - }, - "card": { - "name": "Card", - "type": "Data display", - "path": "card", - "description": "Card container.", - "tmw": "This is a basic card container, which can contain text, list, picture, and paragraph. Generally used for overview.", - "basicDemo": { - "title": "Basic Usage", - "cardTitle": "DEVUI best practice course", - "cardContent": "DEVUI is an open-source, free-of-charge common solution for enterprise mid- and back-end products. Its design is based on \"simplicity\", \"immersive\", \"flexibility\", natural and humanistic combination." - }, - "customDemo": { - "title": "Customize Area", - "cardTitle": "DEVUI best practice course", - "text": "Updated on July 31 15:55" - }, - "mediaDemo": { - "title": "With Images", - "description": "You can use align to set the alignment mode of the d-card-actions operation area: start alignment, end alignment, and stretch alignment.", - "cardTitle": "DEVUI best practice course", - "cardContent": "DEVUI is an open-source, free-of-charge common solution for enterprise mid- and back-end products. Its design is based on \"simplicity\", \"immersive\", \"flexibility\", natural and humanistic combination." - }, - "anchorLinkValues": { - "card-basic": "Basic Usage", - "card-with-media": "With Images", - "card-custom": "Customize Area" - } - }, - "carousel": { - "name": "Carousel", - "type": "Data display", - "path": "carousel", - "description": "An area of carousel.", - "tmw": "Used to display images or cards.", - "basicDemo": { - "title": "Basic Usage" - }, - "triggerDemo": { - "title": "Indicator & Toggle Arrow", - "description": "If arrowTrigger is set to always, the arrow is permanently displayed. If dotTrigger is set to hover, it will switched when hover to the dots." - }, - "autoplayDemo": { - "title": "Automatic NVOD" - }, - "customDemo": { - "title": "Custom Operations" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "trigger-usage": "Indicator & Toggle Arrow", - "autoplay-usage": "Automatic NVOD", - "custom-usage": "Custom Operations" - } - }, - "checkbox": { - "name": "CheckBox", - "type": "Data entry", - "path": "checkbox", - "description": "Checkbox.", - "tmw": "
    1. Select multiple options from a group of options.
    2. This operation can be used independently to switch between two states, which can be combined with the commit operation.
    ", - "basicDemo": { - "title": "Basic Usage", - "selected": "Selected", - "unselected": "Unselected", - "customTitle": "Custom title", - "selectedClose": "Selected status - disabled", - "selectedDisable": "Disabled when selected", - "unselectedDisable": "Disabled when unselected", - "halfSelected": "Partially selected", - "halfSelectedDisable": "Disabled in half-selected mode", - "twoBind": "Bidirectional data binding", - "Custom Selected Color": "Custom Selected Color", - "Custom Half-Select Color": "Custom Half-Select Color", - "Customizing a Label Template": "Customizing a Label Template" - }, - "groupDemo": { - "title": "Checkbox Group", - "Input object array": "Input object array", - "Input string array": "Input string array", - "Disable Entire Group": "Disable Entire Group", - "Custom Selected Color": "Custom Selected Color", - "Selected status - disabled": "Selected status - disabled", - "Multi-line checkbox": "Multi-line checkbox" - }, - "conditionChangeDemo": { - "title": "Stop Checkbox Switching", - "description": "The switch status of the checkbox whose label is \"condition-based call-back forbidden\" is terminated based on the condition.", - "Conditional Callback Allowed": "Conditional Callback Allowed", - "Conditional judgment callback interception selected": "Conditional judgment callback interception selected" - }, - "conditionGroupDemo": { - "title": "Stop Checkbox Group Switching", - "description": "The checkbox with the 'block' field cannot switch the status.", - "stateNotSwitch": "The checkbox with the \"block\" field cannot switch the status.", - "intercepts": "intercepts" - }, - "anchorLinkValues": { - "checkbox-basic": "Basic Usage", - "tabs-group": "Checkbox Group", - "condition-change": "Stop Checkbox Switching", - "condition-group": "Stop Checkbox Group Switching" - } - }, - "common": { - "name": "Common", - "type": "General", - "path": "common", - "description": "Provide some common functions.", - "tmw": "Can be used to deal with date string conversion, file download, a tag simulation, and lazy loading.", - "lazyLoadDemo": { - "title": "Lazyload Directive", - "description": "LazyLoadModule in the util module is introduced. The dLazyLoad instruction is used to respond to the loadMore event when the container is rolled to the bottom to implement lazy loading." - }, - "pipeDemo": { - "title": "DatePipe" - }, - "openURLDemo": { - "title": "Open URL in A New Tag" - }, - "iframePropagateDemo": { - "title": "iframe Event Propagate API", - "description": "Click event of iframe will pass to the parent element." - }, - "clipboardDemo": { - "title": "Copy to Clipboard Directive" - }, - "helperDownloadDemo": { - "title": "Download File" - }, - "anchorLinkValues": { - "lazy-load": "Lazyload Directive", - "date-pipe": "Datepipe", - "open-url": "Open URL in A New Tag", - "download-file": "Download File", - "iframe-propagate": "iframe Event Propagate API", - "clipboard": "Copy to Clipboard Directive" - } - }, - "color-picker": { - "name": "ColorPicker", - "type": "Evolving", - "path": "color-picker", - "description": "A panel to enter or select colors.", - "tmw": "When user want to select a color.", - "basicDemo": { - "title": "Basic Usage" - }, - "tapDemo": { - "title": "Used with Dropdown" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "with-dropdown": "Used with Dropdown" - } - }, - "common-styles": { - "name": "CommonStyles", - "type": "Extended service", - "path": "common-styles", - "description": "Common style specifications of ng-devui.", - "tmw": "When you want to query ng-devui related styles, scenario related styles, and changes of styles.", - "hrefDemo": { - "title": "Link", - "description1": "1. Verify that the devui style sheet (devui.min.css) has been imported globally.", - "description2": "2. Use class=\"devui-link\" to modify the style of ." - }, - "colorDemo": { - "title": "Color", - "description1": "1. DevUI sorts color specifications, including common color values and dark mode color values, and lists the usage scenarios of these colors. To better control and display, DevUI classifies colors and names semantic variables.", - "description2": "2. By `@import' ~ng-devui/styles-var/devui-var.scss '; `.The color variable can be used after being introduced.", - "description3": "3. If the style sheet is a less file, '@import' ~ng-devui/styles-var/devui-var.less '; `, and change the variable prefix '$' to '@'." - }, - "shadowDemo": { - "title": "Shadow", - "description1": "1. The component library provides shadow variables for users in different scenarios. The following table lists the names, values, and application scenarios of these variables.", - "description2": "2. By `@import' ~ng-devui/styles-var/devui-var.scss '; `.The shadow variable can be used after being introduced. ", - "description3": "3. If the style sheet is a less file, '@import' ~ng-devui/styles-var/devui-var.less '; `, and change the variable prefix '$' to '@'." - }, - "fontDemo": { - "title": "Font", - "description1": "1. The component library provides font variables for users in different scenarios. The following table lists the names, values, and application scenarios of these variables.", - "description2": "2. By `@import' ~ng-devui/styles-var/devui-var.scss '; `.The font variable can be used after being introduced.", - "description3": "3. If the style sheet is a less file, '@import' ~ng-devui/styles-var/devui-var.less '; `, and change the variable prefix '$' to '@'." - }, - "cornerDemo": { - "title": "border-radius", - "description1": "1. The component library provides border-radius variables for users in different scenarios. The following table lists the names, values, and application scenarios of these variables.", - "description2": "2. By `@import' ~ng-devui/styles-var/devui-var.scss '; `.The border-radius variable can be used after being introduced.", - "description3": "3. If the style sheet is a less file, '@import' ~ng-devui/styles-var/devui-var.less '; `, and change the variable prefix '$' to '@'." - }, - "anchorLinkValues": { - "href-a": "Link", - "color": "Color", - "shadow": "Shadow", - "font": "Font", - "border-radius": "border-radius" - } - }, - "codemirror": { - "name": "CodeMirror", - "type": "Extended service", - "path": "codemirror", - "description": "Code display.", - "tmw": "Used to display logs, shell scripts or compile code.", - "basicDemo": { - "title": "Basic Usage", - "description": "Configuring themes and patterns." - }, - "eventDemo": { - "title": "Event Listening" - }, - "anchorLinkValues": { - "basic": "Basic Usage", - "event": "Event Listening" - } - }, - "datatable": { - "name": "DataTable", - "type": "Data display", - "path": "datatable", - "description": "Displays row and column data.", - "tmw": "
    1. When a large amount of structured data need to be displayed.
    2. When complex operations such as data sorting, filtering, and customization are required.
    ", - "basicDemo": { - "title": "Basic Usage", - "description": "Simple table, displaying list data\nTwo implementation modes are supported. Method 1 is implemented by customizing the head and body templates and the rows and cells in the templates. Method 2 is implemented by configuring columns." - }, - "asyncDemo": { - "title": "Asynchronously loading data, configuration columns, and empty data templates", - "description": "Simulates asynchronous data loading, supports dynamic column configuration, and uses #noResultTemplateRef to configure an empty data template." - }, - "cellMergeDemo": { - "title": "Cell Merge", - "description": "You can use properties such as colspan and rowspan to set cell combination. You can only customize the head and body templates and the rows and cells in the templates." - }, - "checkOptionsDemo": { - "title": "Customizing Table Selection", - "description": "You can set checkOptions to configure the drop-down list box and the operations to be performed in the table header.\nTwo implementation modes are supported. Method 1 is implemented by customizing the head line, and method 2 is implemented by configuring columns." - }, - "dragColumnDemo": { - "title": "Column dragging", - "description": "This field is a low-frequency operation and is not displayed by default. When you move the cursor to the table header, a flag is displayed, allowing users to quickly sort columns." - }, - "dragRowDemo": { - "title": "Row dragging", - "description": "The DragDrop component can be used to drag rows in a table. You can only customize the head and body templates and the rows and cells in the templates." - }, - "batchDragRowDemo": { - "title": "Batch Row dragging", - "description": "You can use the DragDrop component to drag rows in a table in batches. You can press Ctrl and select multiple rows and cells to drag them. You can only customize the head and body templates and the rows and cells in the templates." - }, - "editableDemo": { - "title": "Edit Cell", - "description": "Two implementation modes are supported. Method 1 is implemented by customizing cells in the body template. Method 2 is implemented by configuring columns." - }, - "expandRowDemo": { - "title": "Extended Row", - "description": "Two implementation modes are supported. Method 1 is implemented by customizing rows in the body template. Method 2 is implemented by defining tables by configuring columns and configuring input and row data." - }, - "fixColumnDemo": { - "title": "fixed column", - "description": "If there are too many columns in a table, fixed columns facilitate data location and comparison when you swipe left or right on the screen. You can set fixedLeft and fixedRight to specify the columns.\nTwo implementation modes are supported. Method 1 is implemented by customizing the head and body templates and the rows and cells in the templates. Method 2 is implemented by configuring columns." - }, - "fixHeightVirtualScrollDemo": { - "title": "Table Header Fixed Virtual Scroll", - "description": "Use fixHeader to set the table header fixed and enable virtual scrolling. The height is adaptive." - }, - "headerGroupingDemo": { - "title": "Header Group", - "description": "Two implementation modes are supported. Method 1 is implemented by customizing colspan and rowspan of th in the head template. Method 2 is implemented by configuring advancedHeader of column." - }, - "interactionDemo": { - "title": "Table interaction", - "description": "Supports column sorting, column filtering, customized filtering template, selection, and column width adjustment.\nTwo implementation modes are supported. Method 1 is implemented by customizing the head and body templates and the rows and cells in the templates. Method 2 is implemented by configuring columns." - }, - "lazyDemo": { - "title": "lazy loading", - "description": "Use lazy to enable lazy loading. When the bottom of a table is scrolled, the loadMore event is triggered to implement lazy loading." - }, - "maxHeightDemo": { - "title": "Table Header Fixed", - "description": "Use fixHeader to set the table header to be fixed so that the table header does not follow the scrolling process." - }, - "mutiDragRowDemo": { - "title": "Batch line dragging", - "description": "You can use the DragDrop component to drag rows in a table in batches. You can press Ctrl and select multiple rows and cells to drag them. You can only customize the head and body templates and the rows and cells in the templates." - }, - "mutilStylesDemo": { - "title": "Table Style" - }, - "treeTableDemo": { - "title": "Tree table", - "description": "Configure the rendering tree table based on the nestedColumn attribute and the child and $isChildTableOpen fields of row data.\nTwo implementation modes are supported. Method 1 is implemented by customizing the head and body templates and the rows and cells in the templates. Method 2 is implemented by configuring columns." - }, - "virtualScrollDemo": { - "title": "Virtual scrolling", - "description": "Use virtualScroll to enable virtual scrolling. The row height must be fixed and the same. If the row height is higher than the default 40px, virtualItemSize must be configured.\nIf there is no data in the initial state, set the height of the element whose class is `cdk-virtual-scroll-viewport`, and set the position of the `d-data-table` element and noResult template." - }, - "allDemo": { - "tab1": "Customizing a Template", - "tab2": "Configuring columns" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "mutil-styles": "Table Style", - "async-loading": "Asynchronous data loading", - "table-interaction": "Table interaction", - "table-check-options": "Customizing Table Selection", - "lazy-loading-of-list-data": "Lazy loading", - "virtual-scroll": "Virtual scrolling", - "table-fixing": "Table Header Fixed", - "fixed-virtual-scroll": "Table Header Fixed Virtual Scroll", - "header-grouping": "Header Group", - "edit-cell": "Edit Cell", - "expand-row": "Extended Row", - "tree-form": "Tree table", - "fixed-column": "Fixed column", - "column-dragging": "Column dragging", - "cell-merge": "Cell Merge", - "drag-row": "Row dragging", - "muti-drag-row": "Batch Row dragging" - } - }, - "datepicker": { - "name": "DatePicker", - "type": "Data entry", - "path": "datepicker", - "description": "Enter or select a date.", - "tmw": "When users want to enter a date or click the input box to select a date.", - "basicDemo": { - "title": "Basic Usage", - "basic": "Basic Usage", - "setCss": "Setting cssClass", - "disableTitle": "In the disabled state, you can use this effect or set the value by referring to the dateRangePicker parameter." - }, - "clearButtonDemo": { - "clear": "purging", - "today": "Today", - "title": "Custom Clear Button", - "description": "The clear button is added to customViewTemplate. The clearAll() button is used to trigger the clear operation.The clearAll() parameter can be transferred to define different reasons." - }, - "templateDemo": { - "selectYesterday": "Select Yesterday", - "selectTomorrow": "Choose Tomorrow", - "select": "Select", - "title": "Custom Operation Area", - "description": "Use customViewTemplate to customize the date or content in the operation area. You can use chooseDate(dateString: string) to set the date." - }, - "formatDemo": { - "reset": "Reset", - "title": "formatting", - "description": "Set the date format through dateFormat." - }, - "limitDemo": { - "title": "Max. and Min. Date Limit", - "limit": "limit", - "limitTogether": "simultaneous restriction" - }, - "setModeDemo": { - "title": "Set Mode ", - "yearPicker": "Set year datePicker by mode='year'", - "monthPicker": "Set year/month datePicker by mode='month'", - "description": "Only the year or month or date can be selected. The specific day may not be required. For example, the year can be 1999, August 1994, or August 15th of 1994. If this parameter is not set, the default is date. There are two mode which are year and month." - }, - "rangeDemo": { - "selectToday": "Choose Today", - "selectStart": "Select the iteration start date.", - "selectWeek": "Select one week later", - "selectEnd": "Select iteration end date", - "title": "Range Date Picker", - "description": "As with the Single Day Date Selector, the current date is selected by default when the Range Date Selector expands. The range date selector includes the start date selector and the end date selector. You can select a date." - }, - "rangeClearDemo": { - "clearTitle": "Date range selector: A parameter can be transferred to clearAll() to define different reasons. The everyRange method is for reference only. The business needs to process the parameter based on the site requirements.", - "clear": "purging", - "title": "Date Range Selector Custom Operation Area and Clear Button", - "description": "Date range selector: A parameter can be transferred to clearAll() to define different reasons. The everyRange method is for reference only. The business needs to process the parameter based on the site requirements." - }, - "rangePickerDemo": { - "rangePicker": "Date Range Selector (auto-hide when selected):", - "valuedRangePicker": "Assigned date range selector (default: left open when selected):", - "cssRangePicker": "Date range selector (set cssClass):", - "title": "Date Range Selector Integration Mode" - }, - "rangeDisableDemo": { - "rangePicker": "Date Range Selector:", - "title": "Date Range Selector Forbidden", - "description": "The disabled status of the datepicker is unavailable. You can perform the operation based on the service requirements." - }, - "rangeFormatDemo": { - "formaterRange": "Date range selector (set format):", - "configRange": "Date Range Selector (set dateConfig):", - "title": "Date Range Selector Formatting" - }, - "rangeRestrictedDemo": { - "limitRange": "The date range selector restricts the start and end ranges. The everyRange method is for reference only. The service side needs to process the method as required.", - "limitStartRange": "Date Range Selector restricts the start range:", - "limitEndRange": "Date Range Selector Limit To:", - "title": "Date Range Selector Optional Range" - }, - "rangeTimeDemo": { - "dateTimeRange": "Date Time Range Selector:", - "valuedTimeRange": "Date Time Range Selector has been assigned:", - "title": "Date Range Selector Select Time" - }, - "rangeTodayDemo": { - "rangePicker": "Date Range Selector:", - "selectYesterday": "Select Yesterday", - "selectWeek": "Select Last Week", - "selectToday": "Choose Today", - "selectTomorrow": "Choose Tomorrow", - "title": "Date Range Selector Custom Action Select Date", - "description": "Select Date, together with rangeStart and rangeEnd to set a customized date." - }, - "twoDatePickerDemo": { - "twoRangePicker": "Hide after double date selector selection", - "keepOpenedPicker": "Double date selector (set cssClass) remains open after the selection is complete.", - "disabledPicker": "Disable the dual date selector (for reference only, or set by referring to dateRangePicker).", - "title": "Double Date Selector" - }, - "twoDatepickerFormatDemo": { - "formaterRange": "Dual Date Selector Formatting", - "configRange": "Setting dateConfig by Double Date Selector", - "title": "Dual Date Selector Formatting" - }, - "appendToBodyDemo": { - "title": "Attached to the body" - }, - "buttonDemo": { - "title": "Date selection button", - "description": "You can click the button to call the Datepicker." - }, - "anchorLinkValues": { - "datepicker-default": "Basic Usage", - "datepicker-set-mode": "Set Mode", - "datepicker-min-max": "Max. and Min. Date Limit", - "datepicker-append-to-body": "Attached to the body", - "datepicker-range": "Range Date Picker", - "datepicker-range-basic": "Date Range Selector Integration Mode", - "datepicker-range-format": "Date Range Selector Formatting", - "datepicker-range-disabled": "Date Range Selector Forbidden", - "datepicker-range-restricted-range": "Date Range Selector Optional Range", - "datepicker-range-time": "Date Range Selector Select Time", - "datepicker-clear-button": "Date Range Selector Custom Action Area, Clear", - "datepicker-range-today": "Date Range Selector Custom Action Select Date", - "datepicker-format": "formatting", - "custom-view-template": "Custom Operation Area", - "date-picker-clear-button": "Custom Clear Button", - "date-picker-button": "Date selection button", - "two-date-picker-basic": "Double Date Selector", - "two-date-picker-format": "Dual Date Selector Formatting" - } - }, - "echarts": { - "name": "Echarts", - "type": "Extended service", - "path": "echarts", - "description": "Chart visualization.", - "tmw": "Used to display statistics intuitively and visually.", - "changeBgDemo": { - "changeBg": "Modify Background Color", - "clickChange": "Click to switch the background of the pie chart.", - "title": "Changing the Chart Background Color", - "description": "Real-time background color change." - }, - "instanceDemo": { - "listener": "Listening event", - "clickTime": "clicks", - "title": "Obtaining an Echarts Instance", - "description": "Obtain the Echoarts instance and invoke the API." - }, - "basicDemo": { - "title": "Render a pie chart", - "description": "Simple usage, rendering a pie chart." - }, - "anchorLinkValues": { - "render-pie": "Render a pie chart", - "chart-bg": "Changing the Chart Background Color", - "chart-ins": "Obtaining an Echarts Instance" - } - }, - "jsmind": { - "name": "Jsmind", - "type": "Extended service", - "path": "jsmind", - "description": "Mind map.", - "tmw": "When you want to display some horizontal structure to others", - "basicDemo": { - "title": "Basic Usage", - "description": "Render a basic mind map." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage" - } - }, - "multi-auto-complete": { - "name": "MultiAutoComplete", - "type": "Data entry", - "path": "multi-auto-complete", - "description": "Match possible options of input.", - "tmw": "When users want to select multiple options.", - "defaultDemo": { - "title": "Basic Usage", - "description": "Set the data source through source.", - "Please select": "Please select" - }, - "arrayDemo": { - "title": "Custom Matching Method", - "description": "Use searchFn to customize the data matching method and returned data format. If you need to clear or copy data, you can use the customized button.", - "Choose three options": "Select at least three options.", - "emptied": "emptied", - "replicated": "replicated", - "Select Object": "Select Object", - "Run the browser copy command.": "Run the browser copy command.", - "Copy succeeded.": "Copy succeeded.", - "Data replicated successfully": "The data was successfully copied to the clipboard." - }, - "disabledDemo": { - "title": "Use Disabled", - "description": "You can specify whether to enable or disable the function by using the disabled command." - }, - "anchorLinkValues": { - "basic-usage": "Basic usage", - "auto-complete-array": "Custom matching method", - "auto-complete-disabled": "Disabled" - } - }, - "form": { - "name": "Form", - "type": "Data entry", - "path": "form", - "description": "A form that supports data collection, verification, and submission, including check boxes, option boxes, text boxes, and drop-down list boxes.", - "tmw": "Used for data collection, data verification, and data submission.", - "basicDemo": { - "title": "Basic usage", - "description": "In basic usage, the label is above the data box.", - "d-form-item-title": "Form item d-form-item", - "d-form-item-description": "Indicates a form item, including the form label and a specific form input component.", - "d-form-label-title": "Form item d-form-label", - "d-form-label-description": "Indicates the form item label, which describes the form keyword, including the help information and whether the field is mandatory.", - "d-form-control-title": "Control container d-form-control", - "d-form-control-description": "Form item control container, which contains different form input components.", - "d-form-operation-title": "Operation area container d-form-operation", - "d-form-operation-description": "Operation area container, which is used to place elements such as buttons.", - "That's the plan name.": "This is the plan name, the plan name, the plan name.", - "Plan Name": "Plan Name", - "Plan Description": "Plan Description", - "Radio box": "Radio box", - "Multiple options": "Multiple options", - "Label Options": "Label Options", - "Label": "Label", - "switch": "switch", - "Execution Date": "Execution Date", - "Submit": "Submit", - "cancels": "cancels", - "Option": "Option", - "Manual execution": "Manual execution", - "Daily Scheduled Execution": "Daily Scheduled Execution", - "Weekly scheduled execution": "Weekly scheduled execution", - "Monday": "Monday", - "tuesday": "tuesday", - "Wednesday": "Wednesday", - "thursday": "thursday", - "friday": "friday", - "Saturday": "Saturday", - "Sunday": "Sunday", - "Option (Multiple Choices with Delete)": "Option (Multiple Choices with Delete)" - }, - "labelHorizontalDemo": { - "title": "Label horizontal arrangement", - "description": "Left-right layout of labels.", - "Plan Name": "Plan Name", - "Short Name": "Enter a short name that meets reading habits. The short name contains a maximum of 30 characters. It cannot be a system field or be the same as an existing field name.", - "Plan Description": "Plan Description", - "Radio box": "Radio box", - "check box": "check box", - "Label Options": "Label Options", - "Single Option": "Single Option", - "Label": "Label", - "switch": "switch", - "Execution Date": "Execution Date", - "Submit": "Submit", - "cancels": "cancels", - "Select your execution cycle": "Select your execution period. You are advised to select Monday, Wednesday, or Friday.", - "Option": "Option", - "Manual execution": "Manual execution", - "Daily Scheduled Execution": "Daily Scheduled Execution", - "Weekly scheduled execution": "Weekly scheduled execution", - "Monday": "Monday", - "tuesday": "tuesday", - "Wednesday": "Wednesday", - "thursday": "thursday", - "friday": "friday", - "Saturday": "Saturday", - "Sunday": "Sunday", - "Option (Multiple Choices with Delete)": "Option (Multiple Choices with Delete)" - }, - "modalDemo": { - "title": "Pop-up form", - "description": "Pop-up form. The recommended pop-up box size is 400px, 550px, 700px, and 900px. The recommended aspect ratio is 16:9 or 3:2.", - "Pop-up form": "Pop-up form", - "ok": "ok", - "cancels": "cancels" - }, - "multiColDemo": { - "title": "Multiple Lists", - "description": "Multiple lists.", - "That's the plan name.": "This is the plan name, the plan name, the plan name.", - "Plan Name": "Plan Name", - "Radio box": "Radio box", - "check box": "check box", - "Label Options": "Label Options", - "switch": "switch", - "Execution Date": "Execution Date", - "Submit": "Submit", - "cancels": "cancels", - "Option": "Option", - "Manual execution": "Manual execution", - "Daily Scheduled Execution": "Daily Scheduled Execution", - "Weekly scheduled execution": "Weekly scheduled execution", - "Monday": "Monday", - "tuesday": "tuesday", - "Wednesday": "Wednesday", - "thursday": "thursday", - "friday": "friday", - "Saturday": "Saturday", - "Sunday": "Sunday", - "Option (Multiple Choices with Delete)": "Option (Multiple Choices with Delete)" - }, - "templateValidateDemo": { - "title": "Template driven form validation", - "description": "To bind ngModel, ngGroupModel, and ngForm elements to the template, you can use dValidateRules to configure validation rules." - }, - "innerValidatorDemo": { - "title": "Verify a single element by using a built-in validator", - "description": "

    Currently, DevUI supports the following built-in validators: required, minlength, maxlength, min, max, requiredTrue, email, pattern, and whitespace.

    If the user input cannot contain only spaces, use whitespacebuilt-in validator

    If the user input length needs to be restricted, it is a good idea to set the maximum limit to the actual verification value +1. In addition to pattern, other built-in validators also provide built-in error messages. If you do not customize a message, the default message is used.

    " - }, - "customerValidatorDemo": { - "title": "Verify a single element and customize a validator", - "description": "
    • A validator requires a unique id identifier. You can explicitly declare this id or declare a key that does not conflict with the reserved word, the key is identified as id, and value functions as a validator.
    • customized validator. You can return true | false to indicate whether the current validation is successful or return string | null to indicate whether the current validation is successful and return an error message. This method applies to dynamic error prompts.
    • If the validator is an asynchronous validator, you need to return your value as an Observable object. More, DevUI is compatible with the native angular validator. You can set isNgValidator to true.
    " - }, - "customErrorStrategyDemo": { - "title": "Verify a single element. The update policy errorStrategy is incorrectly configured and the validation moment updateOn is incorrectly configured.", - "description": "
    • Specifies whether to display an error message if the verification of the errorStrategy element fails during initialization. The default value is dirty. If you want to display an error during initialization, set this parameter to prisine.
    • errorStrategy can be inherited.
    • Set updateOn to specify the verification moment. The validator updateOn is set based on the updateOn of the bound model. You can specify the validator by using ngModelOptions in the template. The default value is change, the options are as follows: blur and submit. If submit is set, validation is triggered when the form where the element is located is submitted.
    " - }, - "customMessageShowDemo": { - "title": "Verify a single element and customize management message prompts", - "description": "
    • Set messageShowType to select the message automatic prompt mode. The default value is popover.
    • If popover is set to popover, error information will be displayed as popover when the element is focused. If
    • is set to text, error information is automatically displayed under the element in text mode (used with the form control container). If is set to none, error information is not automatically displayed in the view, you can obtain message from the template, or obtain the error message by listening to the messageChange event, or directly obtain the error message from the template by reference.
    • This configuration can be inherited. The
    • can customize the pop-up direction when the message prompt mode is set to popover. The default value is ['right','bottom'].
    • This configuration can be inherited.
    " - }, - "debounceTimeDemo": { - "title": "Verify a single element and customize asyncDebounceTime", - "description": "
    • The default value of 300ms debounce time is provided for the asynchronous validator.
    • You can also set asyncDebounceTime in dValidateRules.
    • If your synchronization validator also needs debounce time, the verification is asynchronous and you can convert it to an asynchronous validator.
    • This configuration can be inherited.
    " - }, - "validateTemplateForm": { - "title": "Form Validation and Submission", - "description": "
    • dValidateRules can also be used on the ngForm and ngModelGroup elements that have been bound to the elements to manage form status and error messages in a unified manner.
    • For non-frame elements, you are advised to set dHasFeedback to true in the d-form-item container to provide error feedback.
    • For dForm, the dFormSubmit and dFormReset instructions can be used to associate elements that will trigger the commit and reset operations.
    • If asynchronous validation is set for the form, the loading button can be associated with the pending status of the form.
    " - }, - "userRegisterDemo": { - "title": "Form verification and submission, user registration scenario", - "description": "
    • For complex validation rules in form scenarios, it is recommended that you organize them in the controller to better organize and reuse your validation rules.
    • For automatic error prompt mode, it is recommended that you set messageShowType in dForm.
    • For the submission event triggered by dFormSubmit, you can bind dSubmit to the dForm layer, you can obtain the current form validation status and the corresponding directive reference.
    • If the form is not in the visual center when it is submitted, you can use a prompt to guide the user visually. For the prompt when the form is submitted, it is recommended that d-toast be displayed.
    " - }, - "validateReactiveDemo": { - "title": "Reactive form validation", - "description": "Bind formGroup, formControlName, and formControl to the template and use dValidateRules to configure validation rules.

    Recommended reading [Angular reactive form]

    " - }, - "customStatusDemo": { - "title": "Feedback status of a specified form", - "description": "You can manually specify the feedback status by setting feedbackStatus for d-form-control. Currently, the following statuses are supported: success, error, and pending." - }, - "validateSyncDemo": { - "title": "Form collaboration verification", - "description": "In some scenarios, your multiple form components depend on each other, joint verification (for example, password input and confirmation in registration scenarios) is required. In this case, you need to use the collaborative verification instruction dValidateSyncKey to specify the same keydValidateSyncKey instruction for the components that require system verification to support template-driven forms and reactive forms, the following example uses a template-driven form as an example: password and confirmPassword are set to the same value of dValidateSyncKey. When the value of one component changes, the other component also verifies the value." - }, - "validateCrossComponentDemo": { - "title": "Cross-component verification", - "description": "
    • Current Angular By default, Form does not support cross-component form verification status sharing. For response forms, you can use model to centrally manage and transparently transmit components.
    • For template-driven forms, you can inject the required ngModelGroup or NgForm container by using container injection during subcomponent declaration, for form elements in the template to automatically obtain the parent container.
    " - }, - "reactiveCrossComponent": { - "title": "Responsive form cross-component validation" - }, - "templateCrossComponent": { - "title": "Template-driven form cross-component verification" - }, - "anchorLinkValues": { - "basic-usage": "Basic usage", - "demo-label-horizontal": "Label horizontal arrangement", - "demo-modal": "Pop-up form", - "demo-multi-col": "Multiple lists", - "demo-filter": "Form filtering", - "demo-validate-template": "Template-driven form validation (recommended)", - "demo-validate-reactive": "Reactive form validation", - "demo-custom-status": "Specify form status", - "demo-validate-sync": "Form collaboration verification", - "demo-validate-cross-component": "Cross-component form validation" - } - }, - "fullscreen": { - "name": "Fullscreen", - "type": "General", - "path": "fullscreen", - "description": "Fullscreen.", - "tmw": "When users want to display an area with fullscreen mode.", - "immersiveDemo": { - "title": "Immersive full screen", - "description": "Immersive full screen display.", - "fullscreen": "Full screen", - "exitFullscreen": "Exit Full Screen" - }, - "normalDemo": { - "title": "Common full screen", - "description": "Full screen of the current browser window.", - "fullscreen": "Full screen", - "exitFullscreen": "Exit Full Screen" - }, - "anchorLinkValues": { - "immersive-full-screen": "Immersive full screen", - "general-full-screen": "Common full screen" - } - }, - "transfer": { - "name": "Transfer", - "type": "Data entry", - "path": "transfer", - "description": "Double-column selection box.", - "tmw": "When you need to select multiple options, the tranfer can move data in both columns to complete the selection behavior. The left column means source, and the right column means target. The data in the two columns is returned for developers.", - "basicDemo": { - "title": "Basic Usage", - "description": "Basic Usage of Shuttle Boxes.", - "sourceTitle": "Source Title", - "targetTitle": "Target Title", - "disabled:": "Disabled:", - "option1": "Option 1 (including this option forbidding transfer)", - "option2": "Option 2", - "option3": "Option 3", - "option4": "Option 4", - "option5": "Option 5", - "option6": "Option 6", - "option7": "Option 7", - "option8": "Option 8", - "option9": "Option 9", - "option10": "Option 10", - "option11": "Option 11", - "option12": "Option 12", - "option13": "Option 13", - "option14": "Option 14", - "option15": "Option 15", - "option16": "Option 16", - "option17": "Option 17", - "option18": "Option 18", - "option19": "Option 19", - "option20": "Option 20", - "option21": "Option 21" - }, - "searchDemo": { - "title": "Search Shuttle Box", - "description": "When there is a large amount of data, you can search for and filter the data.", - "sourceTitle": "Source Title", - "targetTitle": "Target Title", - "disabled:": "Disabled:", - "option1": "Option 1", - "option2": "Option 2", - "option3": "Option 3", - "option4": "Option 4", - "option5": "Option 5", - "option6": "Option 6", - "option7": "Option 7", - "option8": "Option 8", - "option9": "Option 9", - "option10": "Option 10", - "option11": "Option 11", - "option12": "Option 12", - "option13": "Option 13", - "option14": "Option 14", - "option15": "Option 15", - "option16": "Option 16", - "option17": "Option 17", - "option18": "Option 18", - "option19": "Option 19" - }, - "sortDemo": { - "title": "Sorting Shuttle Box", - "description": "You can sort the data of the shuttle box source and destination boxes.", - "sourceTitle": "Source Title", - "targetTitle": "Target Title", - "disabled:": "Disabled:", - "option1": "Option 1", - "option2": "Option 2", - "option3": "Option 3", - "option4": "Option 4", - "option5": "Option 5", - "option6": "Option 6", - "option7": "Option 7", - "option8": "Option 8", - "option9": "Option 9", - "option10": "Option 10", - "option11": "Option 11", - "option12": "Option 12", - "option13": "Option 13", - "option14": "Option 14", - "option15": "Option 15", - "option16": "Option 16", - "option17": "Option 17", - "option18": "Option 18", - "option19": "Option 19", - "option20": "Option 20", - "option21": "Option 21" - }, - "customDemo": { - "title": "Custom Shuttle Box", - "description": "You can customize the display of the contents of the shuttle box.", - "sourceTitle": "Source Title", - "targetTitle": "Target Title", - "disabled:": "Disabled:", - "option1": "Option 1", - "option2": "Option 2", - "option3": "Option 3", - "option4": "Option 4", - "option5": "Option 5", - "option6": "Option 6", - "option7": "Option 7", - "option8": "Option 8", - "option9": "Option 9", - "option10": "Option 10", - "option11": "Option 11", - "option12": "Option 12", - "option13": "Option 13", - "option14": "Option 14", - "option15": "Option 15", - "option16": "Option 16", - "option17": "Option 17", - "option18": "Option 18", - "option19": "Option 19", - "option20": "Option 20", - "option21": "Option 21" - }, - "anchorLinkValues": { - "transfer-demo-base": "Basic Usage", - "transfer-demo-search": "Search Shuttle Box", - "transfer-demo-sort": "Sorting Shuttle Box", - "transfer-demo-custom": "Custom Shuttle Box" - } - }, - "dragdrop": { - "name": "DragDrop", - "type": "General", - "path": "dragdrop", - "description": "Drag and drop.", - "tmw": "When multiple steps are required and the sequence of the steps needs to be adjusted flexibly.", - "basicDemo": { - "title": "Basic Usage", - "description": "Dragging a container to another container and sorting.", - "Default dragging": "Default dragging", - "Dragable Item": "Dragable Item", - "Place Sort Area": "Place Sort Area", - "Placement Area (No Sorting)": "Placement Area (No Sorting)", - "(Do not drag)": "(Do not drag)" - }, - "treeDemo": { - "title": "Multi-layer tree dragging", - "description": "Sorting can be dragged to elements and hierarchical nesting is supported.", - "Multi-layer tree dragging": "Multi-layer tree dragging", - "Candidate area": "Candidate area", - "Tree Sorting Area": "Tree Sorting Area" - }, - "followDemo": { - "title": "Drag Entity Elements to Follow", - "description": "Allow non-transparent elements to follow when dragging. You can also use appendToBody: If the parent object in the source position is destroyed after dragging it away, you need to attach the clone to the body to prevent it from being destroyed. By default, the style of the entity to be cloned is copied to ensure that the style of the entity to be cloned is correct. However, some styles and attributes that depend on the DOM node location may fail. You need to manually adjust some styles.", - "Drag Entity Elements to Follow": "Drag Entity Elements to Follow", - "Dragable Item": "Dragable Item", - "Place Sort Area": "Place Sort Area", - "Attaching the clone entity to the body": "Attaching the clone entity to the body", - "AppendToBody of dragFollowOptions is used in the following scenarios: If the parent object in the source location is destroyed after being dragged out, attach the clone to the body to prevent it from being destroyed. By default, the style of the cloned body is copied to ensure that the style of the cloned body is correct. However, some styles and attributes that depend on the DOM node location may fail. In this case, you need to manually adjust some styles.": "AppendToBody of dragFollowOptions is used in the following scenarios: If the parent object in the source location is destroyed after being dragged out, attach the clone to the body to prevent it from being destroyed. By default, the style of the cloned body is copied to ensure that the style of the cloned body is correct. However, some styles and attributes that depend on the DOM node location may fail. In this case, you need to manually adjust some styles." - }, - "switchDemo": { - "title": "crossover exchange", - "description": "Sets switchWhileCrossEdge to allow switching when crossing the edge. Note: This parameter cannot be used together with dropOnItem. This parameter is invalid when dropOnItem is set to true.", - "Move the mouse over the edge of the element.": "Move the mouse over the edge of the element.", - "Drag-and-drop sorting exchange": "Drag-and-drop sorting exchange" - }, - "positionDemo": { - "title": "External Placement Position: near, front, rear", - "description": "When you use defaultDropPostion to configure areas other than the sorter, the elements are added to the front or behind of the list by default. By default, the elements are added to the nearest area (closest).", - "Drag-and-drop items": "Drag-and-drop items", - "Drag and drop here Add to top": "Drag and drop here Add to top", - "Drag and drop here Add to bottom": "Drag and drop here Add to bottom", - "Drag and drop here Add nearest": "Drag and drop here Add nearest" - }, - "dropScrollDemo": { - "title": "Drag and scroll container enhancement", - "description": "Use the dDropScrollEnhanced instruction to accelerate the scroll bar to both sides when dragging to the edge.", - "Drag an element to the edge of the scroll bar to trigger scrolling.": "Drag an element to the edge of the scroll bar to trigger scrolling.", - "Show drag-and-drop scrolling area": "Show drag-and-drop scrolling area", - " Active area. Drag to trigger scrolling.": " Active area. Drag to trigger scrolling.", - " Inactive area, elements under which elements are dragged are placed.": " Inactive area, elements under which elements are dragged are placed." - }, - "originPlaceholderDemo": { - "title": "Source Placeholder", - "description": "Use originPlaceholder to display the placeholder for the source position, and the example disappears.", - "Drag from here. The source placeholder disappears directly after being placed.": "Drag from here. The source placeholder disappears directly after being placed.", - " Drag from here, the source placeholder disappears after the delay": " Drag from here, the source placeholder disappears after the delay", - "Drag from here, the source placeholder disappears after it is placed. Animation": "Drag from here, the source placeholder disappears after it is placed. Animation" - }, - "batchDragDemo": { - "title": "Batch dragging", - "description": "You can use the batchDrag command to drag tags in batches.", - "Batch dragging is supported. Press Ctrl to select multiple items and drag them.": "Batch dragging is supported. Press Ctrl to select multiple items and drag them.", - "Show Source Placeholders": "Show Source Placeholders", - "crossover exchange": "crossover exchange", - "Clear Selected": "Clear Selected" - }, - "crossDimensionDemo": { - "title": "Two-dimensional dragging And Dragging and previewing", - "description": "Use the dDragDropSyncBox, dDragSync, and dDropSync instructions to implement two-dimensional dragging. Use dDragPreview Configure drag and drop preview. Use the d-drag-preview-clone-dom-ref to clone a dragged node.", - "Owner": "Owner", - "To be allocated": "To be allocated", - "Lin Huahua": "Lin Huahua", - "Wang Xiaoming": "Wang Xiaoming", - "Newly created": "Newly created", - "Ongoing": "Ongoing", - "Completed": "Completed" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "multi-level-tree-drag": "Multi-layer tree dragging", - "drag-entity-elements-to-follow": "Drag Entity Elements to Follow", - "cross-edge-switching": "crossover exchange", - "external-location": "External Placement Position", - "drag-and-roll-container-enhancement": "Drag and scroll container enhancement", - "source-placeholder": "Source Placeholder", - "batch-drag-and-drop": "Batch dragging", - "2D-drag-and-drop-preview": "Two-dimensional drag and preview" - } - }, - "drawer": { - "name": "Drawer", - "type": "Feedback", - "path": "drawer", - "description": "The floating layer panel that slides out from the screen edge.", - "tmw": "
    1. The drawer slides in from the edge of the parent window to cover part of the parent window, and you don't have to leave the current task. After the operations are complete, you can smoothly return to the original task.
    2. When an additional panel is required to control the content of the parent form, the panel is called out when needed. For example, you can control the display style of the page and add content to the page.
    3. Create or preview additional content when you need to insert a temporary task into the current task flow. For example, display agreement terms and create child objects.
    ", - "basicDemo": { - "title": "Basic Usage", - "description": "Basic usage to control full screen, close, and set width." - }, - "undestroyableDemo": { - "title": "Do not destroy after being closed", - "description": "Manual destruction is required. This mode applies to scenarios where immediate destruction is not required.", - "openSlider": "Open side sliding window", - "manualDestroy": "Manual Destroy", - "closeManualDestroy": "If this function is disabled, it can be manually destroyed. If this function is enabled, it is invalid." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "do-not-destroy-after-closing": "Do not destroy after being closed" - } - }, - "dropdown": { - "name": "DropDown menu", - "type": "Navigation", - "path": "dropdown", - "description": "Press to display the list.", - "tmw": "When there are too many operation commands on the page, this component can be used to contain operation elements. When you click or move into a drop-down menu, You can select a value from the dropdown list.", - "basicDemo": { - "title": "Basic Usage", - "description": "test.", - "More Operations": "More Operations", - "Text box": "Text box", - "Disable Options": "Disable Options", - "Newly created": "Newly created", - "Deleted": "Deleted", - "Menu 1": "Menu 1", - "Menu 2": "Menu 2", - "Menu 3": "Menu 3", - "Menu 4": "Menu 4", - "Attach to the body to prevent it from being blocked by the scroll bar.": "Attach to the body to prevent it from being blocked by the scroll bar." - }, - "hoverDemo": { - "title": "Hover dropdown", - "description": "Pass trigger Set the trigger mode (click or floating) for the drop-down list.", - "Menu 1": "Menu 1", - "Menu 2": "Menu 2", - "Menu 3": "Menu 3" - }, - "focusDemo": { - "title": "Automatically expanded during focus and automatically focused during initialization", - "description": "Pass toggleOnFocus Sets the tab key to automatically expand when the focus is performed. Pass autoFocus Set the auto focus during initialization. the two may be used in combination or separately.", - "When you press Tab to navigate to the dropdown Toggle object, the menu is automatically expanded.": "When you press Tab to navigate to the dropdown Toggle object, the menu is automatically expanded.", - "More Operations": "More Operations", - "Disable Options": "Disable Options", - "Newly created": "Newly created", - "Deleted": "Deleted", - "Menu 1": "Menu 1", - "Menu 2": "Menu 2", - "Menu 3": "Menu 3", - "Menu 4": "Menu 4", - "The focus is automatically performed during initialization. It can be automatically expanded with toggleOnFocus or used independently.": "The focus is automatically performed during initialization. It can be automatically expanded with toggleOnFocus or used independently.", - "Initialization/Destruction": "Initialization/Destruction", - "Text box": "Text box" - }, - "closeScopeDemo": { - "title": "Close Trigger Point Settings", - "description": "Pass closeScope Set the trigger point for closing the menu. The options are as follows: blank: triggered only when a non-menu area is clicked; all: triggered also in the menu area; none: You can click the drop-down list box to close the area or manually close the area.", - "The drop-down menu is closed only after you click the menu.": "The drop-down menu is closed only after you click the menu.", - "Click the drop-down button.": "Click the drop-down button.", - "Text box": "Text box", - "Menu 1": "Menu 1", - "Menu 2": "Menu 2", - "Menu 3": "Menu 3", - "Self-closed": "Self-closed", - "Click the last menu item to close it.": "Click the last menu item to close it.", - "Menu 1 Disable": "Menu 1 Disable", - "Close": "Close" - }, - "appendToBodyDemo": { - "title": "When appendToBody is used, set the expansion position and change the alignment object.", - "description": "Pass appendToBodyDirections Set the priority list of the expanded position. Pass alignOrigin Change Default Alignment Object.", - "Align with regions Use bottom left (right aligned below), top left (right aligned above display)": "Align with regions Use bottom left (right aligned below), top left (right aligned above display)", - "Align the area.": "Align the area.", - "Drop-down button": "Drop-down button", - "Disable Options": "Disable Options", - "Newly created": "Newly created", - "Deleted": "Deleted", - "Using Centered Display": "Using Centered Display", - "Creating a Content": "Creating a Content", - "Deleted content": "Deleted content" - }, - "manuallyDemo": { - "title": "Manual pull-down control", - "description": "Sets the manual pull-down control by using the trigger." - }, - "set-is-openDemo": { - "title": "Control dropdown meanu with isOpen" - }, - "addIconDemo": { - "title": "Adding icons", - "description": "test.", - "Newly created": "Newly created", - "Delete": "Delete", - "Menu 1": "Menu 1", - "Menu 2": "Menu 2", - "Menu 3": "Menu 3", - "Menu 4": "Menu 4" - }, - "multiLevelDemo": { - "title": "Multi-level drop-down menu", - "description": "test.", - "Click": "Click", - "More options": "More options", - "Content 1": "Content 1", - "Content 1-1": "Content 1-1", - "Content 1-1-1": "Content 1-1-1", - "Content 1-1-2": "Content 1-1-2", - "Content 1-1-3": "Content 1-1-3", - "Content 1-2": "Content 1-2", - "Content 1-2-1": "Content 1-2-1", - "Content 2": "Content 2", - "hovering": "hovering", - "Click to expand the menu. The menu is automatically closed when you exit.": "Click to expand the menu. The menu is automatically closed when you exit." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "turn-off-trigger-point-settings": "Close Trigger Point Settings", - "suspension-drop-down": "Hover dropdown", - "manually-control": "Manual pull-down control", - "dropdown-set-is-open": "Control Dropdown Meanu with IsOpen", - "auto-expand-and-auto-focus": "Auto-expand and auto-focus", - "when-using-appendtobody": "Set the expansion position processing", - "add-icon": "Adding icons", - "multi-level-drop-down-menu": "Multi-level drop-down menu" - } - }, - "editable-select": { - "name": "EditableSelect", - "type": "Data entry", - "path": "editable-select", - "description": "You can enter or select a value from the drop-down list box.", - "tmw": "You can use it easily when you want to search existed data.", - "basicDemo": { - "title": "Basic usage", - "description": "Set source to a data source." - }, - "disableDataDemo": { - "title": "Set disable options", - "description": "Disabling specified data." - }, - "searchFunctionDemo": { - "title": "Customized data matching method", - "description": "Use searchFn to customize the data matching method." - }, - "async-data-function": { - "title": "Asynchronously obtaining the data source and setting the matching method", - "description": "Data sources and matching methods can be set asynchronously." - }, - "lazyLoadDemo": { - "title": "Enable lazy load", - "description": "Data lazy loading." - }, - "anchorLinkValues": { - "basic-usage": "Basic usage", - "disable-data-with-source": "Set disable options", - "with-search-function": "Customized data matching method", - "async-data-with-function": "Asynchronously obtaining the data source and setting the matching method", - "lazy-load": "Enable lazy load" - } - }, - "editorx": { - "name": "EditorX", - "type": "Data entry", - "path": "editorx", - "description": "Rich Text Editor.", - "tmw": "You can use it easily when you need to edit rich text.", - "defaultDemo": { - "title": "Default Example", - "description": "Displaying the default functions of EditorX." - }, - "customToolbarDemo": { - "title": "Custom Toolbar", - "description": "Complete functions + Custom toolbar grouping + Collapse of tools that are not commonly used." - }, - "readOnlyModeDemo": { - "title": "Read-only Mode", - "description": "Read-only mode, no toolbar, no word count. You can press the Save button or Ctrl+S to change the mode to read-only. You can press the Edit button to change the mode to edit." - }, - "expandToolbarDemo": { - "title": "Expand Toolbar", - "description": "Adding a toolbar, custom triggering event, and operating an editor object." - }, - "initWithObjDemo": { - "title": "Init With Obj", - "description": "Use the object format object to initialize the editor (instead of the default HTML format). The object format is more suitable for persistent storage and is recommended for storage in the background." - }, - "uploadDemo": { - "title": "Image And File Upload", - "description": "To upload images and files to the server, you need to replace the upload interface in the example with the actual background interface." - }, - "charStatisticsDemo": { - "title": "Character Statistics", - "description": "Collects statistics on the number of characters, words, and HTML characters that are currently entered, and customizes the display template." - }, - "customFullScreenDemo": { - "title": "Customizing The Full-Screen Mode", - "description": "The default value is immersive full-screen. You can set the value to common full-screen and customize the full-screen hierarchy." - }, - "globalHrefDemo": { - "title": "Global Links", - "description": "Global Links." - }, - "richTextInDrawerDemo": { - "title": "Rich Text in Drawer", - "description": "Using the Rich Text Editor in the Drawer. " - }, - "xssDemo": { - "title": "XSS", - "description": "XSS." - }, - "anchorLinkValues": { - "default-example": "Default Example", - "custom-toolbar": "Custom Toolbar", - "read-only-mode": "Read-only Mode", - "expand-toolbar": "Expand Toolbar", - "init-with-obj": "Init With Obj", - "upload": "Image And File Upload", - "char-statistics": "Character Statistics", - "custom-full-screen": "Customizing The Full-Screen Mode", - "global-href": "Global Links", - "rich-text-in-drawer": "Rich Text in Drawer", - "xss": "XSS" - } - }, - "loading": { - "name": "Loading", - "type": "Feedback", - "path": "loading", - "description": "Tell user that some command is now being executed.", - "tmw": "When the command execution takes a long time (more than several seconds), use loading to tell user.", - "basicDemo": { - "title": "Basic Usage", - "description": "The basic scenario where table data is loaded.", - "click me!": "click me!", - "FirstName": "FirstName", - "LastName": "LastName", - "UserName": "UserName" - }, - "customDemo": { - "title": "Custom Style", - "description": "Customize the loading style using templateRef.", - "Loading Style 2": "Loading Style 2", - "Loading Style 3": "Loading Style 3", - "Text loading": "Text loading" - }, - "promiseDemo": { - "title": "Multipromise", - "description": "Multiple promises are supported.", - "click": "click" - }, - "subscriptionDemo": { - "title": "Using The Subscription Mode", - "description": "Using subscription to control the display of loading information.", - "click": "click" - }, - "showLoadingDemo": { - "title": "Using ShowLoading", - "description": "Use true or false of showLoading to control the display of loading.", - "click me!": "click me!", - "FirstName": "FirstName", - "LastName": "LastName", - "UserName": "UserName" - }, - "fullScreenDemo": { - "title": "Service function", - "description": "Load the loading component in full screen mode or on a specified host using services." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "custom-style": "Custom Style", - "multi-promise": "Multipromise", - "use-subscription-mode": "Using The Subscription Mode", - "show-loading": "Using ShowLoading", - "full-screen": "Service function" - } - }, - "modal": { - "name": "Modal", - "type": "Feedback", - "path": "modal", - "description": "Modal.", - "tmw": "
    1. If you want to process a transaction but do not want to jump to another page to interrupt the workflow, you can use modal to open a floating layer in the middle of the current page to carry the corresponding operation.
    2. The pop-up window is used to interact with users. Users can enter information, read prompts, and set options in the dialog box.
    ", - "basicDemo": { - "title": "Standard Dialog Box", - "description": "Standard dialog boxes that can be dragged using the dialogService." - }, - "customizeDemo": { - "title": "Custom Dialog Box", - "description": "You can use modalService to customize all the contents in the dialog box." - }, - "hideDemo": { - "title": "Blocking dialog box closed", - "description": "Set the blocking method for closing a dialog box by using the beforeHidden parameter." - }, - "tipsDemo": { - "title": "Information", - "description": "Information dialog box of various types." - }, - "warningDemo": { - "title": "Warning Dialog Box", - "description": "Standard warning dialog box." - }, - "basicUpdateDemo": { - "title": "Update the button status in the pop-up dialog box", - "description": "Update the button configuration in the dialog configuration using the update method." - }, - "autofocusDemo": { - "title": "Configure button to automatically get focus", - "description": "Configure the autofocus attribute in buttons of the DialogService service to enable the button to obtain the focus automatically. You can press Enter to trigger the button to be clicked." - }, - "templateDemo": { - "title": "Customizing a pop-up box content template", - "description": "The contentTemplate attribute can be transferred to configure the dialog box content template." - }, - "templateFixedDemo": { - "title": "The outer layer is fixed to solve the jitter and scrolling problem.", - "description": "The outer fixed value is used to avoid scrolling and jitter. In this mode, the position of all fixed elements on the page needs to be specified. If the default value is used, the position offset occurs." - }, - "anchorLinkValues": { - "standard-dialog": "Standard Dialog Box", - "custom-dialog": "Custom Dialog Box", - "intercept-dialog-closed": "Blocking dialog box closed", - "message-hint": "Information", - "warning-pop-up": "Warning Dialog Box", - "update-button-options": "Update the button status in the pop-up dialog box", - "configure-button-to-get-focus-automatically": "Configure button to automatically get focus", - "template-content": "Customizing a pop-up box content template", - "template-fixed": "The outer layer is fixed to solve the jitter and scrolling problem" - } - }, - "pagination": { - "name": "Pagination", - "type": "Navigation", - "path": "pagination", - "description": "Pagination.", - "tmw": "When loading/rendering all the data takes a long time, you can use pagination to split the data.", - "basicDemo": { - "title": "Basic Usage", - "description": "test.", - "Standard Size": "Standard Size", - "Medium size": "Medium size", - "Large size": "Large size", - "Custom Style": "Custom Style", - "Set total to 0.": "Set total to 0.", - "Go to": "Go to" - }, - "liteDemo": { - "title": "Simplified Mode", - "description": "Simplified mode applies to pages with a large amount of information, which simplifies page complexity.", - "Common Simplified Mode": "Common Simplified Mode", - "Total number of records": "Total number of records", - "Set total to 0.": "Set total to 0.", - "Set total to 20.": "Set total to 20.", - "Set total to 30000.": "Set total to 30000.", - "Set total to 100000.": "Set total to 100000.", - "Set index to 2.": "Set index to 2.", - "Set index to 3.": "Set index to 3.", - "Ultra-simplified mode": "Ultra-simplified mode", - "Setting drop-down menu with extensible settings": "Setting drop-down menu with extensible settings", - "Display Field": "Display Field", - "Click Settings.": "Click Settings.", - "Display Mode": "Display Mode" - }, - "widgetsDemo": { - "title": "Multiple Configurations", - "description": "Set the input jump and display jump buttons. Sets functions such as pageSize." - }, - "additionalDemo": { - "title": "Special Circumstances", - "description": "Pager display in special scenarios.", - "Set total to 0.": "Set total to 0.", - "Set total to 5.": "Set total to 5.", - "Set total to 15.": "Set total to 15." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "minimalist-model": "Simplified Mode", - "multiple-configurations": "Multiple Configurations", - "exceptional-case": "Special Circumstances" - } - }, - "panel": { - "name": "Panel", - "type": "General", - "path": "panel", - "description": "Content panel, which is used to group content.", - "tmw": "This parameter is used when the page content needs to be displayed in groups. Generally, this parameter contains the header, content area, and bottom part.", - "basicDemo": { - "title": "Basic Usage" - }, - "typeDemo": { - "title": "Multiple types", - "description": "There are six panels like default, primary, success, danger, warning, and info." - }, - "conditionChangeDemo": { - "title": "Prevent Collapse Based on Conditions", - "description": "When a panel is expanded, if you click folding block button, the panel cannot be collapsed. When the panel is folded, operations are not affected.", - "Prevent Folding": "Prevent Folding" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "multiple-types": "Multiple types", - "condition-change": "Prevent Collapse Based on Conditions" - } - }, - "popover": { - "name": "Popover", - "type": "Feedback", - "path": "popover", - "description": "Simple text prompt box.", - "tmw": "Used to notify users of non-critical problems or to indicate that a control is in a special situation.", - "basicDemo": { - "title": "Basic Usage" - }, - "manualDemo": { - "title": "Manual Control Display", - "description": "Displaying the pop-up dialog box through the visible interface to verify the form. To use the visible control function, set controlled to the default value false.", - "nameErrMsg": "The value must contain at least four characters." - }, - "customizeDemo": { - "title": "Basic Usage", - "description": "The HTMLElement or TemplateRef type can be transferred.", - "customizeTip": "Custom Tips", - "isCustomizeTip": "This is a custom tip.", - "customizeTipLink": "Custom Tips with Links", - "learnMore": "Learn More" - }, - "scrollElementDemo": { - "title": "Parent Container Settings", - "description": "ScrollElement configuration. The default value is window. This parameter is optional by default. It is required only when the page scrolling is not in the window." - }, - "hoverDelayTimeDemo": { - "title": "Delay Trigger", - "description": "Only when the trigger type is hover. This event is triggered only when the mouse pointer is moved in for more than [mouseEnterDelay] milliseconds. The default value is 150 ms to prevent flashing caused by unintentional strokes. The toolTip component is hidden only after [mouseLeaveDelay] milliseconds after the cursor is moved out. The default value is 100 milliseconds." - }, - "positionDemo": { - "title": "Position", - "description": "A total of 12 pop-up positions are supported." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "manual-control-display": "Manual Control Display", - "custom-prompt-content": "Custom Tips", - "parent-container-settings": "Parent Container Settings", - "hover-delay-time": "Delay Trigger", - "position": "Position" - } - }, - "progress": { - "name": "Progress", - "type": "Data display", - "path": "progress", - "description": "Progress bar.", - "tmw": "
    1. When the operation takes a long time.
    2. When an operation takes a long time to interrupt the current interface or background operation.
    3. To display the percentage of completed operations or the number of completed steps/total steps.
    ", - "basicDemo": { - "title": "Basic Usage", - "description": "Basic progress and text configuration." - }, - "circleDemo": { - "title": "Circle Usage", - "description": "Basic progress and text configuration." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "circle-usage": "Circle Usage" - } - }, - "quadrant-diagram": { - "name": "Quadrant Diagram", - "type": "Evolving", - "path": "quadrant-diagram", - "description": "Quadrant.", - "tmw": "To manage the priority of transactions.", - "basicDemo": { - "title": "Basic Usage" - }, - "customizeDemo": { - "title": "Customize", - "description": "Separately set the placement area. Set dropScope to 'devui-quadrant-diagram'." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "custom-quadrant": "Customize" - } - }, - "radio": { - "name": "Radio", - "type": "Data entry", - "path": "radio", - "description": "Radio button.", - "tmw": "The user selects a single option from a dataset and can view all options.", - "basicDemo": { - "title": "Independent Radios" - }, - "conditionChangeDemo": { - "title": "Switch with Condition", - "description": "The second item cannot be redirected based on the condition." - }, - "conditionRadioGroupDemo": { - "title": "Switch With Condition in A Radio Group", - "description": "The second radio group is not allowed to jump." - }, - "disabledDemo": { - "title": "Disabled Radio" - }, - "horizontalDemo": { - "title": "Horizontal Arrangement" - }, - "verticalDemo": { - "title": "Vertical Arrangement" - }, - "customDemo": { - "title": "Custom Radios", - "description": "The array source can be a common array or an object array." - }, - "anchorLinkValues": { - "basic-usage": "Independent Radios", - "condition-change": "Switch with Condition", - "condition-radio-group": "Switch With Condition in A Radio Group", - "disabled": "Disabled Radio", - "horizontal": "Horizontal Arrangement", - "vertical": "Vertical Arrangement", - "custom": "Custom Radios" - } - }, - "rate": { - "name": "Rate", - "type": "Data display", - "path": "rate", - "description": "Rate.", - "tmw": "When you expect users to rate a product.", - "basicDemo": { - "title": "Dynamic Mode", - "currentStar": "Currently 2 stars" - }, - "onlyReadDemo": { - "title": "Read-only Mode" - }, - "customizeDemo": { - "title": "Dynamic Mode-Custom" - }, - "typeDemo": { - "title": "Use the type parameter" - }, - "anchorLinkValues": { - "read-only-mode": "Read-only Mode", - "dynamic-mode": "Dynamic Mode", - "dynamic-mode-Custom": "Dynamic Mode-Custom", - "using-the-type-parameter": "Use the type parameter" - } - }, - "search": { - "name": "Search", - "type": "General", - "path": "search", - "description": "Search box.", - "tmw": "When you need to search for required data in a dataset, you can enter the content (or part) of the required data to return the search results of all the matching content.", - "basicDemo": { - "title": "Basic Usage", - "small": "Small size", - "middle": "Standard Size", - "large": "Large size", - "disable": "Disabled", - "searchLeft": "Search icon left", - "autoFoucs": "autofocus", - "insertKey": "Enter a keyword." - }, - "ngModelDemo": { - "title": "Two-way Binding" - }, - "leftIconDemo": { - "title": "Left Search Icon" - }, - "autoFocusDemo": { - "title": "Auto Focus" - }, - "no-borderDemo": { - "title": "No Border" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "bidirectional-binding": "Two-way Binding", - "icon-left": "Left Search Icon", - "auto-focus": "Auto Focus", - "search-no-border": "No Border" - } - }, - "select": { - "name": "Select", - "type": "Data entry", - "path": "select", - "description": "Drop-down list box.", - "tmw": "The user can select one or more options from multiple options. Only options provided by the system can be selected and searched from the drop-down list box.", - "SelectBasicDemo": { - "title": "Basic Usage", - "description": "Pass options Configure the data source by configuring the overview and size styles by configuring the direction by configuring the direction.", - "Large size": "Large size", - "Standard Size": "Standard Size", - "Small size": "Small size", - "Option": "Option", - "New Option": "New Option", - "Asynchronous option 1": "Asynchronous option 1" - }, - "CustomSearchDemo": { - "title": "Custom Search", - "description": "Over the search function is enabled and the search method is customized for isSearch and searchFn. The searchPlaceholder parameter specifies the text displayed in the search box to enable the multi-selection function.", - "Single-choice custom search method": "Single-choice custom search method", - "Search My Options": "Search My Options", - "Multi-choice self-defined search method": "Multi-choice self-defined search method", - "Select at least three options.": "Select at least three options.", - "Option": "Option" - }, - "SelectAllDemo": { - "title": "Select All", - "description": "Select multiple options from the drop-down list box. isSelectAll Enable Select All.", - "Current Select": "Current Select", - "Option": "Option" - }, - "SelectTemplateDemo": { - "title": "Customized template", - "description": "Configure the drop-down list and selected options using the template.", - "Single choice": "Single choice", - "Use templates only for lists": "Use templates only for lists", - "Use the same template in the list and selected items": "Use the same template in the list and selected items", - "Use different templates in lists and selected items": "Use different templates in lists and selected items", - "Multiple Choices": "Multiple Choices", - "Use different templates for the list and selected items. Use built-in templates in some cases.": "Use different templates for the list and selected items. Use built-in templates in some cases." - }, - "AllowClearValueDemo": { - "title": "Allow clearing values", - "description": "test.", - "test": "Option" - }, - "CustomAreaDemo": { - "title": "Custom Area", - "description": "Use customViewTemplate Defining a Custom Area.", - "Custom Area": "Custom Area", - "Selected xx items": "Selected xx items", - "Option": "Option" - }, - "CustomAreaDirectionDemo": { - "title": "Customizing Area Orientation and Selecting", - "description": "test.", - "Customizing Area Orientation and Selecting": "Customizing Area Orientation and Selecting", - "Customize the region and change the width alignment by appendToBody.": "Customize the region and change the width alignment by appendToBody.", - "Recent Selections": "Recent Selections", - "Option": "Option" - }, - "AppendToBodyDemo": { - "title": "Attach to the body.", - "description": "Use appendToBody The container is attached to the body and is not blocked by the scroll bar.", - "Select from the drop-down list box": "Select from the drop-down list box", - "Option": "Option" - }, - "DisabledDemo": { - "title": "Disabled", - "description": "Pass disabled Disable the drop-down list box. The $disabled option of the option object is disabled, and the $immutable option of the option object is disabled.", - "Disable All": "Disable All", - "Disable an item": "Disable an item", - "Disable an item, Tags cannot be operated independently. You can select or deselect all tags.": "Disable an item, Tags cannot be operated independently. You can select or deselect all tags.", - "Disable an item, Use immutable to disable changes. Select all and deselect all.": "Disable an item, Use immutable to disable changes. Select all and deselect all.", - " The immutable parameter cannot be changed and is not displayed as disabled. To disable the immutable parameter, use the disabled parameter.": " The immutable parameter cannot be changed and is not displayed as disabled. To disable the immutable parameter, use the disabled parameter.", - "Option": "Option" - }, - "LabelizationDemo": { - "title": "Labeling", - "description": "Pass extraConfig.labelization Tag-based configuration: 1. If enable is set to true, the tag is enabled. 2. Overlong overflow configuration style. For details, see the API.", - "Extra-long line feed": "Extra-long line feed", - "Change default": "Change default", - "Current Select": "Current Select", - "Overlong single line, vertical scroll bar": "Overlong single line, vertical scroll bar", - "Maximum width of a tag in an ultra-long row.": "Maximum width of a tag in an ultra-long row.", - "This is an extra long option.": "This is an extra long option.", - "Option": "Option" - }, - "ObjectFilterDemo": { - "title": "Use object", - "description": "Using an array of objects, through filterKey Configuration Object Display Field.", - "Current Select": "Current Select", - "Option": "Option", - "Search": "Search" - }, - "LazyLoadVirtualScrollDemo": { - "title": "Virtual Scroll Or lazy loading", - "description": "Use virtualScroll Virtual scrolling is used in the case of a large amount of data. Run the enableLazyLoad command to load a large amount of data.", - "Virtual scrolling": "Virtual scrolling", - "Scroll to the bottom lazy loading data": "Scroll to the bottom lazy loading data", - "Scroll to the bottom to lazy load data using a custom loading template": "Scroll to the bottom to lazy load data using a custom loading template", - "Option": "Option", - "Asynchronous Options": "Asynchronous Options", - "Test": "Test" - }, - "LoadingDemo": { - "title": "Asynchronous loading: loading", - "description": "test.", - "Lazy loading: Change the options mode.": "Lazy loading: Change the options mode.", - "Lazy loading: The searchFn mode is used.": "Lazy loading: The searchFn mode is used.", - "Option": "Option" - }, - "UserLimitSelectedNumberDemo": { - "title": "User scenario: The number of selected users is limited.", - "description": "test.", - "maxselectnumber:2,disabled:1": "max select number:2, disabled:1", - "Option": "Option" - }, - "MultiKeepOrderDemo": { - "title": "Sets the selected order source array order or selection order.", - "description": "Pass keepMultipleOrder When multiple options are selected, the original array sequence is retained. The options are sorted by origin and sorted by user-select.", - "Current Selec": "Current Selec", - "Option": "Option" - }, - "UserSearchNLazyLoadDemo": { - "title": "User scenario: lazy loading of custom search", - "description": "test.", - "Search and lazy loading are used together.": "Search and lazy loading are used together.", - "Current Select": "Current Select", - "This is a longer option for testing.": "This is a longer option for testing.", - "Option": "Option", - "New Option": "New Option" - }, - "UserMailSearchDemo": { - "title": "User scenario: Combine customized search and template Email search", - "description": "test.", - "Search by name or email address": "Search by name or email address", - "Name:": "Name:", - "E-mail address:": "E-mail address:", - "Option": "Option" - }, - "ModelValueDemo": { - "title": "ngModel Value Processing", - "description": "test.", - "Current Select": "Current Select", - "Option": "Option" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "object-filter": "Use object", - "custom-search": "Custom Search", - "select-all": "Select All", - "select-template": "Customized template", - "labelization": "Labeling", - "disabled": "Disabled", - "allow-clear-value": "Allow clearing values", - "append-to-body": "Attach to the body.", - "lazy-load-virtual-scroll": "Virtual scrolling or lazy loading", - "async-loading": "Asynchronous loading: loading", - "custom-area": "Custom Area", - "custom-area-direction": "Customizing Area Orientation and Selecting", - "multi-keep-order": "Sets the selected order source array order or selection order.", - "user-limit-selected-number": "User scenario: The number of selected users is limited.", - "user-search-n-lazyload": "User scenario: lazy loading of custom search", - "user-mail-search": "User Scenario: Combination of Custom Search and Template - Email Search", - "model-value": "ngModel Value Processing" - } - }, - "cascader": { - "name": "Cascader", - "type": "Evolving", - "path": "cascader", - "description": "Cascading menu.", - "tmw": "
    1. When you want to select data from a set of associated data, such as province/city, company level, and transaction classification.
    2. When select data from a large data set, you can separate the data by multi-level classification.
    ", - "basicDemo": { - "hoverMode": "Hover expansion mode", - "select": "Please select", - "clickMode": "Click expansion mode", - "empty": "The data is empty.", - "title": "Basic Usage", - "disableMode": "Disabled mode" - }, - "lazyloadDemo": { - "loadChildren": "Click the load submenu.", - "title": "Click the load submenu.", - "select": "Please select" - }, - "multipleDemo": { - "title": "Multi-choice mode", - "multiple": "Multi-choice mode", - "select": "Please select" - }, - "parentSelectDemo": { - "title": "Parent can be selected.", - "description": "In this mode, you can click to select a non-leaf node. In multi-choice mode, you can click checkboxRelation to select the parent-child status association mode of the checkbox.", - "single": "Single choice", - "dependence": "Multiple selections (parent-child independent)", - "select": "Please select", - "relationDownward": "Multi-choice sub-item association", - "relationUpward": "Multi-choice association to parent item" - }, - "searchDemo": { - "title": "Search Mode", - "singleSearch": "Single-choice search", - "multipleSearch": "Multi-choice search", - "select": "Please select" - }, - "templateDemo": { - "title": "Template Type", - "templateMode": "Template Type", - "select": "Please select", - "custom": "Custom" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "multiple-cascader": "Multi-choice type", - "search-cascader": "Search Type", - "parent-cascader": "Parent Optional", - "template-cascader": "Template Type", - "lazyload-cascader": "Click to load." - } - }, - "status": { - "name": "Status", - "type": "General", - "path": "status", - "description": "Pass interaction results.", - "tmw": "Indicates the execution result of a task.", - "basicDemo": { - "title": "Basic Usage", - "Succeeded": "Succeeded", - "erroneous": "erroneous", - "warnings": "warnings", - "Initialize": "Initialize", - "Waiting": "Waiting", - "running": "running", - "Invalid": "Invalid" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage" - } - }, - "sticky": { - "name": "Sticky", - "type": "General", - "path": "sticky", - "description": "Sticky.", - "tmw": "When the user scrolls the screen, the content of an area is visible in the paragraph or the viewable area of the browser.", - "basicDemo": { - "title": "Basic Usage", - "Global Text": "Global text. Change the container to the container where the scroll bar is located. When displayed, you can always touch the top of the screen.", - "Global Button": "Global Button", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here.", - "Tips": "Tips", - "page-roll": "Sticky scrolls as you scroll.", - "para-roll": "When the paragraph rolls up, sticky will follow.", - "view": "View can adjust the top and bottom of the window. For example, if the top is covered by a fixed navigation block, set the value of top to the navigation height.", - "container": "The container command can be used to switch the containers that determine the scrolling status." - }, - "scrollTargetDemo": { - "title": "Replace Rolling Container", - "description": "You can change the scrolling container by setting scrollTarget.", - "Global Text": "Global text. Change the container to the container where the scroll bar is located. When displayed, you can always touch the top of the screen.", - "Global Button": "Global Button", - "base-info": "Basic Information", - "issue-list": "Requirement List", - "case-list": "Test Case List", - "quarlity-result": "Quality evaluation", - "The basic information is displayed.": "The basic information is displayed.", - "The requirement list is displayed.": "The requirement list is displayed.", - "The test case list is displayed.": "The test case list is displayed.", - "The quality assessment is displayed here.": "The quality assessment is displayed here.", - "Tips": "Tips", - "page-roll": "Sticky scrolls as you scroll.", - "para-roll": "When the paragraph rolls up, sticky will follow.", - "view": "View can adjust the top and bottom of the window. For example, if the top is covered by a fixed navigation block, set the value of top to the navigation height.", - "container": "The container command can be used to switch the containers that determine the scrolling status." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "scroll-target": "Replace Rolling Container" - } - }, - "tabs": { - "name": "Tabs", - "type": "Navigation", - "path": "tabs", - "description": "Tabs switch.", - "tmw": "When users want to collect and display large pieces of content in areas at the same level to keep the GUI neat.", - "basicDemo": { - "title": "Basic Usage", - "description": "test.", - "Here's what Tab1 says.": "Here's what Tab1 says.", - "This is Tab2.": "This is Tab2.", - "This is Tab3.": "This is Tab3." - }, - "withoutContentDemo": { - "title": "No Content", - "description": "test.", - "activeID": "activeID" - }, - "customDemo": { - "title": "Customizing a Template", - "description": "test.", - "Here's what Tab1 says.": "Here's what Tab1 says.", - "This is Tab2.": "This is Tab2.", - "This is Tab3.": "This is Tab3." - }, - "configDemo": { - "title": "Configuration Type and Arrangement", - "description": "test.", - "Here's what Tab1 says.": "Here's what Tab1 says.", - "This is Tab2.": "This is Tab2.", - "This is Tab3.": "This is Tab3.", - "Vertical arrangement:": "Vertical arrangement:", - "Option tabs:": "Option tabs:", - "Optiontabswithfixwidth100px:": "Optiontabswithfixwidth100px:" - }, - "beforeChangeDemo": { - "title": "Intercept Tab Switching", - "description": "Using beforeChange to intercept tab switchover.", - "Here's what Tab1 says.": "Here's what Tab1 says.", - "This is Tab2.": "This is Tab2.", - "This is Tab3.": "This is Tab3." - }, - "configurableTabsDemo": { - "title": "Customizing Tabs Display and Arrange", - "description": "The transfer component is introduced to implement customized tabs display.", - "activeID": "activeID" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "no-set-content": "No Content", - "custom-template": "Customizing a Template", - "configuration-type-and-arrangement": "Configuration Type and Arrangement", - "intercept-tab-switch": "Intercept Tab Switching", - "custom-tabs-display-and-arrangement": "Customizing Tabs Display and Arrange" - } - }, - "tags": { - "name": "Tags", - "type": "Data display", - "path": "tags", - "description": "Tags.", - "tmw": "When multiple tags need to be displayed,", - "customDemo": { - "title": "Single Tag", - "description": "Defines the label style by using the labelStyle attribute." - }, - "basicDemo": { - "title": "Tag Group", - "description": "The tag group can be a string array or an object array. In the object array, you can use displayProperty and titleProperty to set the label display value and title display value, and use labelStyle to set the label style." - }, - "anchorLinkValues": { - "single-tag": "Single Tag", - "tags-group": "Tag Group" - } - }, - "tags-input": { - "name": "TagsInput", - "type": "Data entry", - "path": "tags-input", - "description": "Enter multiple tags.", - "tmw": "When you need to enter multiple tags.", - "basicDemo": { - "title": "Basic Usage" - }, - "asyncDemo": { - "title": "Asynchronous data source" - }, - "ngmodelDemo": { - "title": "Two-way Binding" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "ng-model": "Two-way Binding", - "async-input": "Asynchronous data source" - } - }, - "time-axis": { - "name": "TimeAxis", - "type": "Data display", - "path": "time-axis", - "description": "Display timeline.", - "tmw": "When you want to show what shoud be done in what time point.", - "allStatesDemo": { - "timeLeft": "The time point is on the left.", - "timeBottom": "The time point is at the bottom.", - "title": "Basic Usage", - "description": "Use position to configure the time point position." - }, - "directionDemo": { - "title": "Setting direction parameters", - "description": "Use direction to configure the direction of the time line." - }, - "templateDemo": { - "description": "Description.", - "title": "Customizing Content Using a Template" - }, - "htmlContentDemo": { - "title": "Content Use HTML" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "direction": "Setting direction parameters", - "content-with-html": "Content Use HTML", - "content-with-template": "Customizing Content Using a Template" - } - }, - "toast": { - "name": "Toast", - "type": "Feedback", - "path": "toast", - "description": "Information notification.", - "tmw": "This is used to display a prompt information to users and will disappear after several seconds.", - "basicDemo": { - "title": "Basic Usage", - "description": "The icon is not displayed in common mode." - }, - "lifeDemo": { - "title": "Timeout interval", - "description": "If the timeout interval is set and no title is set, the title and close button are not displayed." - }, - "singleDemo": { - "title": "Each message uses a separate timeout interval", - "description": "When the timeout mode is set to single, each message uses its own lifetime as the timeout interval. If the timeout interval is not set, the system determines the timeout interval based on severity. If the timeout interval is not set, the default timeout interval is 5000 ms." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "life": "Timeout interval", - "single": "Each message uses a separate timeout interval" - } - }, - "tooltip": { - "name": "Tooltip", - "type": "Feedback", - "path": "tooltip", - "description": "Text notification.", - "tmw": "When users move the cursor to a text, they can see what should do next.", - "basicDemo": { - "title": "Basic Usage" - }, - "delayDemo": { - "title": "Delay Trigger", - "description": "This event is triggered only when the mouse pointer is moved in for more than [mouseEnterDelay] milliseconds. The default value is 150 ms to prevent flashing caused by unintentional strokes. The toolTip component is hidden only after [mouseLeaveDelay] milliseconds after the cursor is moved out. The default value is 100 milliseconds." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "delay-trigger": "Delay Trigger" - } - }, - "read-tip": { - "name": "ReadTip reading tips", - "type": "Feedback", - "path": "read-tip", - "description": "Reading notification component.", - "tmw": "When you need to prompt for specific content in the html document.", - "basicDemo": { - "title": "Basic Usage", - "description": "Set selector to select the element to be displayed in the readtip, and transfer title and content to set the content to be displayed." - }, - "multiDemo": { - "title": "Include Multiple Readtip", - "description": "Set the readtip display mode for different elements when multiple rules are transferred." - }, - "templateDemo": { - "title": "Display Content with Template", - "description": "You can specify the content to be displayed by importing template. When importing template, you do not need to specify title and content." - }, - "asyncDemo": { - "title": "Get Data Asynchronous" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "multi-usage": "Include Multiple Readtip", - "template-usage": "Display Content with Template", - "async-usage": "Get Data Asynchronous" - } - }, - "toggle": { - "name": "Toggle", - "type": "Data entry", - "path": "toggle", - "description": "Toggle.", - "tmw": "When there are two states need to be switched, for example, enabled/disabled.", - "basicDemo": { - "title": "Basic Usage", - "basic": "Basic Style", - "disable": "Disabled", - "small": "Bidirectional binding (small size)", - "middle": "Callback Event (Standard)", - "large": "Custom Style (Large Size)", - "sure": "ok", - "cancel": "cancels" - }, - "twoBindingDemo": { - "title": "Two-way Binding" - }, - "customDemo": { - "title": "Custom Style" - }, - "callbackDemo": { - "title": "Callback Event" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "two-binding": "Two-way Binding", - "callback": "Callback Event", - "custom": "Custom Style" - } - }, - "tree": { - "name": "Tree", - "type": "Data display", - "path": "tree", - "description": "A kind of structure.", - "tmw": "Folders, organizational structures, taxonomy, countries, regions, and so on, most of the structures in the world are tree-shaped. The tree can display the hierarchical relationship completely and provide interactive functions such as expanding, folding, and selecting.", - "basicDemo": { - "title": "Basic Usage", - "description": "The basic usage of tree component.", - "Parent node": "Parent node", - "unfold": "unfold", - "Leaf node": "Leaf node", - "No child node": "No child node", - "Dynamic loading": "Dynamic loading", - "folding": "folding" - }, - "checkControlDemo": { - "title": "Controlling the Parent-Child Check Relationship", - "description": "The usage of checkableRelation controls the performance of parent and child nodes during check.", - "Parent node": "Parent node", - "unfold": "unfold", - "Leaf node": "Leaf node", - "No child node": "No child node", - "Dynamic loading": "Dynamic loading", - "folding": "folding" - }, - "treeFactoryDemo": { - "title": "Common treeFactory functions", - "description": "" - }, - "checkableDemo": { - "title": "Checkable Tree", - "description": "Tree that can be checked.", - "Subnode": "Subnode", - "Parent node": "Parent node" - }, - "customLoadingDemo": { - "title": "Customizing a Loading Template", - "Leaf node": "Leaf node", - "No child node": "No child node", - "Dynamic loading": "Dynamic loading", - "Parent node": "Parent node", - "unfold": "unfold", - "folding": "folding" - }, - "customTitleKeyDemo": { - "title": "Custom Display Fields", - "description": "Set treeNodeTitleKey to customize the keywords displayed and searched in the tree.", - "Leaf node": "Leaf node", - "No child node": "No child node", - "Parent node": "Parent node", - "unfold": "unfold", - "folding": "folding" - }, - "customizeDemo": { - "title": "Custom Icon", - "description": "Customizing operation buttons and node icons.", - "Parent node": "Parent node", - "Subnode": "Subnode", - "Status": "Status" - }, - "draggableDemo": { - "title": "Dragable tree", - "description": "The dragglable attribute of operableTree is used to configure the drag function of nodes and allow external elements to be dragged into the tree.", - "Parent node": "Parent node", - "Subnode": "Subnode", - "external dragable element": "external dragable element" - }, - "mergeNodeDemo": { - "title": "Merging Nodes", - "description": "When a node has only one subnode, the node is merged.", - "Parent node": "Parent node", - "Leaf node": "Leaf node" - }, - "operateBtnDemo": { - "title": "Operation button", - "description": "External operation buttons and virtual floating buttons can be defined.", - "Parent node": "Parent node", - "Subnode": "Subnode" - }, - "searchFilterDemo": { - "title": "Search Filtering", - "description": "You can use the searchTree method in treeFactory to search for or filter nodes.", - "Parent node": "Parent node", - "Subnode": "Subnode" - }, - "virtualScrollDemo": { - "title": "Operable tree in the case of a large amount of data", - "description": "Use virtual scrolling to handle the loading problem of a large amount of data, and handle the problem that the operation of a large amount of data takes a long time and freezes.", - "Parent node": "Parent node", - "Try dynamic lazy loading": "Try dynamic lazy loading", - "Subnode": "Subnode", - "Parent node with 1000 child nodes": "Parent node with 1000 child nodes", - "Node loading": "Node loading", - "Subnode loading": "Subnode loading", - "I'm an extra data ID.": "I'm an extra data ID.", - "I'm an extra data name.": "I'm an extra data name.", - "New node": "New node", - "Add a node.": "Add a node.", - "Leaf node": "Leaf node", - "unfold": "unfold" - }, - "withoutAnimationDemo": { - "title": "Without Animation", - "description": "Indicates whether to display animations for the showAnimation attribute." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "merge-node": "Merging Nodes", - "custom-loading": "Customizing a Loading Template", - "custom-display-field": "Custom Display Fields", - "checkable-tree": "Checkable Tree", - "operation-button": "Operation button", - "search-filtering": "Search Filtering", - "custom-icon": "Custom Icon", - "drag-and-drop-tree": "Dragable tree", - "tree-factory": "Common treeFactory functions", - "check-control-tree": "Controlling the Parent-Child Check Relationship", - "virtual-scroll": "Operation tree of large data volume", - "without-animation": "Without Animation" - } - }, - "typography": { - "name": "Typography", - "type": "Evolving", - "path": "typography", - "description": "Text formatting.", - "tmw": "When you want to format the title, paragraph, help or anything else.", - "titleDemo": { - "title": "Title Usage", - "description": "Defining the title style through the d-title tag." - }, - "textDemo": { - "title": "Text Usage", - "description": "Defining a Text Style Through the d-text Tag." - }, - "customizeDemo": { - "title": "Customize", - "description": "Customizing the Display Template for Editing." - }, - "anchorLinkValues": { - "title-usage": "Title Usage", - "text-usage": "Text Usage", - "custom-usage": "Customize" - } - }, - "upload": { - "name": "Upload", - "type": "Data entry", - "path": "upload", - "description": "File upload.", - "tmw": "When you want to upload files to a backend server.", - "basicDemo": { - "title": "Basic Usage", - "description": "Single file upload, drag file upload, ngModel and disabled.", - "singleText": "Single file", - "clickToUpload": "Click Upload.", - "dragable": "Dragging a single file to upload", - "dragToUpload": "Drag the file to upload.", - "auto": "Automatic upload", - "disabled": "Upload forbidden" - }, - "multiDemo": { - "title": "Upload Multiple Files", - "description": "Multiple files upload, drag file upload, customize and disabled.", - "multiText": "Uploading multiple files", - "dragable": "Multiple files can be dragged and uploaded.", - "multiList": "Displaying multiple files in a list", - "disabled": "Multi-file upload is prohibited." - }, - "autoDemo": { - "title": "Automatic Upload", - "description": "Set automatic upload through autoUpload." - }, - "customizeDemo": { - "title": "Customize", - "description": "Click to customize the upload button. Use preloadFilesRef to set selectedFilesList Template, and use uploadedFilesRef to Set the template of the uploadedFilesList." - }, - "dynamicDemo": { - "title": "Dynamic Upload Parameters", - "description": "Users can use beforeUpload to dynamically modify upload parameters.", - "text": "Dynamically Modifying Upload Parameters Before Uploading" - }, - "areaDemo": { - "title": "Customize Area to Upload", - "description": "Users can use the dUpload command to upload files in any area." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "multi-files": "Upload Multiple Files", - "auto-upload": "Automatic Upload", - "custom": "Customize", - "dynamic-upload-options": "Dynamic Upload Parameters", - "customize-area-upload": "Customize Area to Upload" - } - }, - "input-number": { - "name": "InputNumber", - "type": "Data entry", - "path": "input-number", - "description": "Enter a number.", - "tmw": "Used to obtain the standard value.", - "basicDemo": { - "title": "Basic Usage", - "description": "Transfer the value of size. The value can be customized." - }, - "disabledDemo": { - "title": "Disabled", - "description": "When disabled is set to true, user input is not allowed." - }, - "emptyDemo": { - "title": "Allow Null", - "description": "When allowEmpty is set to true, the value of the input box can be empty. If the value is empty, null is returned. The input data can be undefined or null." - }, - "placeholderAndMaxLengthDemo": { - "title": "Set Placeholder and Maxlength", - "description": "The placeholder prompt can be transferred or maxLength can be used to limit the maximum input length." - }, - "regDemo": { - "title": "Using Regular Expression", - "description": "Regular or regular character strings are allowed to be input. The input regular character string is matched first. If no regular character string is input, the input regular character string is not restricted." - }, - "decimalLimitDemo": { - "title": "Avoid Decimal", - "Limit Decimal": "Limit Decimal" - }, - "anchorLinkValues": { - "number-basic": "Basic Usage", - "number-disabled": "Disabled", - "number-empty": "Allow Null", - "number-placeholder-maxlength": "Set Placeholder and Maxlength", - "number-reg": "Using Regular Expression", - "decimal-limit": "Avoid Decimal" - } - }, - "tree-select": { - "name": "TreeSelect", - "type": "Data entry", - "path": "tree-select", - "description": "Tree-shaped selection box.", - "tmw": "Folders, organizational structures, taxonomy, countries, regions, and so on, most of the structures of everything in the world are tree-shaped. The tree control can display the hierarchical relationship completely and provide interactive functions such as expanding, folding, and selecting.", - "basicDemo": { - "title": "Basic Usage", - "description": "test.", - "Standard: Single Select": "Standard: Single Select", - "Standard: Multiple Select": "Standard: Multiple Select", - "Custom Width: Single Select": "Custom Width: Single Select", - "Disabled: Single Select": "Disabled: Single Select" - }, - "labelizationDemo": { - "title": "Tag-based configuration", - "description": "test.", - "Standard: Single Select": "Standard: Single Select", - "Standard: Multiple Select": "Standard: Multiple Select", - "AllowClear:SingleSelect(allowUnselectparametermustbetrueandenablelabelizationDemomustbefalse, whichisthedefaultvalue)": "AllowClear:SingleSelect(allowUnselectparametermustbetrueandenablelabelizationDemomustbefalse, whichisthedefaultvalue)", - "Standard: Multiple Select(Disabled)": "Standard: Multiple Select(Disabled)" - }, - "leafOnlyDemo": { - "title": "Only leaf nodes can be selected.", - "description": "test.", - "Leaf Only: Single Select": "Leaf Only: Single Select", - "Leaf Only: Multiple Select": "Leaf Only: Multiple Select" - }, - "hooksDemo": { - "title": "Hook called upon completion of initialization", - "description": "test.", - "Open on init: Single Select": "Open on init: Single Select" - }, - "searchableDemo": { - "title": "Easy search tree", - "description": "test.", - "Standard: Single Select": "Standard: Single Select", - "Standard: Multiple Select": "Standard: Multiple Select" - }, - "appendToDemo": { - "title": "Append To Element Capability", - "description": "test.", - "Standard: Single Select Append To Body": "Standard: Single Select Append To Body", - "Standard: Multiple Select Append To Body": "Standard: Multiple Select Append To Body", - "Custom Width: Single Select Append To Body": "Custom Width: Single Select Append To Body", - "click me!": "click me!" - }, - "customIconDemo": { - "title": "Customizing icons", - "description": "test.", - "Standard: iconTemplatePosition": "Standard: iconTemplatePosition", - "Standard: iconTemplateInput": "Standard: iconTemplateInput" - }, - "customTemplateDemo": { - "title": "Custom Area", - "description": "Use customViewTemplate Defining a Custom Area." - }, - "keysDemo": { - "title": "Custom key", - "description": "test.", - "Standard: treeNodeIdKey": "Standard: treeNodeIdKey", - "Standard: treeNodeChildrenKey": "Standard: treeNodeChildrenKey", - "Standard: treeNodeTitleKey": "Standard: treeNodeTitleKey" - }, - "iconParentDemo": { - "title": "Customizing the node expansion and closing icon", - "description": "test.", - "Standard: iconParent": "Standard: iconParent" - }, - "virtualScrollDemo": { - "title": "Virtual scroll" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "labelization": "Tag-based configuration", - "leaf-only": "Only leaf nodes can be selected.", - "init-hooks": "Hook called upon completion of initialization", - "simple-search": "Easy search tree", - "append-to-element": "Append To Element Capability", - "custom-icon": "Customizing icons", - "keys": "Custom key", - "custom-template": "Custom Area", - "icon-parent": "Expand and close the icon.", - "virtual-scroll": "Virtual scroll" - } - }, - "slider": { - "name": "Slider", - "type": "Data entry", - "path": "slider", - "description": "Slider.", - "tmw": "Used when you need to select a value from a specific range.", - "basicDemo": { - "title": "Basic Usage", - "ngModel": "Bidirectional binding", - "stepLimit": "Limit step" - }, - "disabledDemo": { - "title": "Input forbidden state", - "description": "When disabled is set to true, user input is not allowed." - }, - "customDemo": { - "title": "Customized popover content displayed", - "description": "Use the tipsRenderer parameter to transfer the function to customize the content displayed in the POPU." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "slider-disabled": "Input forbidden state", - "slider-custom": "Customized popover content displayed" - } - }, - "splitter": { - "name": "Splitter", - "type": "layouts", - "path": "splitter", - "description": "Split page.", - "tmw": "When you want to dynamically adjust the size of different page layout areas.", - "basicDemo": { - "title": "Basic Usage", - "leftPane": "Left panel", - "leftPaneContent": "Content area on the left. The width is 30% and the minimum width is 20%.", - "rightPane": "Right panel", - "rightPaneContent": "Content area on the right" - }, - "verticalDemo": { - "title": "Vertical Layout Usage", - "topPane": "Upper panel", - "topPaneContent": "Height 200px", - "midPane": "Middle panel", - "midPaneContent": "Height adaptation", - "bottomPane": "lower plate", - "bottomPaneContent": "Height: 100 px, non-adjustable" - }, - "combineDemo": { - "title": "Combination Layout Usage", - "leftPane": "Left panel", - "leftPaneContent": "Content area on the left. The width is 30% and the minimum width is 20%.", - "topPane": "Top panel", - "topPaneContent": "Height 50%", - "bottomPane": "Bottom panel", - "bottomPaneContent": "Height adaptation", - "bottomPane2": "Bottom panel", - "bottomPaneContent2": "Height adaptation" - }, - "directionDemo": { - "title": "Specifies the folding direction", - "leftPane": "Left panel", - "leftPaneContent": "Content area on the left. The width is 30% and the minimum width is 20%.", - "midPane": "Middle panel", - "midPaneContent": "Middle content area, specifying the folding direction to fold forward", - "rightPane": "Right panel", - "rightPaneContent": "Content area on the right" - }, - "shrinkDemo": { - "title": "Collapse and collapse menu", - "rightPane": "Right panel", - "rightPaneContent": "Content area on the right", - "content1": "Content 1", - "childContent1": "Subcontent 1", - "childContent2": "Subcontent 2", - "childContent3": "Subcontent 3", - "content2": "Content 2", - "content3": "Content 3", - "content4": "Content 4", - "content5": "Content 5" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "vertical-layout": "Vertical Layout Usage", - "combine-layout": "Combination Layout Usage", - "certain-unfold-direction": "Specifies the folding direction.", - "shrink-show-menu": "Collapse and collapse menu" - } - }, - "layout": { - "name": "Layout", - "type": "layout", - "path": "layout", - "description": "Page Layout.", - "tmw": "When user want to use some existed layout.", - "basicDemo": { - "title": "Basic Usage" - }, - "appDemo1": { - "title": "Application Scenario 1", - "description": "Common top, middle, and bottom layout." - }, - "appDemo2": { - "title": "Application Scenario 2", - "description": "Common top, middle, and bottom layouts and sidebar layouts." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "application-scenario1": "Application Scenario 1", - "application-scenario2": "Application Scenario 2" - } - }, - "gantt": { - "name": "Gantt", - "type": "Evolving", - "path": "gantt", - "description": "Gantt.", - "tmw": "When user want to use a bar-shaped chart to display the internal relationship of project, progress, and other time-related system progress over time.", - "basicDemo": { - "title": "Basic Usage", - "description1": "The d-gantt-scale container functions as the location parent element of the time axis. The position or table, td, th, and body elements must be set.", - "description2": "The widths of the d-gantt-scale and d-gantt-bar containers must be calculated based on the start time and end time using the method provided by GanttService. After initialization, the ganttScaleConfigChange dynamic settings must be subscribed.", - "description3": "The time bar move and resize events change the start and end time of the time bar and the start and end time of the time axis. The time bar resize, move, and ganttScaleConfigChange events are subscribed to to to record the change.", - "description4": "Respond to the move and resize events of the time bar to adjust the scrolling of the outermost container for better experience." - }, - "withDataDemo": { - "title": "Combined With Datatable" - }, - "anchorLinkValues": { - "gantt-basic": "Basic Usage", - "gantt-in-datatable": "Combined With Datatable" - } - }, - "text-input": { - "name": "Text-input", - "type": "Data entry", - "path": "text-input", - "description": "Text input box.", - "tmw": "When you want to manually enter text.", - "basicDemo": { - "title": "Basic Usage", - "placeholder": "Please enter the content." - }, - "passwordVisibleDemo": { - "title": "Password Input" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "password-input": "Password Input" - } - }, - "textarea": { - "name": "Textarea", - "type": "Data entry", - "path": "textarea", - "description": "A text area.", - "tmw": "It is used when a large number of text need to be entered.", - "basicDemo": { - "title": "Basic Usage", - "placeholder": "Please enter the content." - }, - "resizeDemo": { - "title": "Resizable", - "placeholder": "Please enter the content." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "resize": "Resizable" - } - }, - "steps-guide": { - "name": "StepsGuide", - "type": "Navigation", - "path": "steps-guide", - "description": "Guide user to understand logic.", - "tmw": "When there are some new features and is required to tell user how to use it.", - "basicDemo": { - "title": "Basic Usage", - "description": "Sets the sequence of displaying a group of operation instructions.", - "Current Step": "Current Step", - "Operation Output": "Operation Output" - }, - "customDemo": { - "title": "Custom", - "description": "Customizing the Position and Elements of the Operation Guide." - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "custom": "Custom" - } - }, - "polyfill": { - "name": "Polyfills", - "type": "Extended service", - "path": "polyfill", - "description": "Polyfill.", - "tmw": "To solve the method that is not supported by the browser of an earlier version.", - "basicDemo": { - "title": "Usage", - "description": "Currently, there are few implementation methods and are mainly used by the rich text component. Therefore, the putty script file is stored in the rich text module. When using the devcloud project or the project created by the Angular CLI, you can insert the following information into src/polyfills.ts: import' ng-devui/add-ons/editorx/polyfill '; The putty script is only a piece of JS code that is independently executed. You can also insert a static resource into the page for use.", - "name": "Polyfills", - "license": "License", - "size": "Size", - "browser": "Browser", - "des": "Description", - "remove": "Removes an object from the DOM tree to which it belongs", - "matches": "Check whether the specified selector string is matched. Browsers of earlier versions implement the MatchesSelector method with their own prefix. For example, msMatchesSelector", - "closest": "The ancestor element that matches a particular selector and is closest to the current element(or the current element itself)", - "event": "Events that occur in the DOM", - "forEach": "Method of sequentially traversing the collection of nodes" - }, - "anchorLinkValues": { - "basic-usage": "Usage" - } - }, - "time-picker": { - "name": "TimePicker", - "type": "Evolving", - "path": "time-picker", - "description": "Enter or select a time.", - "tmw": "If you need to enter a time, click the standard input box and select a time from the displayed panel.", - "basicDemo": { - "basic": "Basic Usage", - "defaultValue": "Sets the initial value. This function is enabled by default.", - "setDisable": "Disabled", - "title": "Basic Usage" - }, - "customDemo": { - "template": "Importing a template", - "chooseNow": "Select Now", - "chooseTime": "Select 22 points", - "title": "Importing a template" - }, - "formatDemo": { - "setting": "Set the format, maximum value, and minimum value.", - "title": "Format, Max, and Min" - }, - "anchorLinkValues": { - "basic-usage": "Basic Usage", - "format": "formatting", - "custom": "Importing a template" - } - }, - "relative-time": { - "name": "RelativeTime", - "type": "Data display", - "path": "relative-time", - "description": "Show relative time.", - "tmw": "When you want to display the relative time based on the current time.", - "basicDemo": { - "beforeTrans": "Before Conversion", - "afterTrans": "After Conversion", - "title": "Conversion Example", - "description": "Introduce the RelativeTimeModule and use the dRelativeTime pipe to convert the date." - }, - "customDemo": { - "title": "customizing comparison time demo", - "description": "Do not compare the current time with the current time. Customize the comparison time. For example, compare the comparison time with 2015-05-20 12:00:00." - } - } - } -} \ No newline at end of file diff --git a/docs/i18n/zh-cn.json b/docs/i18n/zh-cn.json deleted file mode 100644 index 6c613cca0692d2090280ef41b59bfda21e381f97..0000000000000000000000000000000000000000 --- a/docs/i18n/zh-cn.json +++ /dev/null @@ -1,3275 +0,0 @@ -{ - "mainNav": { - "design": "设计体系", - "components": "组件", - "icons": "图标库", - "versions": "版本历程" - }, - "themePicker": { - "theme": "主题", - "color": "主题颜色", - "mode": "主题模式", - "light": "浅色模式", - "dark": "深色模式", - "follow": "跟随系统", - "largeSize": "大字号模式", - "default":"默认主题", - "extend":"扩展主题", - "infinity": "无限", - "sweet": "蜜糖", - "deep": "深邃夜空", - "provence": "普罗旺斯" - }, - "public": { - "start": "快速开始", - "themeDoc": "主题化使用指南", - "plus": "DevUI Plus组件库", - "whenToUse": "何时使用", - "goTo": "快速前往" - }, - "codebox": { - "showCode": "展开代码", - "hideCode": "收起代码", - "copyCode": "复制代码", - "success": "复制成功" - }, - "components": { - "accordion": { - "name": "Accordion 手风琴", - "type": "导航", - "path": "accordion", - "description": "为页面提供导航的组件。", - "tmw": "需要通过分组组织菜单的时候使用。", - "basicDemo": { - "title": "基本用法", - "description": "传入菜单,监听含子项的可展开菜单的开合事件(menuToggle)或可点击菜单的点击事件(itemClick)。可展开菜单默认展开使用属性open,可点击菜单默认激活使用属性active,禁用项使用disabled。通过restrictOneOpen设置是否限制只能展开一个一级菜单。", - "Only one level-1 menu can be expanded.": "限制只能展开一个一级菜单", - "Embedded menu (no shadow)": "内嵌菜单形式(无阴影)", - "Content 1": "内容一", - "Subcontent 1": "子内容1", - "Subcontent 2": "子内容2", - "Subcontent 3": "子内容3", - "Content 2 (overlong, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long": "内容二(超长长长长长长长长长长长长长长内容测试)", - "Subcontent 1 (Extremely long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long, long,": "子内容1(超长长长长长长长长长长长长长长内容测试", - "Content 3 (expanded by default)": "内容三(默认展开)", - "Subcontent 1 (disabled)": "子内容1(禁用)", - "Subcontent 2 (activated by default)": "子内容2(默认激活)", - "Content 4 (no sub-item)": "内容四(没有子项)", - "Content 5 (Disabled)": "内容五(禁用)", - "Content 6 (dynamic loading)": "内容六(动态加载)" - }, - "changeKeyDemo": { - "title": "改变键值", - "description": "通过titleKey,childrenKey,disabledKey,activeKey等等改变数组键值,适配不同的接口类型定义。", - "Content 1": "内容一", - "Content 2 (expanded)": "内容二(展开)", - "Subcontent 1 (disabled)": "子内容1(禁用)", - "Subcontent 2 (selected)": "子内容2(选中)", - "Subcontent 3": "子内容3" - }, - "innerListTemplateDemo": { - "title": "使用列表模板", - "description": "内部列表通过制定innerListTemplate使用模板。", - "test": "内容二的内容" - }, - "linkDemo": { - "title": "使用内置路由和链接类型", - "description": "通过设置linkType切换不同的内置路由和链接类型:默认类型'';路由类型'routerLink';外链类型:'hrefLink';基于数据判断路由或链接类型:'dependOnLinkTypeKey'。", - "Route Link (Recommended)": "路由链接(推荐使用)", - "Native hyperlink (used in cross-site scenarios)": "原生超链接(涉及跨站场景使用)", - "Hybrid link (used in some cross-site scenarios)": "混合链接(部分涉及跨站场景使用)", - "Basic components": "基础组件", - "accordion": "手风琴", - "Anchor": "锚点", - "Button": "按钮", - "Advanced Component": "高级组件", - "Table (Disabled)": "表格(禁用)", - "Dragging (Parameter Example)": "拖拽(参数示例)", - "Others": "其他", - "Icon Library": "图标库", - "Home page": "首页", - "dragging": "拖拽", - "Home page (new window)": "首页(新开窗口)", - "Home page (external link and open this window)": "首页(外链且本窗口打开)" - }, - "multiLevelDemo": { - "title": "复合层级和自动展", - "description": "支持多层级和不限制嵌套层级。可以独立使用autoOpenActiveMenu使得激活的菜单的父层级自动展开。", - "Automatically expand activated menus": "自动展开激活的菜单", - "Content 1 (menu only)": "内容一(仅菜单)", - "Content 2 (menu and content)": "内容二(菜单和内容)", - "Subcontent 1": "子子内容1", - "Subcontent 2": "子子内容2", - "Subcontent 3": "子子内容3", - "Content 3 (menu and content)": "内容三(菜单和内容)", - "Subcontent 1 (with sublists)": "子内容1(有子列表)", - "Subcontent 2 (with sublists)": "子子内容2(有子列表)", - "Sub-sub-content 1": "子子子内容1", - "Sub-sub-content 2": "子子子内容2", - "Sub-content 3": "子子子内容3", - "Content 4 (no content in the sublist)": "内容四(子列表没有内容)" - }, - "templateDemo": { - "title": "使用模板", - "description": "可展开菜单和可点击菜单分别使用模板。可展开菜单指定menuItemTemplate,可点击菜单指定itemTemplate。没有数据模板指定noContentTemplate,并可以通过showNoContent控制无数据的时候不展开。 加载中模板指定loadingTemplate,通过item的loadingKey对应的属性值控制是否显示加载中。", - "Reset": "重置", - "Number of clicks:": "点击次数:", - "Not open yet. Please wait...": "尚未开放,敬请期待...", - "It's loading hard.": "正在用力地加载中.", - "Content 1": "内容一", - "Content 2": "内容二", - "Content 3": "内容三", - "Content 4 (customized template without data)": "内容四(自定义无数据模板)", - "Content 5 (Customizing the Template Being Loaded)": "内容五(自定义加载中模板)", - "The expandable menu node must have a non-undefined child.": "可展开菜单节点必须有children非undefined", - "Subcontent 1": "子内容1", - "Subcontent 2": "子内容2", - "Subcontent 3": "子内容3", - "Subcontent 4": "子内容4", - "Subcontent 5": "子内容5", - "Subcontent 6": "子内容6", - "Subcontent 7": "子内容7" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "use-built-in-routing-and-link-types": "内置路由和链接类型", - "using-templates": "使用模板", - "compound-level-and-auto-expand": "复合层级和自动展开", - "change-values": "改变键值" - } - }, - "alert": { - "name": "Alert 警告", - "type": "反馈", - "path": "alert", - "description": "显示警告信息,需要用户关注的信息的组件。", - "tmw": "当页面需要向用户发出警告信息时。", - "basicDemo": { - "title": "基本用法", - "description": "共有四种样式:success、danger、warning、info。" - }, - "closableDemo": { - "title": "可关闭的提示", - "description": "显示关闭按钮,点击可关闭提示。" - }, - "withoutIconDemo": { - "title": "不使用默认图标", - "description": "不使用默认的类型图标。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "tips-to-close": "可关闭的提示", - "without-icon": "不使用默认图标" - } - }, - "anchor": { - "name": "Anchor 锚点", - "type": "导航", - "path": "anchor", - "description": "跳转到页面指定位置的组件。", - "tmw": "需要在页面的各个部分之间实现快速跳转时。", - "basicDemo": { - "title": "基本用法", - "description": "跟随滚动效果请参考sticky。", - "attention": "组件仅实现了锚点的功能,可搭配sticky使用,跟随滚动效果请参考sticky", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。" - }, - "asyncDemo": { - "title": "异步加载", - "description": "支持异步加载, 可以先加载菜单或者先加载内容,点击按钮切换加载。", - "Click to switch to asynchronous loading content.": "点击切换异步加载内容", - "Asynchronous loading menu": "异步加载菜单", - "Asynchronous loading of content": "异步加载内容", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。" - }, - "hashDemo": { - "title": "支持url锚点", - "description": "支持url的锚点哈希链接,支持更新哈希。", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。", - "Activating an anchor": "激活anchor的时候刷新地址哈希值", - "Refresh Hash Address": "刷新地址哈希值生效", - "Click the anchor link in the Case List area.": "点击“用例列表”锚点链接", - "Click the Quality Evaluation anchor.": "点击“质量评估”锚点内部", - "Initialize scrolling to the corresponding anchor point.": "仅初始化的时候滚动到对应锚点", - "Scroll to the corresponding anchor to take effect": "滚动到对应锚点生效", - "Jump to Requirements List via Hash and initialize": "通过哈希跳到“需求列表”并重新初始化", - "Jump to the Requirement List via Hash": "通过哈希跳到“需求列表”" - }, - "scrollTargetDemo": { - "title": "更换滚动容器", - "description": "通过scrollTarget更换滚动容器。", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "asynchronous-loading": "异步加载", - "scroll-target": "更换滚动容器", - "support-hash": "支持url锚点" - } - }, - "auto-complete": { - "name": "AutoComplete 自动补全", - "type": "数据录入", - "path": "auto-complete", - "description": "联想用户可能需要的输入结果。", - "tmw": "当需要根据用户输入的部分字符推断出他可能想要输入的内容时。", - "basicDemo": { - "title": "基础用法", - "description": "通过 source 设置自动完成的数据源。" - }, - "objectDemo": { - "title": "自定义数据匹配方法", - "description": "通过 searchFn 自定义数据的匹配方法和返回的数据格式。" - }, - "customDemo": { - "title": "自定义模板展示", - "description": "通过 itemTemplate、noResultItemTemplate 自定义下拉框和无匹配提示。" - }, - "disabledDemo": { - "title": "设置禁用", - "description": "通过 disabled 设置输入框禁用,通过 disabledKey 禁用下拉选项。", - "Search Results": "搜索结果" - }, - "latestDemo": { - "title": "最近输入", - "description": "通过 latestSource 设置最近输入。" - }, - "lazyLoadDemo": { - "title": "懒加载", - "description": "enableLazyLoad 开启懒加载。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "auto-object": "自定义数据匹配方法", - "auto-custom": "自定义模板展示", - "auto-disable": "设置禁用", - "auto-latest": "最近输入", - "auto-lazy-load": "启用懒加载" - } - }, - "editormd": { - "name": "Markdown MD编辑器", - "type": "数据录入", - "path": "editormd", - "description": "Markdown编辑器。", - "tmw": "当需进行Markdown编辑时。", - "defaultDemo": { - "title": "基本使用", - "description": "展示editor-md的默认基本功能,支持双向绑定。", - "Current value of content.": "content当前值:", - "Switching Modes": "切换mode", - "The input cannot be empty.": "你的输入不能为空", - "Initialization Title": "初始化标题,不使用双向绑定进行传值", - "Bidirectional binding": "双向绑定" - }, - "toolbarDemo": { - "title": "自定义工具栏", - "description": "改变工具栏顺序、添加自定义按钮,自定义按钮支持多种传入方式(本例中添加了【引用】【预览开关】按钮)。", - "Open Preview": "打开预览", - "Turn off preview": "关闭预览", - "Customizing Button Sequence and Display": "自定义按钮顺序与显示、引用按钮", - "Initialize when init": "需要在init时进行初始化,可获取到template引用", - "Default toolbarConfig of the editor": "编辑器默认toolbarConfig为:", - "quoting": "引用" - }, - "xssDemo": { - "title": "自定义xss过滤规则", - "description": "自定义配置指定标签过滤规则。", - "This is the input content.": "这是输入的content", - "Defines a custom attribute.": "这里定义了一个自定义属性,xss中自定义白名单添加了此属性,控制台查看元素将看到此属性被渲染", - "Another custom property is defined": "这里定义了另一个自定义属性,xss白名单中没有添加此属性,控制台查看元素将看到此属性没有被渲染", - "Tag name.": "对应tag的名称", - "Current tag trustlist attribute array": "当前tag白名单属性数组" - }, - "renderDemo": { - "title": "单独渲染md文本", - "description": "单独渲染md文本。CustomParse添加的内容,将不会进入到XSS过滤中。", - "This is the input content.": "这是输入的content", - "Defines a custom attribute.": "这里定义了一个自定义属性,xss中自定义白名单添加了此属性,控制台查看元素将看到此属性被渲染", - "Another custom property": "这里定义了另一个自定义属性,xss白名单中没有添加此属性,控制台查看元素将看到此属性没有被渲染", - "relative link": "相对链接", - "Tag name.": "对应tag的名称", - "Current tag trustlist attribute array": "当前tag白名单属性数组", - "Added Text": "这里是自定义parse方法添加的文本,", - "The content is not filtered by the trustlist.": "将会在markdown被解析后执行,这里内容不会被白名单过滤" - }, - "parseDemo": { - "title": "自定义parse方法", - "description": "自定义parse方法处理最终输出的html。", - "Initialization Content": "初始化内容", - "Added Text": "我是自定义parse方法中添加的内容,无论如何我都会在最后" - }, - "imageDemo": { - "title": "配置图片文件上传", - "description": "配置图片文件上传。设置imageUploadToServer后,编辑器对粘贴操作也将进行监听,若有图片也将触发imageUpload事件。", - "Select an image to upload.": "选择一张图片上传至服务器", - "After imageUploadToServer is set": "设置imageUploadToServer后,编辑器对粘贴操作也将进行监听,若有图片也将触发imageUpload事件", - "Open the file upload entry.": "打开文件上传入口", - "Selecting a picture type": "请选择bmp/jpg/jpeg/png/gif/tiff类型图片进行上传", - "Limit the image size.": "请选择小于1M的图片进行上传", - "Uploading a file": "上传文件", - "Failed to upload the image.": "图片上传失败" - }, - "hintDemo": { - "title": "配置快速提示", - "description": "可用于支持@选择用户等场景。", - "Associated Member": "你可以输入@关联成员,输入#关联一个订单号……", - "Set Search": "设置搜索debounceTime", - "User": "用户", - "Order No.": "订单号" - }, - "markedDemo": { - "title": "自定义渲染", - "description": "自定义从md到html的渲染规则。", - "Level-1 Title": "一级标题", - "Level-2 Title": "二级标题", - "Level-3 Title": "三级标题", - "Level-4 Title": "四级标题", - "Level-5 Title": "五级标题", - "Level 6 Title": "六级标题" - }, - "enormousTextDemo": { - "title": "大数据量场景处理", - "description": "手动获取内容,而非通过事件实时回传,当前可保证编辑无卡顿,渲染会进行延迟渲染(实验功能)。", - "Generate 10,000 lines of data.": "生成1W行数据", - "Output the content in the editing area.": "控制台输出编辑区内容", - "Initialization Title": "初始化标题,不使用双向绑定进行传值", - "Incoming Initialization": "可传入初始化content的值", - "The change event is closed.": "关闭了change事件,编辑区内容改变,事件将不会被触发", - "For details, see codemirror.": "更多editorRef方法,可参考codemirror官方文档", - "Data": "这是第${i}行数据" - }, - "anchorLinkValues": { - "basic-usage": "基本使用", - "custom-toolbar": "自定义工具栏", - "custom-xss": "自定义xss过滤规则", - "custom-render": "自定义渲染", - "custom-parse": "自定义parse方法", - "img-upload": "配置图片文件上传", - "quick-suggestion": "快速提示(@用户等)", - "single-render-md": "单独渲染md文本", - "big-data-process": "大数据量场景处理" - } - }, - "avatar": { - "name": "Avatar 头像", - "type": "数据展示", - "path": "avatar", - "description": "显示用户头像的组件。", - "tmw": "当需要显示用户头像时。", - "basicDemo": { - "title": "头像显示的基本规则", - "description": "头像组件传入'name'属性时,会根据一定的规则显示头像的字段,具体规则参见API。", - "cnStart": "中文开头的情况,取最后两个字符:", - "enStart": "英文开头的情况,取前面两个字符:", - "multi": "多个英文名的情况,取前两个英文名首字母:", - "others": "非中英文开头的情况,取前两个字符:" - }, - "configDemo": { - "title": "头像的基础配置", - "description": "头像组件可设置宽度,高度,是否为圆形头像,同时可自定义头像的显示字段,传入自定义图片等。", - "smaller": "设置宽度,高度小于30px时,只显示一个字符:", - "custome": "传入自定义头像显示字段customText:", - "img": "传入imgSrc:" - }, - "specialDemo": { - "title": "头像的特殊显示", - "description": "头像组件会对一些特殊情况进行处理,具体表现为用户不存在或展示默认头像,详细规则参见API。", - "notExist": "未传入name,customText,imgSrc,视为使用该头像的用户不存在:", - "beNull": "传入name,customText,imgSrc的值为空,视为使用该头像的用户无昵称,使用默认头像:" - }, - "anchorLinkValues": { - "basic-rules": "头像显示的基本规则", - "basic-configuration": "头像的基础配置", - "special-display": "头像的特殊显示" - } - }, - "ImagePreview": { - "name": "ImagePreview 图片预览", - "type": "数据展示", - "path": "ImagePreview", - "description": "预览一张或多张图片的组件。", - "tmw": "需要根据用户传入进行图片预览展示或对容器内图片进行预览时。", - "basicDemo": { - "title": "基本用法", - "description": "使用image-preview指令,对容器内图片进行预览。" - }, - "customDemo": { - "title": "自定义开启预览窗口", - "description": "传入subject,触发next时打开预览。", - "previewImage": "预览图片" - }, - "zIndexDemo": { - "title": "设置zIndex", - "description1": "通过设置zIndex控制弹出效果的层级,设置backDropZIndex控制弹出层背景的层级。", - "description2": "可以看到当设置zIndex小于backDropZIndex时,imagePreview会显示在背景下方。", - "description3": "可以通过Esc关闭imagePreview。", - "previewImage": "预览图片" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "custom-usage": "自定义开启预览窗口", - "z-index-usage": "设置zIndex" - } - }, - "breadcrumb": { - "name": "Breadcrumb 面包屑", - "type": "导航", - "path": "breadcrumb", - "description": "显示当前页面层级的组件。", - "tmw": "
    1. 用户需要了解当前出于什么层级时;
    2. 用户需要快速返回之前的层级时;
    3. 用户需要导航至与指定层级相同的任意页面时。
    ", - "basicDemo": { - "title": "基础面包屑", - "itemText": "通过d-breadcrumb-item定义显示内容", - "sourceText": "通过传入source显示默认面包屑", - "content": "面包屑" - }, - "menuDemo": { - "title": "可下拉的面包屑" - }, - "customDemo": { - "title": "自定义下拉列表和分隔符的面包屑", - "breadText": "面包屑", - "anchorText": "锚点", - "btnText": "按钮" - }, - "sourceDemo": { - "title": "传入source" - }, - "anchorLinkValues": { - "basic-breadcrumbs": "基础面包屑", - "source-config-breadcrumbs": "传入source", - "drop-down-breadcrumbs": "可下拉的面包屑", - "self-defined-breadcrumbs": "自定义下拉列表和分隔符的面包屑" - } - }, - "back-top": { - "name": "BackTop 回到顶部", - "type": "导航", - "path": "back-top", - "description": "返回页面顶部的操作按钮。", - "tmw": "当页面内容区域比较长时;当用户需要频繁返回顶部查看相关内容时。", - "basicDemo": { - "title": "基本用法", - "description": "回到顶部按钮的默认样式,距离底部50px,右侧30px。", - "default": "默认样式", - "text": "开启后,向下滑动滚动条即可见回到顶部默认按钮:" - }, - "customizeDemo": { - "title": "自定义", - "description": "回到顶部组件可自定义按钮样式,限制宽高:40px * 40px。同时可通过visibleHeight设置按钮可见的滚动高度。", - "customizeStyle": "自定义回到顶部按钮的样式,限制宽高:40px * 40px。", - "text": "开启开关,向下滑动滚动条展示按钮:", - "scrollHeight": "滚动高度达到visibleHeight所设值后展示回到顶部按钮。" - }, - "scrollDemo": { - "title": "滚动容器", - "description": "通过设置scrollTarget参数,可对特定容器进行返回顶部操作。" - }, - "anchorLinkValues": { - "back-top-basic": "基本用法", - "back-top-customize": "自定义", - "back-top-scroll-container": "滚动容器" - } - }, - "button": { - "name": "Button 按钮", - "type": "通用", - "path": "button", - "description": "按钮用于开始一个即时操作。", - "tmw": "标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。", - "button-primary": { - "title": "主要按钮", - "ok": "确认", - "disabled": "禁用" - }, - "button-common": { - "title": "次要按钮", - "cancel": "取消", - "disabled": "禁用" - }, - "button-primary-and-common": { - "title": "主要按钮与次要按钮组合", - "description": "主要按钮与次要按钮组合使用时,一个场景通常只有一个主要按钮。", - "ok": "确定", - "cancel": "取消", - "last": "上一步", - "next": "下一步" - }, - "button-left-right": { - "title": "左按钮与右按钮", - "left": "左按钮", - "right": "右按钮" - }, - "button-text": { - "title": "文字按钮", - "ok": "确定", - "cancel": "取消", - "disabled": "禁用" - }, - "button-danger": { - "title": "警示按钮", - "description": "用于标识系统中的关键操作,例如购买场景。", - "purchase": "购买" - }, - "button-loading": { - "title": "加载中状态" - }, - "button-auto-focus": { - "title": "自动获得焦点", - "description": "通过autofocus设置按钮自动获得焦点。", - "ok": "确定", - "cancel": "取消" - }, - "button-icon": { - "title": "图标按钮", - "new": "新建", - "filter": "过滤", - "newDisabled": "新建禁用", - "filterDisabled": "过滤禁用", - "connect": "关联", - "run": "执行", - "connectDisabled": "关联禁用", - "runDisabled": "执行禁用", - "select": "请选择", - "drop": "下拉选择" - }, - "button-size": { - "title": "按钮尺寸", - "description": "按钮有4种大小,可以根据业务场景选择合适大小的按钮。", - "tiny": "超小号", - "small": "小号", - "normal": "正常", - "large": "大号" - }, - "button-groups": { - "title": "按钮组", - "description": "将多个按钮作为一组放入按钮组容器中。按钮组可通过size设置尺寸,并与下拉菜单混合使用。", - "text": "按钮组有4种大小,可通过size设置所有元素尺寸", - "filter": "过滤", - "new": "新建", - "delete": "删除", - "drop": "点击下拉", - "itemOne": "菜单一", - "itemTwo": "菜单二", - "itemThree": "菜单三" - }, - "anchorLinkValues": { - "button-primary": "主要按钮", - "button-common": "次要按钮", - "button-primary-and-common": "主要按钮与次要按钮组合", - "button-left-right": "左按钮与右按钮", - "button-danger": "警示按钮", - "button-text": "文字按钮", - "button-loading": "加载中状态", - "button-auto-focus": "自动获得焦点", - "button-icon": "图标按钮", - "button-size": "按钮尺寸", - "button-groups": "按钮组" - } - }, - "badge": { - "name": "Badge 徽标", - "type": "数据展示", - "path": "badge", - "description": "图标右上角的圆形徽标数字。", - "tmw": "出现在图标右上角或列表项右方,通过不同的状态色加数字提示用户有消息需要处理时。", - "basicDemo": { - "title": "基本徽章", - "description": "基本徽章类型,当有包裹元素时在右上角显示徽章和数目。", - "basic": "标准徽章,通过count参数设置徽章展示的数目,通过status参数可设置徽章状态色", - "maxCount": "可通过maxCount参数设置徽章展示的数目最大值,默认为99", - "statusColor": "通过bgColor参数设置徽章展示状态色,通过offsetXY参数可设置徽章偏移量", - "position": "通过badgePos参数设置徽章位置", - "unread": "未读消息" - }, - "dotDemo": { - "title": "点状徽章", - "description": "点状徽章类型,当有包裹元素且showDot参数为true时为点状徽章,默认在右上角展示小点不显示数目。" - }, - "countDemo": { - "title": "计数徽章", - "description": "当徽章独立使用且不包裹任何元素时,只展示徽章状态色和数目。", - "myCodeHub": "我的代码库", - "myFocus": "我关注的", - "myManaged": "我管理的", - "customFontColor": "通过textColor、bgColor自定义文字、背景颜色", - "code": "代码" - }, - "statusDemo": { - "title": "状态徽章", - "description": "当徽章独立使用、不包裹任何元素且showDot参数为true时为状态徽章,不同状态展示不同色点。" - }, - "positionDemo": { - "title": "徽章位置", - "description": "通过badgePos参数设置徽章位置。" - }, - "customDemo": { - "title": "自定义", - "description": "通过bgColor参数设置徽章展示状态色(此时status参数设置的徽章状态色失效),通过offsetXY参数可设置相对于badgePos的徽章偏移量。通过textColor、bgColor自定义文字、背景颜色。" - }, - "anchorLinkValues": { - "badge-basic": "基本徽章", - "badge-dot": "点状徽章", - "badge-count": "计数徽章", - "badge-status": "状态徽章", - "position": "徽章位置", - "custom": "自定义" - } - }, - "card": { - "name": "Card 卡片", - "type": "数据展示", - "path": "card", - "description": "通用卡片容器。", - "tmw": "基础卡片容器,其中可包含文字,列表,图片,段落,用于概览展示时。", - "basicDemo": { - "title": "基本用法", - "cardTitle": "DEVUI精品实践课", - "cardContent": "DEVUI是一种开源的免费的企业中后台产品前端的通用解决方案,其设计基于“致简”,“沉浸”,“灵活”自然与人文相结合…" - }, - "customDemo": { - "title": "自定义区域", - "cardTitle": "DEVUI精品实践课", - "text": "更新于07月31日15:55" - }, - "mediaDemo": { - "title": "使用图片", - "description": "通过align可设置d-card-actions操作区域对齐方式:起始对齐、尾部对齐、拉伸对齐。", - "cardTitle": "DEVUI精品实践课", - "cardContent": "DEVUI是一种开源的免费的企业中后台产品前端的通用解决方案,其设计基于“致简”,“沉浸”,“灵活”自然与人文相结合…" - }, - "anchorLinkValues": { - "card-basic": "基本用法", - "card-with-media": "使用图片", - "card-custom": "自定义区域" - } - }, - "carousel": { - "name": "Carousel 走马灯", - "type": "数据展示", - "path": "carousel", - "description": "一组轮播的区域。", - "tmw": "用于展示图片或者卡片。", - "basicDemo": { - "title": "基本用法" - }, - "triggerDemo": { - "title": "指示器&切换箭头", - "description": "arrowTrigger设为always可以使箭头永久显示,dotTrigger设为hover可以使hover到点上就切换。" - }, - "autoplayDemo": { - "title": "自动轮播" - }, - "customDemo": { - "title": "自定义操作" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "trigger-usage": "指示器&切换箭头", - "autoplay-usage": "自动轮播", - "custom-usage": "自定义操作" - } - }, - "checkbox": { - "name": "CheckBox 复选框", - "type": "数据录入", - "path": "checkbox", - "description": "多选框。", - "tmw": "
    1. 在一组选项中进行多项选择;
    2. 单独使用可以表示在两个状态之间切换,可以和提交操作结合。
    ", - "basicDemo": { - "title": "基本用法", - "selected": "选中状态", - "unselected": "未选中状态", - "customTitle": "自定义title", - "selectedClose": "选中状态-关闭动效", - "selectedDisable": "选中状态下禁用", - "unselectedDisable": "未选中状态下禁用", - "halfSelected": "半选状态", - "halfSelectedDisable": "半选状态下禁用", - "twoBind": "数据双向绑定", - "Custom Selected Color": "自定义选中颜色", - "Custom Half-Select Color": "自定义半选颜色", - "Customizing a Label Template": "自定义label模板" - }, - "groupDemo": { - "title": "使用CheckBoxGroup", - "Input object array": "传入对象数组", - "Input string array": "传入字符串数组", - "Disable Entire Group": "整组禁用", - "Custom Selected Color": "自定义选中颜色", - "Selected status - disabled": "选中状态-关闭动效", - "Multi-line checkbox": "多行checkbox" - }, - "conditionChangeDemo": { - "title": "checkbox根据条件终止切换状态", - "description": "根据条件判断,label为'条件判断回调禁止选中'的checkbox终止切换状态。", - "Conditional Callback Allowed": "条件判断回调允许选中", - "Conditional judgment callback interception selected": "条件判断回调拦截选中" - }, - "conditionGroupDemo": { - "title": "checkbox-group根据条件终止切换状态", - "description": "选项包含'拦截'字段的checkbox无法切换状态。", - "stateNotSwitch": "选项包含\"拦截\"字段的checkbox无法切换状态", - "intercepts": "拦截" - }, - "anchorLinkValues": { - "checkbox-basic": "基本用法", - "tabs-group": "使用CheckBoxGroup", - "condition-change": "根据条件终止checkbox切换状态", - "condition-group": "根据条件终止checkbox-group切换状态" - } - }, - "common": { - "name": "Common 公共方法", - "type": "通用", - "path": "common", - "description": "提供一些公共的函数。", - "tmw": "处理日期字符串转换、文件下载、a标签模拟、懒加载等。", - "lazyLoadDemo": { - "title": "懒加载指令", - "description": "引入util模块中的LazyLoadModule,使用dLazyLoad指令在滚到到容器底部时响应loadMore事件实现懒加载。" - }, - "pipeDemo": { - "title": "日期解析器" - }, - "openURLDemo": { - "title": "在新标签页打开网页" - }, - "iframePropagateDemo": { - "title": "iframe 冒泡事件", - "description": "iframe的冒泡事件会传递到父容器。" - }, - "clipboardDemo": { - "title": "复制到剪贴板指令" - }, - "helperDownloadDemo": { - "title": "下载文件" - }, - "anchorLinkValues": { - "lazy-load": "懒加载指令", - "date-pipe": "日期解析器", - "open-url": "新标签页打开网页", - "download-file": "文件下载", - "iframe-propagate": "iframe 冒泡事件", - "clipboard": "复制到剪贴板指令" - } - }, - "color-picker": { - "name": "ColorPicker 颜色选择器", - "type": "演进中", - "path": "color-picker", - "description": "输入或选择颜色的控件。", - "tmw": "当用户需要选择颜色时。", - "basicDemo": { - "title": "基本用法" - }, - "tapDemo": { - "title": "配合Dropdown使用" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "with-dropdown": "配合Dropdown使用" - } - }, - "common-styles": { - "name": "CommonStyles 公共样式", - "type": "扩展服务", - "path": "common-styles", - "description": "组件库公共样式规范。", - "tmw": "当需要查看组件库相关样式,使用场景以及变更时。", - "hrefDemo": { - "title": "链接a元素", - "description1": "1. 确认已全局引入devui样式表(devui.min.css);", - "description2": "2. 使用 class=\"devui-link\" 修改a标签的样式。" - }, - "colorDemo": { - "title": "颜色", - "description1": "1. DevUI整理了颜色规范,包括普通色值和暗黑模式色值,以及列出了这些颜色的使用场景,为了更好的精细化控制和显示,同时对颜色做了分类和语义化变量命名;", - "description2": "2. 通过`@import '~ng-devui/styles-var/devui-var.scss';`引入颜色变量后即可使用;", - "description3": "3. 若样式表为less文件,则`@import '~ng-devui/styles-var/devui-var.less';`,并将变量前缀'$'改为'@'。" - }, - "shadowDemo": { - "title": "阴影", - "description1": "1. 组件库为用户们提供了阴影变量用于不同的场景,下表列出了这些变量的名称,对应的变量值以及使用场景;", - "description2": "2. 通过`@import '~ng-devui/styles-var/devui-var.scss';`引入阴影变量后即可使用;", - "description3": "3. 若样式表为less文件,则`@import '~ng-devui/styles-var/devui-var.less';`,并将变量前缀'$'改为'@'。" - }, - "fontDemo": { - "title": "字体", - "description1": "1. 组件库为用户们提供了字体相关变量用于不同的场景,下表列出了这些变量的名称,对应的变量值以及使用场景;", - "description2": "2. 通过`@import '~ng-devui/styles-var/devui-var.scss';`引入字体变量后即可使用;", - "description3": "3. 若样式表为less文件,则`@import '~ng-devui/styles-var/devui-var.less';`,并将变量前缀'$'改为'@'。" - }, - "cornerDemo": { - "title": "圆角", - "description1": "1. 组件库为用户们提供了圆角变量用于不同的场景,下表列出了这些变量的名称,对应的变量值以及使用场景;", - "description2": "2. 通过`@import '~ng-devui/styles-var/devui-var.scss';`引入圆角变量后即可使用;", - "description3": "3. 若样式表为less文件,则`@import '~ng-devui/styles-var/devui-var.less';`,并将变量前缀'$'改为'@'。" - }, - "anchorLinkValues": { - "href-a": "链接a元素", - "color": "颜色", - "shadow": "阴影", - "font": "字体", - "border-radius": "圆角" - } - }, - "codemirror": { - "name": "CodeMirror 代码编辑器", - "type": "扩展服务", - "path": "codemirror", - "description": "代码显示区域。", - "tmw": "用于日志、shell脚本等内容展示或者代码编写。", - "basicDemo": { - "title": "基础用法", - "description": "配置主题和模式。" - }, - "eventDemo": { - "title": "事件监听" - }, - "anchorLinkValues": { - "basic": "基础用法", - "event": "事件监听" - } - }, - "datatable": { - "name": "DataTable 表格", - "type": "数据展示", - "path": "datatable", - "description": "展示行列数据。", - "tmw": "
    1. 当有大量结构化的数据需要展现时;
    2. 当需要对数据进行排序、过滤、自定义操作等复杂行为时。
    ", - "basicDemo": { - "title": "基本用法", - "description": "简单表格,展示列表数据\n支持两种实现方式,方式一通过自定义head、body模板和其中的行、单元格来实现,方式二通过配置column来实现。" - }, - "asyncDemo": { - "title": "异步加载数据、配置列及空数据模板", - "description": "模拟异步加载数据、支持配置动态列、使用#noResultTemplateRef配置空数据模板。" - }, - "cellMergeDemo": { - "title": "单元格合并", - "description": "支持使用colspan、rowspan等属性来设置单元格的合并,只能通过自定义head、body模板和其中的行、单元格来实现。" - }, - "checkOptionsDemo": { - "title": "自定义表格选中操作", - "description": "通过设置checkOptions来配置表头选中的下拉项及操作\n支持两种实现方式,方式一通过自定义head的行来实现,方式二通过配置column来实现。" - }, - "dragColumnDemo": { - "title": "列拖拽", - "description": "应用于列内容有对比诉求,属于低频操作,默认不展示,当鼠标移入表头显示标识,支持用户快速对列进行排序。" - }, - "dragRowDemo": { - "title": "行拖拽", - "description": "支持使用DragDrop组件来实现表格的行拖拽功能,只能通过自定义head、body模板和其中的行、单元格来实现。" - }, - "batchDragRowDemo": { - "title": "批量行拖拽", - "description": "支持使用DragDrop组件来实现表格的批量行拖拽功能,请用Ctrl按键和鼠标多选并进行拖拽,只能通过自定义head、body模板和其中的行、单元格来实现。" - }, - "editableDemo": { - "title": "编辑单元格", - "description": "支持两种实现方式,方式一通过自定义body模板中的单元格来实现,方式二通过配置column来实现。" - }, - "expandRowDemo": { - "title": "扩展行", - "description": "支持两种实现方式,方式一通过自定义body模板中的行来实现,方式二通过配置column来定义table,并配置input和行数据来实现。" - }, - "fixColumnDemo": { - "title": "固定列", - "description": "当表格列过多时,固定列有利于用户在左右滑动屏幕时,能够便捷地进行数据定位与对比,通过fixedLeft、fixedRight来配置\n支持两种实现方式,方式一通过自定义head、body模板和其中的行、单元格来实现,方式二通过配置column来实现。" - }, - "fixHeightVirtualScrollDemo": { - "title": "表头固定虚拟滚动", - "description": "使用fixHeader设置表头固定,并启动虚拟滚动,高度自适应。" - }, - "headerGroupingDemo": { - "title": "表头分组", - "description": "支持两种实现方式,方式一通过自定义head模板中th的colspan、rowspan来实现,方式二通过配置column的advancedHeader来实现。" - }, - "interactionDemo": { - "title": "表格交互", - "description": "支持列排序、列过滤、自定义过滤模板、选中、调整列宽\n支持两种实现方式,方式一通过自定义head、body模板和其中的行、单元格实现,方式二通过配置column来实现。" - }, - "lazyDemo": { - "title": "懒加载", - "description": "使用lazy启用懒加载,当滚动表格底部时到触发loadMore事件实现懒加载。" - }, - "maxHeightDemo": { - "title": "表头固定", - "description": "使用fixHeader设置表头固定,使之不跟随滚动。" - }, - "mutiDragRowDemo": { - "title": "批量行拖拽", - "description": "支持使用DragDrop组件来实现表格的批量行拖拽功能,请用Ctrl按键和鼠标多选并进行拖拽,只能通过自定义head、body模板和其中的行、单元格来实现。" - }, - "mutilStylesDemo": { - "title": "表格样式" - }, - "treeTableDemo": { - "title": "树形表格", - "description": "通过nestedColumn属性和行数据的children、$isChildTableOpen字段来配置渲染树形表格\n支持两种实现方式,方式一通过自定义head、body模板和其中的行、单元格来实现,方式二通过配置column来实现。" - }, - "virtualScrollDemo": { - "title": "虚拟滚动", - "description": "使用virtualScroll启用虚拟滚动,行高须确定且相同,如果行高高于默认的40px,须配置virtualItemSize\n若初始状态无数据,需要对class为`cdk-virtual-scroll-viewport`的元素设定高度,并且建议对`d-data-table`元素和noResult模板设定定位。" - }, - "allDemo": { - "tab1": "自定义模板", - "tab2": "配置column" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "mutil-styles": "表格样式", - "async-loading": "异步加载数据", - "table-interaction": "表格交互", - "table-check-options": "自定义表格选中操作", - "lazy-loading-of-list-data": "懒加载", - "virtual-scroll": "虚拟滚动", - "table-fixing": "表头固定", - "fixed-virtual-scroll": "表头固定虚拟滚动", - "header-grouping": "表头分组", - "edit-cell": "编辑单元格", - "expand-row": "扩展行", - "tree-form": "树形表格", - "fixed-column": "固定列", - "column-dragging": "列拖拽", - "cell-merge": "单元格合并", - "drag-row": "行拖拽", - "muti-drag-row": "批量行拖拽" - } - }, - "datepicker": { - "name": "DatePicker 日期选择器", - "type": "数据录入", - "path": "datepicker", - "description": "输入或选择日期的组件。", - "tmw": "当用户需要输入一个日期时;需要点击标准输入框,弹出日期面板进行选择时。", - "basicDemo": { - "title": "基本用法", - "basic": "基本用法", - "setCss": "设置cssClass", - "disableTitle": "disabled态,可采用本效果,或是参考下方dateRangePicker自行设置的效果" - }, - "clearButtonDemo": { - "clear": "清除", - "today": "今天", - "title": "自定义清除按钮", - "description": "通过 customViewTemplate 增加清除按钮, 可以通过clearAll()来触发, 可给clearAll()传入参数以定义不同reason。" - }, - "templateDemo": { - "selectYesterday": "选择昨天", - "selectTomorrow": "选择明天", - "select": "选择", - "title": "自定义操作区", - "description": "通过 customViewTemplate 自定义快捷设置日期或自定义操作区内容, 可以通过chooseDate(dateString: string)来设置日期。" - }, - "formatDemo": { - "reset": "重置", - "title": "格式化", - "description": "通过dateFormat设置日期的格式。" - }, - "limitDemo": { - "title": "限制最大最小日期", - "limit": "限制", - "limitTogether": "同时限制" - }, - "setModeDemo": { - "title": "设置日期选择器的类型", - "yearPicker": "设置年选择器 mode='year'", - "monthPicker": "设置年月选择器 mode='month'", - "description": "只选择截止到年,月,周,不一定需要准确的具体的某天,比如:可以是1999年,可以是1994年8月,可以是1994年8月15日,如果不设置,则默认选择到日。分为年和月两种模式。" - }, - "rangeDemo": { - "selectToday": "选择今天", - "selectStart": "选择迭代开始日期", - "selectWeek": "选择一周后", - "selectEnd": "选择迭代结束日期", - "title": "范围日期选择器", - "description": "与单日日期选择器相同,范围日期选择器展开时默认选中当前日期。范围日期选择器包含开始日期选择器和结束日期选择器,用户可以选择一段日期。" - }, - "rangeClearDemo": { - "clearTitle": "日期范围选择器:可给clearAll()传入参数以定义不同reason,everyRange方法仅提供参考,具体请业务自行处理", - "clear": "清除", - "title": "日期范围选择器 自定义操作区及清除按钮", - "description": "日期范围选择器:可给clearAll()传入参数以定义不同reason,everyRange方法仅提供参考,具体请业务自行处理。" - }, - "rangePickerDemo": { - "rangePicker": "日期范围选择器(选择完成时自动隐藏):", - "valuedRangePicker": "已赋值的日期范围选择器(默认:选择完成时保持打开):", - "cssRangePicker": "日期范围选择器(设置cssClass):", - "title": "日期范围选择器 集成模式" - }, - "rangeDisableDemo": { - "rangePicker": "日期范围选择器:", - "title": "日期范围选择器 禁止输入态", - "description": "禁止输入只提供一种思路,datepicker本身自带disabled状态不可选,请根据业务情况自行操作。" - }, - "rangeFormatDemo": { - "formaterRange": "日期范围选择器(设置format):", - "configRange": "日期范围选择器(设置dateConfig):", - "title": "日期范围选择器 格式化" - }, - "rangeRestrictedDemo": { - "limitRange": "日期范围选择器 限制开始和截止范围,everyRange方法仅提供参考,具体请业务自行处理:", - "limitStartRange": "日期范围选择器 限制开始范围:", - "limitEndRange": "日期范围选择器 限制截止范围:", - "title": "日期范围选择器 可选范围" - }, - "rangeTimeDemo": { - "dateTimeRange": "日期时间范围选择器:", - "valuedTimeRange": "日期时间范围选择器 已赋值:", - "title": "日期范围选择器 选择时间" - }, - "rangeTodayDemo": { - "rangePicker": "日期范围选择器:", - "selectYesterday": "选择昨天", - "selectWeek": "选择上周", - "selectToday": "选择今天", - "selectTomorrow": "选择明天", - "title": "日期范围选择器 自定义操作选择日期", - "description": "通过 chooseDate 结合 rangeStart 和 rangeEnd 设置自定义日期。" - }, - "twoDatePickerDemo": { - "twoRangePicker": "双日期选择器 选择完成后隐藏", - "keepOpenedPicker": "双日期选择器 (设置cssClass)选择完成后保持打开", - "disabledPicker": "双日期选择器 禁用(仅提供参考,或参考dateRangePicker进行设置)", - "title": "双日期选择器" - }, - "twoDatepickerFormatDemo": { - "formaterRange": "双日期选择器 格式化", - "configRange": "双日期选择器 设置dateConfig", - "title": "双日期选择器 格式化" - }, - "appendToBodyDemo": { - "title": "附着在body上" - }, - "buttonDemo": { - "title": "日期选择按钮", - "description": "可以通过按钮唤出Datepicker。" - }, - "anchorLinkValues": { - "datepicker-default": "基本用法", - "datepicker-set-mode": "设置日期选择器的类型", - "datepicker-min-max": "限制最大最小日期", - "datepicker-append-to-body": "附着在body上", - "datepicker-range": "范围日期选择器", - "datepicker-range-basic": "日期范围选择器 集成模式", - "datepicker-range-format": "日期范围选择器 格式化", - "datepicker-range-disabled": "日期范围选择器 禁止输入态", - "datepicker-range-restricted-range": "日期范围选择器 可选范围", - "datepicker-range-time": "日期范围选择器 选择时间", - "datepicker-clear-button": "日期范围选择器 自定义操作区、清除", - "datepicker-range-today": "日期范围选择器 自定义操作选择日期", - "datepicker-format": "格式化", - "custom-view-template": "自定义操作区", - "date-picker-clear-button": "自定义清除按钮", - "date-picker-button": "日期选择按钮", - "two-date-picker-basic": "双日期选择器", - "two-date-picker-format": "双日期选择器 格式化" - } - }, - "echarts": { - "name": "Echarts 可视化图表", - "type": "扩展服务", - "path": "echarts", - "description": "图表可视化组件。", - "tmw": "当需要向用户直观可视化展示统计数据时使用。", - "changeBgDemo": { - "changeBg": "修改背景色", - "clickChange": "点击切换饼图背景", - "title": "修改chart背景色", - "description": "支持背景颜色实时修改。" - }, - "instanceDemo": { - "listener": "监听事件", - "clickTime": "点击次数", - "title": "获取echarts实例", - "description": "获取echarts实例,进行api调用。" - }, - "basicDemo": { - "title": "渲染一个饼图", - "description": "简单用法,渲染一个圆饼图。" - }, - "anchorLinkValues": { - "render-pie": "渲染一个饼图", - "chart-bg": "修改chart背景色", - "chart-ins": "获取echarts实例" - } - }, - "jsmind": { - "name": "Jsmind 思维导图", - "type": "扩展服务", - "path": "jsmind", - "description": "思维导图组件。", - "tmw": "当需要向用户展示一些横向结构层次关系时。", - "basicDemo": { - "title": "基本用法", - "description": "渲染一个基本的思维导图。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法" - } - }, - "multi-auto-complete": { - "name": "MultiAutoComplete 多项自动补全", - "type": "数据录入", - "path": "multi-auto-complete", - "description": "匹配可能的选项输入组件。", - "tmw": "当用户需要在若干选项当中选择多个进行输入时。", - "defaultDemo": { - "title": "基本用法", - "description": "通过 source 设置数据源。", - "Please select": "请选择" - }, - "arrayDemo": { - "title": "自定义匹配方法", - "description": "通过 searchFn 自定义数据的匹配方法和返回的数据格式,如果你需要实现数据的清空与复制操作,可使用自定义按钮的方式。", - "Choose three options": "请至少选择三个选项", - "emptied": "清空", - "replicated": "复制", - "Select Object": "选择对象", - "Run the browser copy command.": "执行浏览器复制命令", - "Copy succeeded.": "复制成功", - "Data replicated successfully": "数据已成功复制至剪切板" - }, - "disabledDemo": { - "title": "使用禁用", - "description": "通过 disabled 自定义是否使用禁用。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "auto-complete-array": "自定义匹配方法", - "auto-complete-disabled": "使用禁用" - } - }, - "form": { - "name": "Form 表单", - "type": "数据录入", - "path": "form", - "description": "具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。", - "tmw": "需要进行数据收集、数据校验、数据提交功能时。", - "basicDemo": { - "title": "基本用法", - "description": "基本用法当中,Label是在数据框的上面。", - "d-form-item-title": "表单项 d-form-item", - "d-form-item-description": "表单项,包含表单Label和具体表单输入组件。", - "d-form-label-title": "表单项 d-form-label", - "d-form-label-description": "表单项Label,描述该项表单关键字,包括帮助信息、是否必填等功能。", - "d-form-control-title": "控件容器 d-form-control", - "d-form-control-description": "表单项控件容器,里面容纳不同的表单输入组件。", - "d-form-operation-title": "操作区容器 d-form-operation", - "d-form-operation-description": "操作区域容器,用来放置按钮等元素。", - "That's the plan name.": "这是计划名,计划名字,计划名", - "Plan Name": "计划名", - "Plan Description": "计划描述", - "Radio box": "单选框", - "Multiple options": "多选项", - "Label Options": "标签选项", - "Label": "标签", - "switch": "开关", - "Execution Date": "执行日", - "Submit": "提交", - "cancels": "取消", - "Option": "选项", - "Manual execution": "手工执行", - "Daily Scheduled Execution": "每日定时执行", - "Weekly scheduled execution": "每周定时执行", - "Monday": "周一", - "tuesday": "周二", - "Wednesday": "周三", - "thursday": "周四", - "friday": "周五", - "Saturday": "周六", - "Sunday": "周日", - "Option (Multiple Choices with Delete)": "选项(多选带删除)" - }, - "labelHorizontalDemo": { - "title": "label 横向排列", - "description": "Label左右布局方式。", - "Plan Name": "计划名", - "Short Name": "输入一个符合阅读习惯的短名字,最多30个字符,不能是系统字段,且不能与已有的字段重名", - "Plan Description": "计划描述", - "Radio box": "单选框", - "check box": "多选框", - "Label Options": "标签选项", - "Single Option": "单选项", - "Label": "标签", - "switch": "开关", - "Execution Date": "执行日", - "Submit": "提交", - "cancels": "取消", - "Select your execution cycle": "选择您的执行周期,推荐选择周一,周三,周五", - "Option": "选项", - "Manual execution": "手工执行", - "Daily Scheduled Execution": "每日定时执行", - "Weekly scheduled execution": "每周定时执行", - "Monday": "周一", - "tuesday": "周二", - "Wednesday": "周三", - "thursday": "周四", - "friday": "周五", - "Saturday": "周六", - "Sunday": "周日", - "Option (Multiple Choices with Delete)": "选项(多选带删除)" - }, - "modalDemo": { - "title": "弹框表单", - "description": "弹框表单,弹框建议是400px,550px,700px,900px,建议宽高比是16: 9、3: 2。", - "Pop-up form": "弹框表单", - "ok": "确定", - "cancels": "取消" - }, - "multiColDemo": { - "title": "多列表单", - "description": "多列表单。", - "That's the plan name.": "这是计划名,计划名字,计划名", - "Plan Name": "计划名", - "Radio box": "单选框", - "check box": "多选框", - "Label Options": "标签选项", - "switch": "开关", - "Execution Date": "执行日", - "Submit": "提交", - "cancels": "取消", - "Option": "选项", - "Manual execution": "手工执行", - "Daily Scheduled Execution": "每日定时执行", - "Weekly scheduled execution": "每周定时执行", - "Monday": "周一", - "tuesday": "周二", - "Wednesday": "周三", - "thursday": "周四", - "friday": "周五", - "Saturday": "周六", - "Sunday": "周日", - "Option (Multiple Choices with Delete)": "选项(多选带删除)" - }, - "templateValidateDemo": { - "title": "模板驱动表单验证", - "description": "模板中绑定ngModel、ngGroupModel、ngForm的元素,可使用dValidateRules配置校验规则。" - }, - "innerValidatorDemo": { - "title": "验证单个元素,使用内置校验器", - "description": "

    当前DevUI支持的内置校验器有:required、minlength、maxlength、min、max、requiredTrue、email、pattern、whitespace

    若需限制用户输入不能全为空格,可使用whitespace内置校验器

    若需限制用户输入长度,将最大限制设置为实际校验值+1是一个好的办法。

    pattern外,其他内置校验器我们也提供了内置的错误提示信息,在你未自定义提示消息时,我们将使用默认的提示信息。

    " - }, - "customerValidatorDemo": { - "title": "验证单个元素,自定义校验器", - "description": "
    • 一个校验器需要一个唯一的id标识,你可显式声明此id,也可声明一个与保留字不冲突的key,此key将被识别为id, 其value作为校验器。
    • 自定义校验器,你可以简单返回true | false 来标识当前校验是否通过, 也可以返回string | null,来标识当前是否错误并返回错误消息,适用于动态错误提示。
    • 如果是异步校验器,你需要将你的值以Observable对象方式返回。
    • 更多地,DevUI兼容原生angular校验器, 你可将isNgValidator设置为true
    " - }, - "customErrorStrategyDemo": { - "title": "验证单个元素,配置错误更新策略errorStrategy、校验时机updateOn", - "description": "
    • 设置errorStrategy元素初始化时若校验不通过,错误是否会进行提示, 默认配置为dirty,若需要在初始化时将错误抛出,可配置为pristine
    • errorStrategy可继承。
    • 设置updateOn,指定校验的时机。 校验器updateOn基于你绑定的模型的updateOn设置, 在模板中你可以通过ngModelOptions来指定, 默认为change,可选值还有blursubmit, 设置为submit,则当元素所在表单进行提交时将触发校验。
    " - }, - "customMessageShowDemo": { - "title": "验证单个元素,自定义管理消息提示", - "description": "
    • 配置messageShowType可选择消息自动提示的方式,默认为popover
    • 设置为popover错误信息将在元素聚焦时以popover形式呈现。
    • 设置为text错误信息将自动以文本方式显示在元素下方(需要与表单控件容器配合使用)。
    • 设置为none错误信息将不会自动呈现到视图, 可在模板中获取message或通过监听messageChange事件获取错误message, 或在模板中直接通过引用获取。
    • 此配置可继承。
    • 配置popPosition可在消息提示方式为popover时,自定义popover内容弹出方向。 默认为['right', 'bottom']
    • 此配置可继承。
    " - }, - "debounceTimeDemo": { - "title": "验证单个元素,自定义asyncDebounceTime", - "description": "
    • 我们对于异步校验器,提供默认300ms debounce time
    • 也可在dValidateRules中设置asyncDebounceTime显示设置(单位ms)。
    • 若你的同步校验器也需要debounce time,则其表现已为异步校验,你可将其转换为异步校验器。
    • 此配置可继承。
    " - }, - "validateTemplateForm": { - "title": "Form验证与提交", - "description": "
    • dValidateRules也可作用于已绑定ngForm、ngModelGroup元素上, 进行表单状态与错误消息的统一管理。
    • 对于非边框类元素,建议在d-form-item容器上配置dHasFeedbacktrue 进行错误反馈提示。
    • 对于dForm,可使用dFormSubmit、dFormReset 指令关联将用于触发提交与重置操作的元素。
    • 若表单设置了异步校验,可将对应按钮loading与表单pending状态关联起来。
    " - }, - "userRegisterDemo": { - "title": "Form验证与提交,用户注册场景", - "description": "
    • 针对表单场景复杂的校验规则,我们推荐在控制器中组织,可更好地组织与复用你的校验规则。
    • 对于自动错误提示的方式,在form中, 建议在dForm层统一设置messageShowType
    • 对于由dFormSubmit触发的提交事件, 你可在dForm层绑定dSubmit监听, 可获取到当前form验证状态与对应的directive引用。
    • 若表单在提交时,已不在视觉中心,那么你可以使用一个提示来引导用户视觉,对于表单提交时的提示,我们推荐使用d-toast显示。
    " - }, - "validateReactiveDemo": { - "title": "响应式表单验证", - "description": "模板中绑定formGroup、formControlName、formControl,使用dValidateRules配置校验规则。

    推荐阅读【Angular响应式表单】

    " - }, - "customStatusDemo": { - "title": "指定表单Feedback状态", - "description": "你可通过对d-form-control设置feedbackStatus手动指定反馈状态。当前已支持状态:success、error、pending。" - }, - "validateSyncDemo": { - "title": "表单协同验证", - "description": "在一些场景下,你的多个表单组件互相依赖,需共同校验(如注册场景中的密码输入与确认密码),此时你需要用协同验证指令dValidateSyncKey来为需要系统校验的组件指定相同的keydValidateSyncKey指令支持模板驱动表单与响应式表单,以下示例以模板驱动表单为例:passwordconfirmPassword设置相同的dValidateSyncKey值,在其中一个组件值变更时,另一个组件也将进行校验。" - }, - "validateCrossComponentDemo": { - "title": "跨组件验证", - "description": "
    • 当前Angular Form默认暂不支持跨组件共享表单校验状态,对于响应式表单,你可使用统一管理model,向下透传的方式进行组件组织。
    • 针对模板驱动表单,你可使用在子组件声明时进行容器注入的方式,将你需要的ngModelGroupNgForm容器进行注入,以供模板中表单元素自动获取父容器。
    " - }, - "reactiveCrossComponent": { - "title": "响应式表单跨组件验证" - }, - "templateCrossComponent": { - "title": "模板驱动表单跨组件验证" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "demo-label-horizontal": "label 横向排列", - "demo-modal": "弹框表单", - "demo-multi-col": "多列表单", - "demo-filter": "表单过滤", - "demo-validate-template": "模板驱动表单验证(推荐)", - "demo-validate-reactive": "响应式表单验证", - "demo-custom-status": "指定表单状态", - "demo-validate-sync": "表单协同验证", - "demo-validate-cross-component": "跨组件表单验证" - } - }, - "fullscreen": { - "name": "Fullscreen 全屏", - "type": "通用", - "path": "fullscreen", - "description": "全屏组件。", - "tmw": "当用户需要将某一区域进行全屏展示时。", - "immersiveDemo": { - "title": "沉浸式全屏", - "description": "充满整个显示器屏幕的沉浸式全屏。", - "fullscreen": "全屏", - "exitFullscreen": "退出全屏" - }, - "normalDemo": { - "title": "普通全屏", - "description": "充满当前浏览器窗口的普通全屏。", - "fullscreen": "全屏", - "exitFullscreen": "退出全屏" - }, - "anchorLinkValues": { - "immersive-full-screen": "沉浸式全屏", - "general-full-screen": "普通全屏" - } - }, - "transfer": { - "name": "Transfer 穿梭框", - "type": "数据录入", - "path": "transfer", - "description": "双栏穿梭选择框。", - "tmw": "需要在多个可选项中进行多选时。穿梭选择框可用只管的方式在两栏中移动数据,完成选择行为。其中左边一栏为source,右边一栏为target。最终返回两栏的数据,提供给开发者使用。", - "basicDemo": { - "title": "基本用法", - "description": "穿梭框基本用法。", - "sourceTitle": "源标题", - "targetTitle": "目标标题", - "disabled:": "禁用:", - "option1": "选项1(包含此选项禁止transfer)", - "option2": "选项2", - "option3": "选项3", - "option4": "选项4", - "option5": "选项5", - "option6": "选项6", - "option7": "选项7", - "option8": "选项8", - "option9": "选项9", - "option10": "选项10", - "option11": "选项11", - "option12": "选项12", - "option13": "选项13", - "option14": "选项14", - "option15": "选项15", - "option16": "选项16", - "option17": "选项17", - "option18": "选项18", - "option19": "选项19", - "option20": "选项20", - "option21": "选项21" - }, - "searchDemo": { - "title": "搜索穿梭框", - "description": "在数据很多的情况下,可以对数据进行搜索和过滤。", - "sourceTitle": "源标题", - "targetTitle": "目标标题", - "disabled:": "禁用:", - "option1": "选项1", - "option2": "选项2", - "option3": "选项3", - "option4": "选项4", - "option5": "选项5", - "option6": "选项6", - "option7": "选项7", - "option8": "选项8", - "option9": "选项9", - "option10": "选项10", - "option11": "选项11", - "option12": "选项12", - "option13": "选项13", - "option14": "选项14", - "option15": "选项15", - "option16": "选项16", - "option17": "选项17", - "option18": "选项18", - "option19": "选项19" - }, - "sortDemo": { - "title": "排序穿梭框", - "description": "可以对穿梭框源和目标框的数据进行排序。", - "sourceTitle": "源标题", - "targetTitle": "目标标题", - "disabled:": "禁用:", - "option1": "选项1", - "option2": "选项2", - "option3": "选项3", - "option4": "选项4", - "option5": "选项5", - "option6": "选项6", - "option7": "选项7", - "option8": "选项8", - "option9": "选项9", - "option10": "选项10", - "option11": "选项11", - "option12": "选项12", - "option13": "选项13", - "option14": "选项14", - "option15": "选项15", - "option16": "选项16", - "option17": "选项17", - "option18": "选项18", - "option19": "选项19", - "option20": "选项20", - "option21": "选项21" - }, - "customDemo": { - "title": "自定义穿梭框", - "description": "可以对穿梭框内容的显示进行自定义。", - "sourceTitle": "源标题", - "targetTitle": "目标标题", - "disabled:": "禁用:", - "option1": "选项1", - "option2": "选项2", - "option3": "选项3", - "option4": "选项4", - "option5": "选项5", - "option6": "选项6", - "option7": "选项7", - "option8": "选项8", - "option9": "选项9", - "option10": "选项10", - "option11": "选项11", - "option12": "选项12", - "option13": "选项13", - "option14": "选项14", - "option15": "选项15", - "option16": "选项16", - "option17": "选项17", - "option18": "选项18", - "option19": "选项19", - "option20": "选项20", - "option21": "选项21" - }, - "anchorLinkValues": { - "transfer-demo-base": "基本用法", - "transfer-demo-search": "搜索穿梭框", - "transfer-demo-sort": "排序穿梭框", - "transfer-demo-custom": "自定义穿梭框" - } - }, - "dragdrop": { - "name": "DragDrop 拖拽", - "type": "通用", - "path": "dragdrop", - "description": "拖拽组件。", - "tmw": "当需要使用数个操作步骤,且步骤的顺序需要灵活调整时。", - "basicDemo": { - "title": "基本用法", - "description": "从一个container拖动到另外一个container,并支持排序。", - "Default dragging": "默认拖拽", - "Dragable Item": "可拖拽项", - "Place Sort Area": "放置排序区", - "Placement Area (No Sorting)": "放置区(无排序)", - "(Do not drag)": "(禁止拖拽)" - }, - "treeDemo": { - "title": "多层树状拖拽", - "description": "排序允许拖拽到元素上,支持层级嵌套。", - "Multi-layer tree dragging": "多层树状拖拽", - "Candidate area": "备选区", - "Tree Sorting Area": "树状排序区" - }, - "followDemo": { - "title": "拖拽实体元素跟随", - "description": "允许拖拽时候非半透明元素跟随。也可以使用appendToBody:当拖拽离开后源位置的父对象会被销毁的话,需要把克隆体附着到body上防止被销毁。 默认会通过复制样式保证克隆到body的实体的样式是正确的,但部分深度依赖DOM节点位置的样式和属性可能会失败,需要手动调整部分样式。", - "Drag Entity Elements to Follow": "拖拽实体元素跟随", - "Dragable Item": "可拖拽项", - "Place Sort Area": "放置排序区", - "Attaching the clone entity to the body": "克隆实体附着到body上", - "AppendToBody of dragFollowOptions is used in the following scenarios: If the parent object in the source location is destroyed after being dragged out, attach the clone to the body to prevent it from being destroyed. By default, the style of the cloned body is copied to ensure that the style of the cloned body is correct. However, some styles and attributes that depend on the DOM node location may fail. In this case, you need to manually adjust some styles.": "dragFollowOptions的appendToBody使用场景说明:当拖拽离开后源位置的父对象会被销毁的话,需要把克隆体附着到body上防止被销毁。默认会通过复制样式保证克隆到body的实体的样式是正确的,但部分深度依赖DOM节点位置的样式和属性可能会失败,需要手动调整部分样式。" - }, - "switchDemo": { - "title": "越边交换", - "description": "设置switchWhileCrossEdge允许越过边缘的时候交换。注意:不可与dropOnItem一起用,dropOnItem为true的时候无效。", - "Move the mouse over the edge of the element.": "鼠标越过元素边缘发生交换", - "Drag-and-drop sorting exchange": "拖拽排序交换" - }, - "positionDemo": { - "title": "外部放置位置:就近,前面,后面", - "description": "使用defaultDropPostion配置排序器之外的区域拖拽元素放下的时候默认加到列表的前面或者后面,默认为就近('closest')。", - "Drag-and-drop items": "可拖放项", - "Drag and drop here Add to top": "拖放到此处加到顶部", - "Drag and drop here Add to bottom": "拖放到此处加到底部", - "Drag and drop here Add nearest": "拖放到此处加到最近处" - }, - "dropScrollDemo": { - "title": "拖拽滚动容器增强", - "description": "搭配使用dDropScrollEnhanced指令允许拖拽到边缘的时候加速滚动条向两边滚动。", - "Drag an element to the edge of the scroll bar to trigger scrolling.": "拖拽元素到滚动条边缘区块触发滚动", - "Show drag-and-drop scrolling area": "显示拖拽滚动感应区域", - " Active area. Drag to trigger scrolling.": "活跃区域,拖拽可触发滚动", - " Inactive area, elements under which elements are dragged are placed.": "非活跃区域,拖拽元素会放在其下的元素" - }, - "originPlaceholderDemo": { - "title": "源占位符", - "description": "使用originPlaceholder显示源位置的占位符,示例消失动画。", - "Drag from here. The source placeholder disappears directly after being placed.": "从这里拖,源占位符在放置之后直接消失", - " Drag from here, the source placeholder disappears after the delay": "从这里拖,源占位符在放置之后延迟消失", - "Drag from here, the source placeholder disappears after it is placed. Animation": "从这里拖,源占位符在放置之后动画消失" - }, - "batchDragDemo": { - "title": "批量拖拽", - "description": "使用batchDrag指令标记可以批量拖拽。", - "Batch dragging is supported. Press Ctrl to select multiple items and drag them.": "支持批量拖拽,请用ctrl按键和鼠标选中多个并进行拖拽", - "Show Source Placeholders": "显示源占位符", - "crossover exchange": "越边交换", - "Clear Selected": "清空已选" - }, - "crossDimensionDemo": { - "title": "二维拖拽和拖拽预览", - "description": "使用dDragDropSyncBox指令、dDragSync指令、dDropSync指令协同拖拽,实现二维拖拽;使用dDragPreview配置拖拽预览,使用d-drag-preview-clone-dom-ref 完成拖拽节点预览的克隆。", - "Owner": "责任人", - "To be allocated": "待分配", - "Lin Huahua": "林花花", - "Wang Xiaoming": "王小明", - "Newly created": "新建", - "Ongoing": "进行中", - "Completed": "已完成" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "multi-level-tree-drag": "多层树状拖拽", - "drag-entity-elements-to-follow": "拖拽实体元素跟随", - "cross-edge-switching": "越边交换", - "external-location": "外部放置位置", - "drag-and-roll-container-enhancement": "拖拽滚动容器增强", - "source-placeholder": "源占位符", - "batch-drag-and-drop": "批量拖拽", - "2D-drag-and-drop-preview": "二维拖拽和拖拽预览" - } - }, - "drawer": { - "name": "Drawer 抽屉板", - "type": "反馈", - "path": "drawer", - "description": "屏幕边缘滑出的浮层面板组件。", - "tmw": "
    1. 抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到到原任务。
    2. 当需要一个附加的面板来控制父窗体内容,这个面板在需要时呼出。比如,控制界面展示样式,往界面中添加内容。
    3. 当需要在当前任务流中插入临时任务,创建或预览附加内容。比如展示协议条款,创建子对象。
    ", - "basicDemo": { - "title": "基本用法", - "description": "基本用法,可以控制全屏、关闭和设置宽度。" - }, - "undestroyableDemo": { - "title": "关闭后不销毁", - "description": "关闭后不销毁,需要手动销毁,适用于不需要关闭立即销毁的场景。", - "openSlider": "打开侧滑窗", - "manualDestroy": "手动销毁", - "closeManualDestroy": "关闭后可手动销毁,打开状态调用无效" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "do-not-destroy-after-closing": "关闭后不销毁" - } - }, - "dropdown": { - "name": "DropDown 下拉菜单", - "type": "导航", - "path": "dropdown", - "description": "按下弹出列表组件。", - "tmw": "当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。", - "basicDemo": { - "title": "基本用法", - "description": "", - "More Operations": "更多操作", - "Text box": "输入框", - "Disable Options": "禁用选项", - "Newly created": "新建", - "Deleted": "删除", - "Menu 1": "菜单一", - "Menu 2": "菜单二", - "Menu 3": "菜单三", - "Menu 4": "菜单四", - "Attach to the body to prevent it from being blocked by the scroll bar.": "附着到body上防止被滚动条遮挡" - }, - "hoverDemo": { - "title": "悬浮下拉", - "description": "通过trigger设置下拉的触发方式(点击或悬浮)。", - "Menu 1": "菜单一", - "Menu 2": "菜单二", - "Menu 3": "菜单三" - }, - "focusDemo": { - "title": "聚焦的时候自动的展开和初始化的时候自动聚焦", - "description": "通过toggleOnFocus设置tab按键等聚焦的时候自动展开;通过autoFocus设置初始化的时候自动聚焦;两者可结合使用也可分开使用。", - "When you press Tab to navigate to the dropdown Toggle object, the menu is automatically expanded.": "tab键导航到dropdown的Toggle对象的时候,会自动展开菜单", - "More Operations": "更多操作", - "Disable Options": "禁用选项", - "Newly created": "新建", - "Deleted": "删除", - "Menu 1": "菜单一", - "Menu 2": "菜单二", - "Menu 3": "菜单三", - "Menu 4": "菜单四", - "The focus is automatically performed during initialization. It can be automatically expanded with toggleOnFocus or used independently.": "初始化的时候会自动focus;搭配toggleOnFocus可以自动展开,也可单独使用", - "Initialization/Destruction": "初始化/销毁", - "Text box": "输入框" - }, - "closeScopeDemo": { - "title": "关闭触发点设置", - "description": "通过closeScope设置关闭的触发点,blank:非菜单区域点击才会触发,all:菜单区域也会触发,none:仅下拉区域可以点击关闭,或者自行手动关闭。", - "The drop-down menu is closed only after you click the menu.": "点击菜单外才会关闭的下拉菜单", - "Click the drop-down button.": "点击下拉", - "Text box": "输入框", - "Menu 1": "菜单一", - "Menu 2": "菜单二", - "Menu 3": "菜单三", - "Self-closed": "自行关闭", - "Click the last menu item to close it.": "点击最后一个菜单项进行关闭", - "Menu 1 Disable": "菜单一禁用", - "Close": "关闭" - }, - "appendToBodyDemo": { - "title": "使用appendToBody的时候设置展开位置处理,更换对齐对象", - "description": "通过appendToBodyDirections设置展开位置的优先级列表;通过alignOrigin更换默认对齐对象。", - "Align with regions Use bottom left (right aligned below), top left (right aligned above display)": "与区域对齐使用左下(右对齐下),左上(右对齐上方显示)", - "Align the area.": "对齐区域", - "Drop-down button": "下拉按钮", - "Disable Options": "禁用选项", - "Newly created": "新建", - "Deleted": "删除", - "Using Centered Display": "使用居中显示", - "Creating a Content": "新建内容操作", - "Deleted content": "删除内容等" - }, - "manuallyDemo": { - "title": "手动控制下拉", - "description": "通过 trigger 设置手动控制下拉。" - }, - "set-is-openDemo": { - "title": "通过设置isOpen控制下拉" - }, - "addIconDemo": { - "title": "支持添加图标", - "description": "", - "Newly created": "新建", - "Delete": "刪除", - "Menu 1": "菜单一", - "Menu 2": "菜单二", - "Menu 3": "菜单三", - "Menu 4": "菜单四" - }, - "multiLevelDemo": { - "title": "多级下拉菜单", - "description": "", - "Click": "单击", - "More options": "更多选择", - "Content 1": "内容1", - "Content 1-1": "内容1-1", - "Content 1-1-1": "内容1-1-1", - "Content 1-1-2": "内容1-1-2", - "Content 1-1-3": "内容1-1-3", - "Content 1-2": "内容1-2", - "Content 1-2-1": "内容1-2-1", - "Content 2": "内容2", - "hovering": "悬停", - "Click to expand the menu. The menu is automatically closed when you exit.": "单击展开,离开菜单自动关闭" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "turn-off-trigger-point-settings": "关闭触发点设置", - "suspension-drop-down": "悬浮下拉", - "manually-control": "手动控制下拉", - "dropdown-set-is-open": "通过isOpen控制下拉", - "auto-expand-and-auto-focus": "自动展开和自动聚焦", - "when-using-appendtobody": "设置展开位置处理", - "add-icon": "支持添加图标", - "multi-level-drop-down-menu": "多级下拉菜单" - } - }, - "editable-select": { - "name": "EditableSelect 可输入下拉选择框", - "type": "数据录入", - "path": "editable-select", - "description": "同时支持输入和下拉选择的输入框。", - "tmw": "当需要同时支持用户输入数据和选择已有数据的时候使用,加入输入联想功能,方便用户搜索已有数据。", - "basicDemo": { - "title": "基本用法", - "description": "通过 source 设置数据源。" - }, - "disableDataDemo": { - "title": "设置禁用选项", - "description": "支持禁用指定数据。" - }, - "searchFunctionDemo": { - "title": "自定义匹配方法", - "description": "通过 searchFn 自定义数据匹配方法。" - }, - "async-data-function": { - "title": "异步获取数据源并设置匹配方法", - "description": "支持异步设置数据源并设置匹配方法。" - }, - "lazyLoadDemo": { - "title": "数据懒加载", - "description": "数据懒加载。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "disable-data-with-source": "设置禁用选项", - "with-search-function": "自定义匹配方法", - "async-data-with-function": "异步获取数据源并设置匹配方法", - "lazy-load": "数据懒加载" - } - }, - "editorx": { - "name": "EditorX 富文本", - "type": "数据录入", - "path": "editorx", - "description": "富文本编辑器。", - "tmw": "当需要对富文本内容进行编辑时。", - "defaultDemo": { - "title": "默认示例", - "description": "展示EditorX的默认功能。" - }, - "customToolbarDemo": { - "title": "自定义工具栏", - "description": "完整功能+自定义工具栏分组+收起不常用的工具按钮。" - }, - "readOnlyModeDemo": { - "title": "只读模式", - "description": "只读模式,没有工具栏,没有字数统计。按保存按钮或快捷键 Ctrl+S 可以变成只读模式,按编辑按钮可以变成编辑模式。" - }, - "expandToolbarDemo": { - "title": "扩展工具栏", - "description": "添加工具栏-自定义触发事件-操作editor对象。" - }, - "initWithObjDemo": { - "title": "使用对象进行初始化", - "description": "使用 object 格式对象对编辑器进行初始化(而不是默认的 html 格式),object 格式是更适合持久化存储的格式,也是推荐存储到后台的格式。" - }, - "uploadDemo": { - "title": "图片和文件上传", - "description": "图片和文件上传到服务器,需要将示例中的上传接口替换成真实的后台接口才能正确运行。" - }, - "charStatisticsDemo": { - "title": "字符统计", - "description": "统计当前输入的字符数、单词数、HTML字符数,并可定制展示的模板。" - }, - "customFullScreenDemo": { - "title": "定制全屏模式", - "description": "默认是沉浸式全屏,可以通过配置成普通全屏,并可定制全屏层级。" - }, - "globalHrefDemo": { - "title": "全局链接", - "description": "全局链接。" - }, - "richTextInDrawerDemo": { - "title": "抽屉板中的富文本", - "description": "在抽屉板中使用富文本编辑器。" - }, - "xssDemo": { - "title": "XSS", - "description": "XSS。" - }, - "anchorLinkValues": { - "default-example": "默认示例", - "custom-toolbar": "自定义工具栏", - "read-only-mode": "只读模式", - "expand-toolbar": "扩展工具栏", - "init-with-obj": "使用对象进行初始化", - "upload": "图片和文件上传", - "char-statistics": "字符统计", - "custom-full-screen": "定制全屏模式", - "global-href": "全局链接", - "rich-text-in-drawer": "抽屉板中的富文本", - "xss": "XSS" - } - }, - "loading": { - "name": "Loading 加载提示", - "type": "反馈", - "path": "loading", - "description": "提示用户页面正在执行指令,需要等待。", - "tmw": "当执行指令时间较长(需要数秒以上)时,向用户展示正在执行的状态。", - "basicDemo": { - "title": "基本用法", - "description": "展示加载表格数据的场景中的基本使用方法。", - "click me!": "clickme!", - "FirstName": "FirstName", - "LastName": "LastName", - "UserName": "UserName" - }, - "customDemo": { - "title": "自定义样式", - "description": "通过 templateRef 自定义loading样式。", - "Loading Style 2": "loading样式2", - "Loading Style 3": "loading样式3", - "Text loading": "文字加载" - }, - "promiseDemo": { - "title": "多promise", - "description": "支持多个promise。", - "click": "click" - }, - "subscriptionDemo": { - "title": "使用Subscription方式", - "description": "使用Subscription方式控制loading的显示。", - "click": "click" - }, - "showLoadingDemo": { - "title": "使用showLoading控制", - "description": "使用showLoading的true或false控制loading的显示。", - "click me!": "clickme!", - "FirstName": "FirstName", - "LastName": "LastName", - "UserName": "UserName" - }, - "fullScreenDemo": { - "title": "服务方式调用", - "description": "使用服务的方式全屏加载loading组件或者在指定宿主上加载loading组件" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "custom-style": "自定义样式", - "multi-promise": "多promise", - "use-subscription-mode": "使用Subscription方式", - "show-loading": "使用showLoading控制", - "full-screen": "服务方式调用" - } - }, - "modal": { - "name": "Modal 模态弹窗", - "type": "反馈", - "path": "modal", - "description": "模态对话框。", - "tmw": "
    1. 需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。
    2. 弹窗起到与用户进行交互的作用,用户可以在对话框中输入信息、阅读提示、设置选项等操作。
    ", - "basicDemo": { - "title": "标准对话框", - "description": "使用dialogService可拖拽的标准对话框。" - }, - "customizeDemo": { - "title": "自定义对话框", - "description": "使用modalService可以自定义对话框内的所有内容。" - }, - "hideDemo": { - "title": "拦截对话框关闭", - "description": "通过 beforeHidden 设置在关闭弹出框时的拦截方法。" - }, - "tipsDemo": { - "title": "信息提示", - "description": "各种类型的信息提示框。" - }, - "warningDemo": { - "title": "警告弹出框", - "description": "标准警告弹出框。" - }, - "basicUpdateDemo": { - "title": "更新标准弹出框按钮状态", - "description": "通过update方法来更新dialog配置的buttons配置。" - }, - "autofocusDemo": { - "title": "配置按钮自动获得焦点", - "description": "配置dialogService的buttons中的autofocus属性可以设置按钮自动获得焦点,可以通过回车直接触发按钮点击。" - }, - "templateDemo": { - "title": "自定义弹出框内容模板", - "description": "支持传入contentTemplate属性来配置弹出框内容模板。" - }, - "templateFixedDemo": { - "title": "通过外层fixed同时避免滚动和抖动", - "description": "通过外层fixed同时避免滚动和抖动,在使用这种方式时,页面内所有fixed元素需要给定具体的位置值,使用默认定位值会导致位置偏移。" - }, - "anchorLinkValues": { - "standard-dialog": "标准对话框", - "custom-dialog": "自定义对话框", - "intercept-dialog-closed": "拦截对话框关闭", - "message-hint": "信息提示", - "warning-pop-up": "警告弹出框", - "update-button-options": "更新弹出框按钮状态", - "configure-button-to-get-focus-automatically": "配置按钮自动获得焦点", - "template-content": "配置弹出框内容模板", - "template-fixed": "通过外层fixed同时避免滚动和抖动" - } - }, - "pagination": { - "name": "Pagination 分页", - "type": "导航", - "path": "pagination", - "description": "分页器。", - "tmw": "当加载/渲染所有数据将花费很多时间时,可以切换页码浏览数据。", - "basicDemo": { - "title": "基本用法", - "description": "", - "Standard Size": "标准尺寸", - "Medium size": "中等尺寸", - "Large size": "大尺寸", - "Custom Style": "自定义样式", - "Set total to 0.": "设置total为0", - "Go to": "跳转至" - }, - "liteDemo": { - "title": "极简模式", - "description": "极简模式适用于一些有大量信息的页面,可以简化页面的复杂度。", - "Common Simplified Mode": "普通极简模式", - "Total number of records": "总条数", - "Set total to 0.": "设置total为0", - "Set total to 20.": "设置total为20", - "Set total to 30000.": "设置total为30000", - "Set total to 100000.": "设置total为100000", - "Set index to 2.": "设置index为2", - "Set index to 3.": "设置index为3", - "Ultra-simplified mode": "超极简模式", - "Setting drop-down menu with extensible settings": "带可拓展设置的设置下拉菜单", - "Display Field": "显示字段", - "Click Settings.": "点击设置", - "Display Mode": "显示方式" - }, - "widgetsDemo": { - "title": "多种配置", - "description": "支持设置输入跳转、显示跳转按钮;设置pageSize等功能。" - }, - "additionalDemo": { - "title": "特殊情况", - "description": "特殊场景下分页器的显示。", - "Set total to 0.": "设置total为0", - "Set total to 5.": "设置total为5", - "Set total to 15.": "设置total为15" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "minimalist-model": "极简模式", - "multiple-configurations": "多种配置", - "exceptional-case": "特殊情况" - } - }, - "panel": { - "name": "Panel 面板", - "type": "通用", - "path": "panel", - "description": "内容面板,用于内容分组。", - "tmw": "当页面内容需要进行分组显示时使用,一般包含头部、内容区域、底部三个部分。", - "basicDemo": { - "title": "基本用法" - }, - "typeDemo": { - "title": "多种类型", - "description": "面板类型分为default、primary、success,danger、warning、info。" - }, - "conditionChangeDemo": { - "title": "根据条件阻止折叠", - "description": "根据条件判断,当panel展开时,点击阻止折叠按钮,将无法折叠panel。当panel折叠时不影响操作。", - "Prevent Folding": "阻止折叠" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "multiple-types": "多种类型", - "condition-change": "根据条件阻止折叠" - } - }, - "popover": { - "name": "Popover 悬浮提示", - "type": "反馈", - "path": "popover", - "description": "简单的文字提示气泡框。", - "tmw": "用来通知用户非关键性问题或提示某控件处于某特殊情况。", - "basicDemo": { - "title": "基本用法" - }, - "manualDemo": { - "title": "手动控制显示", - "description": "通过visible控制弹框显示实现表单验证,使用visible控制必须令controlled参数为默认值false。", - "nameErrMsg": "输入长度不能小于4个字符!" - }, - "customizeDemo": { - "title": "基本用法", - "description": "支持传入HTMLElement或TemplateRef类型。", - "customizeTip": "自定义提示", - "isCustomizeTip": "这是一个自定义提示", - "customizeTipLink": "自定义提示,带链接", - "learnMore": "学习更多" - }, - "scrollElementDemo": { - "title": "父容器设置", - "description": "scrollElement配置,这里默认是 window,默认可以不传,只有当页面的滚动不在 window 上的时候才需要传递。" - }, - "hoverDelayTimeDemo": { - "title": "延时触发", - "description": "仅需要在 trigger 为 hover 的时候,鼠标移入的时长超过 [mouseEnterDelay] 毫秒之后才会触发,以防止用户无意划过导致的闪现,默认值是150毫秒;鼠标移出之后,再经过[mouseLeaveDelay]毫秒后,Popover组件才会隐藏,默认值是100毫秒。" - }, - "positionDemo": { - "title": "弹出位置", - "description": "总共支持12个弹出位置。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "manual-control-display": "手动控制显示", - "custom-prompt-content": "自定义提示内容", - "parent-container-settings": "父容器设置", - "hover-delay-time": "延时触发", - "position": "弹出位置" - } - }, - "progress": { - "name": "Progress 进度条", - "type": "数据展示", - "path": "progress", - "description": "进度条。", - "tmw": "
    1. 当操作需要较长的时间时,向用户展示操作进度。
    2. 当操作需要打断现有界面或后台运行,需要较长时间时。
    3. 当需要显示一个操作完成的百分比或已完成的步骤/总步骤时。
    ", - "basicDemo": { - "title": "基本用法", - "description": "基本的进度和文字配置。" - }, - "circleDemo": { - "title": "圆环用法", - "description": "基本的进度和文字配置。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "circle-usage": "圆环用法" - } - }, - "quadrant-diagram": { - "name": "Quadrant Diagram 象限图", - "type": "演进中", - "path": "quadrant-diagram", - "description": "象限图。", - "tmw": "根据需求对事务进行区域划分与价值排序,可用于管理事务的优先级。", - "basicDemo": { - "title": "基本用法" - }, - "customizeDemo": { - "title": "配置自定义象限图", - "description": "需要单独设置可放置的区域,将dropScope的值设置为'devui-quadrant-diagram'。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "custom-quadrant": "配置自定义象限图" - } - }, - "radio": { - "name": "Radio 单选框", - "type": "数据录入", - "path": "radio", - "description": "单选框。", - "tmw": "用户要从一个数据集中选择单个选项,且能并排查看所有可选项,选项数量在2~7之间时,建议使用单选按钮。", - "basicDemo": { - "title": "互相独立的单选项" - }, - "conditionChangeDemo": { - "title": "radio根据条件终止切换操作", - "description": "根据条件判断,第二项禁止跳转。" - }, - "conditionRadioGroupDemo": { - "title": "radio-group根据条件终止切换操作", - "description": "根据条件判断,第二个radio-group禁止跳转。" - }, - "disabledDemo": { - "title": "禁用" - }, - "horizontalDemo": { - "title": "横向排列" - }, - "verticalDemo": { - "title": "竖向排列" - }, - "customDemo": { - "title": "自定义单选项", - "description": "数组源可为普通数组、对象数组等。" - }, - "anchorLinkValues": { - "basic-usage": "互相独立的单选项", - "condition-change": "条件切换", - "condition-radio-group": "radio-group条件切换", - "disabled": "禁用", - "horizontal": "横向排列", - "vertical": "竖向排列", - "custom": "自定义单选项" - } - }, - "rate": { - "name": "Rate 等级评估", - "type": "数据展示", - "path": "rate", - "description": "等级评估。", - "tmw": "用户对一个产品进行评分时可以使用。", - "basicDemo": { - "title": "动态模式", - "currentStar": "当前有2颗星" - }, - "onlyReadDemo": { - "title": "只读模式" - }, - "customizeDemo": { - "title": "动态模式-自定义" - }, - "typeDemo": { - "title": "使用type参数" - }, - "anchorLinkValues": { - "read-only-mode": "只读模式", - "dynamic-mode": "动态模式", - "dynamic-mode-Custom": "动态模式-自定义", - "using-the-type-parameter": "使用type参数" - } - }, - "search": { - "name": "Search 搜索框", - "type": "通用", - "path": "search", - "description": "搜索框。", - "tmw": "当用户需要在数据集中搜索所需数据时,输入所需数据的内容(或部分内容),返回所有匹配内容的搜索结果。", - "basicDemo": { - "title": "基本用法", - "small": "小尺寸", - "middle": "标准尺寸", - "large": "大尺寸", - "disable": "禁用", - "searchLeft": "搜索图标左置", - "autoFoucs": "自动对焦", - "insertKey": "请输入关键字" - }, - "leftIconDemo": { - "title": "搜索图标左置" - }, - "ngModelDemo": { - "title": "双向绑定" - }, - "autoFocusDemo": { - "title": "自动对焦" - }, - "no-borderDemo": { - "title": "无边框" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "bidirectional-binding": "双向绑定", - "icon-left": "搜索图标左置", - "auto-focus": "自动对焦", - "search-no-border": "无边框" - } - }, - "select": { - "name": "Select 下拉选择框", - "type": "数据录入", - "path": "select", - "description": "下拉选择框。", - "tmw": "用户可以从多个选项中选择一项或几项;仅支持用户在下拉选项中选择和搜索系统提供的选项,不支持输入。", - "SelectBasicDemo": { - "title": "基本用法", - "description": "通过options配置数据源 通过 overview、size 配置样式 通过 direction 配置展开方向。", - "Large size": "大尺寸", - "Standard Size": "标准尺寸", - "Small size": "小尺寸", - "Option": "选项", - "New Option": "新增选项", - "Asynchronous option 1": "异步选项1" - }, - "CustomSearchDemo": { - "title": "自定义搜索功能", - "description": "通过isSearch、searchFn开启搜索功能并自定搜索方法,searchPlaceholder定义搜索框显示文字 通过 multiple 启用多选功能。", - "Single-choice custom search method": "单选自定搜索方法", - "Search My Options": "搜索我的选项", - "Multi-choice self-defined search method": "多选自定搜索方法", - "Select at least three options.": "请至少选择三个选项", - "Option": "选项" - }, - "SelectAllDemo": { - "title": "全选下拉选项", - "description": "多选下拉中通过isSelectAll启用全选功能。", - "Current Select": "Current Select", - "Option": "选项" - }, - "SelectTemplateDemo": { - "title": "自定义模板", - "description": "通过模板配置下拉选项和已选项。", - "Single choice": "单选", - "Use templates only for lists": "只在列表使用模板", - "Use the same template in the list and selected items": "在列表和选中项使用相同模板", - "Use different templates in lists and selected items": "在列表和选中项使用不同模板", - "Multiple Choices": "多选", - "Use different templates for the list and selected items. Use built-in templates in some cases.": "在列表和选中项使用不同模板,某些情况下使用内置模板" - }, - "AllowClearValueDemo": { - "title": "允许清空值", - "description": "", - "test": "选项" - }, - "CustomAreaDemo": { - "title": "自定义区域", - "description": "使用customViewTemplate定义自定义区域。", - "Custom Area": "自定义区域", - "Selected xx items": "已选xx项", - "Option": "选项" - }, - "CustomAreaDirectionDemo": { - "title": "自定义区域方向和选中", - "description": "", - "Customizing Area Orientation and Selecting": "自定义区域方向和选中", - "Customize the region and change the width alignment by appendToBody.": "自定义区域和通过appendToBody改变宽度对齐", - "Recent Selections": "最近选择", - "Option": "选项" - }, - "AppendToBodyDemo": { - "title": "附着到Body上", - "description": "使用appendToBody使得附着到body上,不被带滚动条的容器遮挡。", - "Select from the drop-down list box": "下拉选择", - "Option": "选项" - }, - "DisabledDemo": { - "title": "禁用", - "description": "通过disabled禁用下拉,通过选项对象的$disabled禁用选项,通过选项对象的$immutable禁止修改选项。", - "Disable All": "全部禁用", - "Disable an item": "禁用某一项", - "Disable an item, Tags cannot be operated independently. You can select or deselect all tags.": "禁用某一项,标签不可单独操作,全选仍可以选中和取消", - "Disable an item, Use immutable to disable changes. Select all and deselect all.": "禁用某一项,使用immutable禁止变更,全选不可选中和取消", - " The immutable parameter cannot be changed and is not displayed as disabled. To disable the immutable parameter, use the disabled parameter.": "immutable只控制不能变更,不会显示为禁用状态,禁用状态请使用disabled。", - "Option": "选项" - }, - "LabelizationDemo": { - "title": "标签化", - "description": "通过extraConfig.labelization配置标签化:1.enable为true时启用,已选项显示为可删除的标签 2.overflow配置超长的样式,具体参考api。", - "Extra-long line feed": "超长换行", - "Change default": "改变默认值", - "Current Select": "当前选中", - "Overlong single line, vertical scroll bar": "超长单行、出现竖向滚动条", - "Maximum width of a tag in an ultra-long row.": "超长单行,配置标签的最大宽度", - "This is an extra long option.": "这是一个超长的选项", - "Option": "选项" - }, - "ObjectFilterDemo": { - "title": "使用对象", - "description": "使用对象数组,通过filterKey配置对象显示字段。", - "Current Select": "CurrentSelect", - "Option": "选项", - "Search": "Search" - }, - "LazyLoadVirtualScrollDemo": { - "title": "虚拟滚动或懒加载", - "description": "使用virtualScroll在大数据量下用虚拟滚动;使用 enableLazyLoad 在大数据量下用懒加载。", - "Virtual scrolling": "虚拟滚动", - "Scroll to the bottom lazy loading data": "滚动到底部懒加载数据", - "Scroll to the bottom to lazy load data using a custom loading template": "滚动到底部使用自定义loading模板懒加载数据", - "Option": "选项", - "Asynchronous Options": "异步选项", - "Test": "Test" - }, - "LoadingDemo": { - "title": "异步加载显示加载中", - "description": "", - "Lazy loading: Change the options mode.": "懒加载:改变options方式", - "Lazy loading: The searchFn mode is used.": "懒加载:使用searchFn方式", - "Option": "选项" - }, - "UserLimitSelectedNumberDemo": { - "title": "用户场景:限制选中个数", - "description": "", - "maxselectnumber:2,disabled:1": "maxselectnumber:2,disabled:1", - "Option": "选项" - }, - "MultiKeepOrderDemo": { - "title": "设置已选项顺序源数组顺序或选中顺序", - "description": "通过keepMultipleOrder配置多选的时候已选项维持原数组顺序:'origin'源数组排序,'user-select'用户选择顺序排序。", - "Current Selec": "Current Select", - "Option": "选项" - }, - "UserSearchNLazyLoadDemo": { - "title": "用户场景:自定义搜索的懒加载", - "description": "", - "Search and lazy loading are used together.": "搜索和懒加载同时使用", - "Current Select": "Current Select", - "This is a longer option for testing.": "这是一个用来测试的比较长的选项", - "Option": "选项", - "New Option": "新增选项" - }, - "UserMailSearchDemo": { - "title": "用户场景:自定义搜索和模板结合邮箱搜索", - "description": "", - "Search by name or email address": "搜索支持名字和邮箱搜索", - "Name:": "名称:", - "E-mail address:": "邮箱:", - "Option": "选项" - }, - "ModelValueDemo": { - "title": "ngModel值处理", - "description": "", - "Current Select": "CurrentSelect", - "Option": "选项" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "object-filter": "使用对象", - "custom-search": "自定义搜索功能", - "select-all": "全选下拉选项", - "select-template": "自定义模板", - "labelization": "标签化", - "disabled": "禁用", - "allow-clear-value": "允许清空值", - "append-to-body": "附着到Body上", - "lazy-load-virtual-scroll": "虚拟滚动 或 懒加载", - "async-loading": "异步加载显示加载中", - "custom-area": "自定义区域", - "custom-area-direction": "自定义区域方向和选中", - "multi-keep-order": "设置已选项顺序源数组顺序或选中顺序", - "user-limit-selected-number": "用户场景:限制选中个数", - "user-search-n-lazyload": "用户场景:自定义搜索的懒加载", - "user-mail-search": "用户场景:自定义搜索和模板结合 —— 邮箱搜索", - "model-value": "ngModel值处理" - } - }, - "cascader": { - "name": "Cascader 级联菜单", - "type": "演进中", - "path": "cascader", - "description": "下拉级联菜单。", - "tmw": "
    1. 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。
    2. 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。
    ", - "basicDemo": { - "hoverMode": "hover展开模式", - "select": "请选择", - "clickMode": "click展开模式", - "empty": "数据为空", - "title": "基本用法", - "disableMode": "禁用模式" - }, - "lazyloadDemo": { - "loadChildren": "点击加载子菜单", - "title": "点击加载子菜单", - "select": "请选择" - }, - "multipleDemo": { - "title": "多选模式", - "multiple": "多选模式", - "select": "请选择" - }, - "parentSelectDemo": { - "title": "父级可选择", - "description": "该模式下可点击选择非叶子节点,在多选模式下,可以通过checkboxRelation选择checkbox的父子状态联动方式。", - "single": "单选", - "dependence": "多选父子独立", - "select": "请选择", - "relationDownward": "多选向子项关联", - "relationUpward": "多选向父项关联" - }, - "searchDemo": { - "title": "搜索模式", - "singleSearch": "单选搜索", - "multipleSearch": "多选搜索", - "select": "请选择" - }, - "templateDemo": { - "title": "模板类型", - "templateMode": "模板类型", - "select": "请选择", - "custom": "自定义" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "multiple-cascader": "多选类型", - "search-cascader": "搜索类型", - "parent-cascader": "父级可选", - "template-cascader": "模板类型", - "lazyload-cascader": "点击加载" - } - }, - "status": { - "name": "Status 状态", - "type": "通用", - "path": "status", - "description": "传达交互结果的组件。", - "tmw": "表示一个任务的执行结果时使用。", - "basicDemo": { - "title": "基本用法", - "Succeeded": "成功", - "erroneous": "错误", - "warnings": "警告", - "Initialize": "初始化", - "Waiting": "等待", - "running": "运行", - "Invalid": "无效" - }, - "anchorLinkValues": { - "basic-usage": "基本用法" - } - }, - "sticky": { - "name": "Sticky 便贴", - "type": "通用", - "path": "sticky", - "description": "便签组件。", - "tmw": "当用户在滚动屏幕时,需要某个区域内容在段落或者浏览器可视区域可见时。", - "basicDemo": { - "title": "基本用法", - "Global Text": "全局文本,需要更改容器为滚动条所在容器。出现后,可以一直贴着屏幕顶部。", - "Global Button": "全局按钮", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。", - "Tips": "小贴士", - "page-roll": "滚动页面的时候,sticky会随着滚动。", - "para-roll": "段落滚动到的时候,sticky会跟着被托走。", - "view": "view可以调整视窗的顶部和底部,比如顶部被固定导航块覆盖时候,应将top的值置为导航的高度。", - "container": "container可以切换判断滚动状态的容器。" - }, - "scrollTargetDemo": { - "title": "更换滚动容器", - "description": "可以通过设置scrollTarget来更改滚动容器。", - "Global Text": "全局文本,需要更改容器为滚动条所在容器。出现后,可以一直贴着屏幕顶部。", - "Global Button": "全局按钮", - "base-info": "基本信息", - "issue-list": "需求列表", - "case-list": "用例列表", - "quarlity-result": "质量评估", - "The basic information is displayed.": "这里显示基本信息。", - "The requirement list is displayed.": "这里显示需求列表。", - "The test case list is displayed.": "这里显示用例列表。", - "The quality assessment is displayed here.": "这里显示质量评估。", - "Tips": "小贴士", - "page-roll": "滚动页面的时候,sticky会随着滚动。", - "para-roll": "段落滚动到的时候,sticky会跟着被托走。", - "view": "view可以调整视窗的顶部和底部,比如顶部被固定导航块覆盖时候,应将top的值置为导航的高度。", - "container": "container可以切换判断滚动状态的容器。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "scroll-target": "更换滚动容器" - } - }, - "tabs": { - "name": "Tabs 选项卡切换", - "type": "导航", - "path": "tabs", - "description": "选项卡切换组件。", - "tmw": "用户需要通过平级的区域将大块内容进行收纳和展现,保持界面整洁。", - "basicDemo": { - "title": "基本用法", - "description": "", - "Here's what Tab1 says.": "这是Tab1的内容", - "This is Tab2.": "这是Tab2的内容", - "This is Tab3.": "这是Tab3的内容" - }, - "withoutContentDemo": { - "title": "禁用选项卡", - "description": "", - "activeID:": "activeID:" - }, - "customDemo": { - "title": "自定义模板", - "description": "", - "Here's what Tab1 says.": "这是Tab1的内容", - "This is Tab2.": "这是Tab2的内容", - "This is Tab3.": "这是Tab3的内容" - }, - "configDemo": { - "title": "配置类型与排列", - "description": "", - "Here's what Tab1 says.": "这是Tab1的内容", - "This is Tab2.": "这是Tab2的内容", - "This is Tab3.": "这是Tab3的内容", - "Vertical arrangement:": "竖向排列:", - "Option tabs:": "Optiontabs:", - "Optiontabswithfixwidth100px:": "Optiontabswithfixwidth100px:" - }, - "beforeChangeDemo": { - "title": "拦截tab切换", - "description": "使用beforeChange拦截tab切换。", - "Here's what Tab1 says.": "这是Tab1的内容", - "This is Tab2.": "这是Tab2的内容", - "This is Tab3.": "这是Tab3的内容" - }, - "configurableTabsDemo": { - "title": "自定义Tabs显示与排列", - "description": "通过引入transfer组件,实现tabs的自定义显示。", - "activeID:": "activeID:" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "no-set-content": "禁用选项卡", - "custom-template": "自定义模板", - "configuration-type-and-arrangement": "配置类型与排列", - "intercept-tab-switch": "拦截tab切换", - "custom-tabs-display-and-arrangement": "自定义Tabs显示与排列" - } - }, - "tags": { - "name": "Tags 标签", - "type": "数据展示", - "path": "tags", - "description": "标签展示组件。", - "tmw": "用户需要展示多个标签时。", - "customDemo": { - "title": "单个标签", - "description": "通过labelStyle属性定义标签样式。" - }, - "basicDemo": { - "title": "标签组", - "description": "标签组可传入字符串数组或对象数组,在对象数组中,可通过displayProperty,titleProperty设置标签显示值和title显示值,通过labelStyle设置标签样式。" - }, - "anchorLinkValues": { - "single-tag": "单个标签", - "tags-group": "标签组" - } - }, - "tags-input": { - "name": "TagsInput 标签输入", - "type": "数据录入", - "path": "tags-input", - "description": "输入标签组件。", - "tmw": "当用户需要输入多个标签时。", - "basicDemo": { - "title": "基本用法" - }, - "asyncDemo": { - "title": "异步数据源" - }, - "ngmodelDemo": { - "title": "双向绑定" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "ng-model": "双向绑定", - "async-input": "异步数据源" - } - }, - "time-axis": { - "name": "Time Axis 时间轴", - "type": "数据展示", - "path": "time-axis", - "description": "时间轴展示组件。", - "tmw": "当需要向用户展示时间进度和每个时间点的事件状态时。", - "allStatesDemo": { - "timeLeft": "时间点在左侧", - "timeBottom": "时间点在底部", - "title": "基本用法", - "description": "通过 position 配置时间点位置。" - }, - "directionDemo": { - "title": "设置方向", - "description": "通过 direction 配置时间线排列方向。" - }, - "templateDemo": { - "description": "描述。", - "title": "内容使用模板自定义" - }, - "htmlContentDemo": { - "title": "内容使用html" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "direction": "设置方向", - "content-with-html": "内容使用html", - "content-with-template": "内容使用模板自定义" - } - }, - "toast": { - "name": "Toast 全局通知", - "type": "反馈", - "path": "toast", - "description": "全局信息提示组件。", - "tmw": "当需要向用户全局展示提示信息时使用,显示数秒后消失。", - "basicDemo": { - "title": "基本用法", - "description": "common时不展示图标。" - }, - "lifeDemo": { - "title": "超时时间", - "description": "当设置超时时间、没有标题时,则不展示标题和关闭按钮。" - }, - "singleDemo": { - "title": "每个消息使用单独的超时时间", - "description": "当设置超时时间模式为single时,每个消息使用自身的life作为超时时间,如果未设置则按severity判断,severity也未设置时默认超时时间为5000毫秒。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "life": "超时时间", - "single": "每个消息使用单独的超时时间" - } - }, - "tooltip": { - "name": "Tooltip 提示", - "type": "反馈", - "path": "tooltip", - "description": "文字提示组件。", - "tmw": "用户鼠标移动到文字上,需要进一步的提示时使用。", - "basicDemo": { - "title": "基本用法" - }, - "delayDemo": { - "title": "延时触发", - "description": "鼠标移入的时长超过 [mouseEnterDelay] 毫秒之后才会触发,以防止用户无意划过导致的闪现,默认值是150毫秒;鼠标移出之后,再经过[mouseLeaveDelay]毫秒后,toolTip组件才会隐藏,默认值是100毫秒。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "delay-trigger": "延时触发" - } - }, - "read-tip": { - "name": "ReadTip 阅读提示", - "type": "反馈", - "path": "read-tip", - "description": "阅读提示组件。", - "tmw": "当html文档中需要对特定内容进行提示时使用。", - "basicDemo": { - "title": "基本用法", - "description": "通过设置selector选择需要显示readtip的元素,传入title和content设置显示的内容。" - }, - "multiDemo": { - "title": "包括多个提示的readtip", - "description": "传入多个rule,设置不同元素的readtip显示模式。" - }, - "templateDemo": { - "title": "传入模板显示内容", - "description": "可以通过传入template自定义需要显示的内容,传入template时不必再传入title和content。" - }, - "asyncDemo": { - "title": "异步获取数据" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "multi-usage": "包括多个提示的readtip", - "template-usage": "传入模板显示内容", - "async-usage": "异步获取数据" - } - }, - "toggle": { - "name": "Toggle 开关", - "type": "数据录入", - "path": "toggle", - "description": "开/关切换组件。", - "tmw": "当两种状态需要来回切换控制时,比如启用/禁用。", - "basicDemo": { - "title": "基本用法", - "basic": "基本样式", - "disable": "禁用状态", - "large": "自定义样式(大尺寸)", - "sure": "确定", - "cancel": "取消" - }, - "twoBindingDemo": { - "title": "双向绑定" - }, - "callbackDemo": { - "title": "回调事件" - }, - "customDemo": { - "title": "自定义样式" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "two-binding": "双向绑定", - "callback": "回调事件", - "custom": "自定义样式" - } - }, - "tree": { - "name": "Tree 树", - "type": "数据展示", - "path": "tree", - "description": "一种表现嵌套结构的组件。", - "tmw": "文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。", - "basicDemo": { - "title": "基本用法", - "description": "渲染一棵基本树。", - "Parent node": "父节点", - "unfold": "展开", - "Leaf node": "叶子节点", - "No child node": "没有子节点", - "Dynamic loading": "动态加载", - "folding": "折叠" - }, - "checkControlDemo": { - "title": "控制父子check关系", - "description": "通过OperableTree的 checkableRelation 控制check时父子节点的表现。", - "Parent node": "父节点", - "unfold": "展开", - "Leaf node": "叶子节点", - "No child node": "没有子节点", - "Dynamic loading": "动态加载", - "folding": "折叠" - }, - "treeFactoryDemo": { - "title": "常用treeFactory函数", - "description": "" - }, - "checkableDemo": { - "title": "可勾选树", - "description": "可以进行勾选的树。", - "Subnode": "子节点", - "Parent node": "父节点" - }, - "customLoadingDemo": { - "title": "自定义loading模板", - "Leaf node": "叶子节点", - "No child node": "没有子节点", - "Dynamic loading": "动态加载", - "Parent node": "父节点", - "unfold": "展开", - "folding": "折叠" - }, - "customTitleKeyDemo": { - "title": "自定显示字段", - "description": "通过设置treeNodeTitleKey,自定义树中显示和搜索的关键字。", - "Leaf node": "叶子节点", - "No child node": "没有子节点", - "Parent node": "父节点", - "unfold": "展开", - "folding": "折叠" - }, - "customizeDemo": { - "title": "自定义图标", - "description": "自定义操作按钮图标、节点图标。", - "Parent node": "父节点", - "Subnode": "子节点", - "Status": "状态" - }, - "draggableDemo": { - "title": "可拖拽树", - "description": "通过OperableTree的 draggable 属性配置节点的拖拽功能,并支持外部元素拖拽入树。", - "Parent node": "父节点", - "Subnode": "子节点", - "external dragable element": "外部可拖动元素" - }, - "mergeNodeDemo": { - "title": "合并节点", - "description": "当节点下只有一个子节点时,合并该节点。", - "Parent node": "父节点", - "Leaf node": "叶子节点" - }, - "operateBtnDemo": { - "title": "操作按钮", - "description": "可定义外部操作按钮、虚浮按钮。", - "Parent node": "父节点", - "Subnode": "子节点" - }, - "searchFilterDemo": { - "title": "搜索过滤", - "description": "通过treeFactory中的searchTree方法可以搜索节点或者过滤节点。", - "Parent node": "父节点", - "Subnode": "子节点" - }, - "virtualScrollDemo": { - "title": "大数据量下的可操作树", - "description": "使用虚拟滚动处理大数据量的加载问题,同时处理大数据量操作耗时长卡顿的问题。", - "Parent node": "父节点", - "Try dynamic lazy loading": "试试动态懒加载", - "Subnode": "子节点", - "Parent node with 1000 child nodes": "拥有1000子节点的父节点", - "Node loading": "节点加载", - "Subnode loading": "子节点加载", - "I'm an extra data ID.": "我是额外数据id", - "I'm an extra data name.": "我是额外的数据名称", - "New node": "新节点", - "Add a node.": "新增一个节点", - "Leaf node": "叶子节点", - "unfold": "展开" - }, - "withoutAnimationDemo": { - "title": "无动画", - "description": "通过showAnimation设置是否展示动画。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "merge-node": "合并节点", - "custom-loading": "自定义loading模板", - "custom-display-field": "自定显示字段", - "checkable-tree": "可勾选树", - "operation-button": "操作按钮", - "search-filtering": "搜索过滤", - "custom-icon": "自定义图标", - "drag-and-drop-tree": "可拖拽树", - "check-control-tree": "控制父子check关系", - "tree-factory": "常用treeFactory函数", - "virtual-scroll": "大数据量可操作树", - "without-animation": "无动画" - } - }, - "typography": { - "name": "Typography 文字排版", - "type": "演进中", - "path": "typography", - "description": "文字排版。", - "tmw": "当需要对标题、段落、帮助文字进行排版时。", - "titleDemo": { - "title": "标题用法", - "description": "通过d-title标签定义标题样式。" - }, - "textDemo": { - "title": "文本用法", - "description": "通过d-text标签定义文本样式。" - }, - "customizeDemo": { - "title": "自定义用法", - "description": "自定义编辑时的显示模板。" - }, - "anchorLinkValues": { - "title-usage": "标题用法", - "text-usage": "文本用法", - "custom-usage": "自定义用法" - } - }, - "upload": { - "name": "Upload 上传", - "type": "数据录入", - "path": "upload", - "description": "文件上传组件。", - "tmw": "当需要将文件上传到后端服务器时。", - "basicDemo": { - "title": "基本用法", - "description": "单文件上传、拖动文件上传、ngModel双向绑定、禁止上传。", - "singleText": "单文件", - "clickToUpload": "点击上传", - "dragable": "单文件支持拖动上传", - "dragToUpload": "请拖动文件上传", - "auto": "自动上传", - "disabled": "禁止上传" - }, - "multiDemo": { - "title": "多文件上传", - "description": "多文件上传,支持拖动文件上传、禁止上传。", - "multiText": "多文件上传", - "dragable": "多文件支持拖动上传", - "multiList": "多文件列表展示", - "disabled": "多文件上传禁止" - }, - "autoDemo": { - "title": "自动上传", - "description": "通过autoUpload设置自动上传。" - }, - "customizeDemo": { - "title": "自定义", - "description": "自定义上传按钮,通过preloadFilesRef设置已选择文件列表模板,通过uploadedFilesRef设置已上传文件列表模版。" - }, - "dynamicDemo": { - "title": "动态上传参数", - "description": "用户可通过beforeUpload动态修改上传参数。", - "text": "上传前动态修改上传参数" - }, - "areaDemo": { - "title": "任意区域上传", - "description": "用户可通过dUpload指令支持文件任意区域上传。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "multi-files": "多文件上传", - "auto-upload": "自动上传", - "custom": "自定义", - "dynamic-upload-options": "动态上传参数", - "customize-area-upload": "任意区域上传" - } - }, - "input-number": { - "name": "InputNumber 数字输入框", - "type": "数据录入", - "path": "input-number", - "description": "数字输入框组件。", - "tmw": "当需要获取标准数值时。", - "basicDemo": { - "title": "基本用法", - "description": "传入size可定制大小。" - }, - "disabledDemo": { - "title": "禁止输入态", - "description": "当 disabled 为 true 的时候是禁止用户输入的状态。" - }, - "emptyDemo": { - "title": "允许空值", - "description": "当 allowEmpty 为 true 的时候允许输入框的值为空,空值返回为 null ,传入数据可以为 undefined 或 null。" - }, - "placeholderAndMaxLengthDemo": { - "title": "设置placeholder和最大长度", - "description": "可传入placeholder提示,也可以使用maxLength限制最大输入长度。" - }, - "regDemo": { - "title": "正则限制", - "description": "允许传入正则或正则字符串限制输入,输入时会优先匹配传入的正则,不输入则不限制。" - }, - "decimalLimitDemo": { - "title": "限制小数", - "Limit Decimal": "限制小数" - }, - "anchorLinkValues": { - "number-basic": "基本用法", - "number-disabled": "禁止输入态", - "number-empty": "允许空值", - "number-placeholder-maxlength": "设置placeholder和最大长度", - "number-reg": "正则限制", - "decimal-limit": "限制小数" - } - }, - "tree-select": { - "name": "TreeSelect 树形选择框", - "type": "数据录入", - "path": "tree-select", - "description": "树形选择框。", - "tmw": "文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。", - "basicDemo": { - "title": "基本用法", - "description": "", - "Standard: Single Select": "Standard:SingleSelect", - "Standard: Multiple Select": "Standard:MultipleSelect", - "Custom Width: Single Select": "CustomWidth:SingleSelect", - "Disabled: Single Select": "Disabled:SingleSelect" - }, - "labelizationDemo": { - "title": "标签化配置", - "description": "", - "Standard: Single Select": "Standard:SingleSelect", - "Standard: Multiple Select": "Standard:MultipleSelect", - "AllowClear:SingleSelect(allowUnselectparametermustbetrueandenablelabelizationDemomustbefalse, whichisthedefaultvalue)": "AllowClear:SingleSelect(allowUnselectparametermustbetrueandenablelabelizationDemomustbefalse,whichisthedefaultvalue)", - "Standard: Multiple Select(Disabled)": "Standard:MultipleSelect(Disabled)" - }, - "leafOnlyDemo": { - "title": "仅叶节点可选", - "description": "", - "Leaf Only: Single Select": "LeafOnly:SingleSelect", - "Leaf Only: Multiple Select": "LeafOnly:MultipleSelect" - }, - "hooksDemo": { - "title": "初始化完成时调用的钩子", - "description": "", - "Open on init: Single Select": "Open on init: Single Select" - }, - "searchableDemo": { - "title": "可简易搜索树", - "description": "", - "Standard: Single Select": "Standard: Single Select", - "Standard: Multiple Select": "Standard: Multiple Select" - }, - "appendToDemo": { - "title": "Append To Element 能力", - "description": "", - "Standard: Single Select Append To Body": "Standard: Single Select Append To Body", - "Standard: Multiple Select Append To Body": "Standard: Multiple Select Append To Body", - "Custom Width: Single Select Append To Body": "Custom Width: Single Select Append To Body", - "click me!": "clickme!" - }, - "customIconDemo": { - "title": "自定义icon能力", - "description": "", - "Standard: iconTemplatePosition": "Standard: iconTemplatePosition", - "Standard: iconTemplateInput": "Standard: iconTemplateInput" - }, - "keysDemo": { - "title": "自定义key", - "description": "", - "Standard: treeNodeIdKey": "Standard: treeNodeIdKey", - "Standard: treeNodeChildrenKey": "Standard: treeNodeChildrenKey", - "Standard: treeNodeTitleKey": "Standard: treeNodeTitleKey" - }, - "customTemplateDemo": { - "title": "自定义区域", - "description": "使用customViewTemplate定义自定义区域,customViewDirection自定义方向,在自定义区域使用let-selectComponent的值。" - }, - "iconParentDemo": { - "title": "自定义节点展开关闭图标", - "description": "", - "Standard: iconParent": "Standard: iconParent" - }, - "virtualScrollDemo": { - "title": "虚拟滚动" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "labelization": "标签化配置", - "leaf-only": "仅叶节点可选", - "init-hooks": "初始化完成时调用的钩子", - "simple-search": "可简易搜索树", - "append-to-element": "Append To Element 能力", - "custom-icon": "自定义icon能力", - "keys": "自定义key", - "custom-template": "自定义区域", - "icon-parent": "展开关闭icon", - "virtual-scroll": "虚拟滚动" - } - }, - "slider": { - "name": "Slider 滑动输入条", - "type": "数据录入", - "path": "slider", - "description": "滑动输入条。", - "tmw": "当用户需要在数值区间内进行选择时使用。", - "basicDemo": { - "title": "基本用法", - "ngModel": "双向绑定", - "stepLimit": "限制步长" - }, - "disabledDemo": { - "title": "禁止输入态", - "description": "当 disabled 为 true 的时候是禁止用户输入的状态。" - }, - "customDemo": { - "title": "异定制Popover的显示内容", - "description": "通过 tipsRenderer 参数传入函数定制Popover内的显示内容。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "slider-disabled": "禁止输入态", - "slider-formatter": "异定制Popover的显示内容" - } - }, - "splitter": { - "name": "Splitter 分割器", - "type": "布局", - "path": "splitter", - "description": "页面分割器。", - "tmw": "需要动态调整不同页面布局区域大小的时候选择使用。", - "basicDemo": { - "title": "基本用法", - "leftPane": "左侧面板", - "leftPaneContent": "左侧内容区域,宽度30%, 最小宽度20%", - "rightPane": "右侧面板", - "rightPaneContent": "右侧内容区域" - }, - "verticalDemo": { - "title": "垂直布局用法", - "topPane": "上面板", - "topPaneContent": "高度200px", - "midPane": "中间面板", - "midPaneContent": "高度自适应", - "bottomPane": "下面板", - "bottomPaneContent": "高度100px, 不可调节" - }, - "combineDemo": { - "title": "组合布局用法", - "leftPane": "左侧面板", - "leftPaneContent": "左侧内容区域,宽度30%, 最小宽度20%", - "topPane": "顶部面板", - "topPaneContent": "高度50%", - "bottomPane": "底部面板", - "bottomPaneContent": "高度自适应", - "bottomPane2": "底部面板", - "bottomPaneContent2": "高度自适应" - }, - "directionDemo": { - "title": "指定折叠收起方向", - "leftPane": "左侧面板", - "leftPaneContent": "左侧内容区域,宽度30%, 最小宽度20%", - "midPane": "中间面板", - "midPaneContent": "中间内容区域, 指定折叠收起方向为向前收起", - "rightPane": "右侧面板", - "rightPaneContent": "右侧内容区域" - }, - "shrinkDemo": { - "title": "折叠收缩显示菜单", - "rightPane": "右侧面板", - "rightPaneContent": "右侧内容区域", - "content1": "内容一", - "childContent1": "子内容1", - "childContent2": "子内容2", - "childContent3": "子内容3", - "content2": "内容二", - "content3": "内容三", - "content4": "内容四", - "content5": "内容五" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "vertical-layout": "垂直布局用法", - "combine-layout": "组合布局用法", - "certain-unfold-direction": "指定折叠收起方向", - "shrink-show-menu": "折叠收缩显示菜单" - } - }, - "layout": { - "name": "Layout 布局", - "type": "布局", - "path": "layout", - "description": "页面的布局方式。", - "tmw": "当用户需要直接使用一些既有布局时。", - "basicDemo": { - "title": "基本用法" - }, - "appDemo1": { - "title": "应用场景1", - "description": "常用上中下布局。" - }, - "appDemo2": { - "title": "应用场景2", - "description": "常用上中下布局及侧边栏布局。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "application-scenario1": "应用场景1", - "application-scenario2": "应用场景2" - } - }, - "gantt": { - "name": "Gantt 甘特图", - "type": "演进中", - "path": "gantt", - "description": "甘特图。", - "tmw": "当用户需要通过条状图来显示项目,进度和其他时间相关的系统进展的内在关系随着时间进展的情况时。", - "basicDemo": { - "title": "基本用法", - "description1": "d-gantt-scale(时间轴)容器作为时间轴标线的定位父级元素,须设置position或者是table、td、th、body元素。", - "description2": "d-gantt-scale(时间轴)容器和d-gantt-bar(时间条)容器宽度须通过GanttService提供的方法根据起止时间计算后设置,初始化之后还须订阅ganttScaleConfigChange动态设置。", - "description3": "时间条move、resize事件会改变该时间条起止时间和时间轴的起止时间,订阅时间条resize、move事件和ganttScaleConfigChange来记录变化。", - "description4": "响应时间条move、resize事件调整最外层容器的滚动以获得更好的体验。" - }, - "withDataDemo": { - "title": "与datatable组件结合的甘特图" - }, - "anchorLinkValues": { - "gantt-basic": "基本用法", - "gantt-in-datatable": "与datatable组件结合的甘特图" - } - }, - "text-input": { - "name": "Text-input 文本框", - "type": "数据录入", - "path": "text-input", - "description": "文本输入框。", - "tmw": "需要手动输入文字使用。", - "basicDemo": { - "title": "基本用法", - "placeholder": "请输入内容" - }, - "passwordVisibleDemo": { - "title": "密码框" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "password-input": "密码框" - } - }, - "textarea": { - "name": "Textarea 多行文本框", - "type": "数据录入", - "path": "textarea", - "description": "文本输入区域。", - "tmw": "需要手动输入文字,并且文字内容较多时使用。", - "basicDemo": { - "title": "基本用法", - "placeholder": "请输入内容" - }, - "resizeDemo": { - "title": "调整大小", - "placeholder": "请输入内容" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "resize": "调整大小" - } - }, - "steps-guide": { - "name": "StepsGuide 操作指引", - "type": "导航", - "path": "steps-guide", - "description": "引导用户了解业务使用逻辑组件。", - "tmw": "业务推出新特性,或复杂的业务逻辑需要指引用户时使用。", - "basicDemo": { - "title": "基本用法", - "description": "设定一组操作指引信息顺序显示。", - "Current Step": "当前步骤", - "Operation Output": "操作输出" - }, - "customDemo": { - "title": "自定义", - "description": "自定义操作指引信息弹出的位置和元素。" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "custom": "自定义" - } - }, - "polyfill": { - "name": "Polyfills 腻子脚本", - "type": "扩展服务", - "path": "polyfill", - "description": "用于实现一些低版本浏览器(主要是IE)不支持的API。", - "tmw": "需要解决低版本浏览器不支持的方法时。", - "basicDemo": { - "title": "使用方法", - "description": "目前由于实现方法较少,且主要供富文本组件使用,因此当前腻子脚本文件存放于富文本模块下。 使用时,devcloud 项目或 Angular cli 创建的项目可以在 src/polyfills.ts 中插入:import 'ng-devui/add-ons/editorx/polyfill'; 由于腻子脚本只是一段独立执行的js代码,也可以直接用静态资源的方式插入页面来使用。", - "name": "腻子脚本", - "license": "授权方式", - "size": "大小", - "browser": "浏览器", - "des": "描述", - "remove": "把对象从它所属的 DOM 树中删除", - "matches": "判断是否匹配指定选择器字符串,各低版本浏览器分别实现了带有自身前缀的MatchesSelector方法,比如 msMatchesSelector", - "closest": "匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)", - "event": "在 DOM 中出现的事件", - "forEach": "顺序遍历节点的集合的方法" - }, - "anchorLinkValues": { - "basic-usage": "使用方法" - } - }, - "time-picker": { - "name": "TimePicker 时间选择器", - "type": "演进中", - "path": "time-picker", - "description": "输入或选择时间的控件。", - "tmw": "当用户需要输入一个时间,可以点击标准输入框,弹出面板进行选择。", - "basicDemo": { - "basic": "基本用法", - "defaultValue": "设置初始赋值,默认打开", - "setDisable": "设置disabled", - "title": "基本用法" - }, - "customDemo": { - "template": "传入模板", - "chooseNow": "选择现在", - "chooseTime": "选择22点", - "title": "传入模板" - }, - "formatDemo": { - "setting": "设置format、最大值和最小值", - "title": "格式化、最大值和最小值" - }, - "anchorLinkValues": { - "basic-usage": "基本用法", - "format": "格式化", - "custom": "传入模板" - } - }, - "relative-time": { - "name": "RelativeTime 人性化时间转换", - "type": "数据展示", - "path": "relative-time", - "description": "相对时间。", - "tmw": "需要通过当前时间来显示相对时间时使用。", - "basicDemo": { - "beforeTrans": "转换前", - "afterTrans": "转换后", - "title": "转换示例", - "description": "引入RelativeTimeModule,使用dRelativeTime管道转换日期。" - }, - "customDemo": { - "title": "自定义比较时间示例", - "description": "不与当前时间作比较,自定义比较时间,如下与'2015-5-20 12:00:00'时间作比较。" - } - } - } -} diff --git a/lerna.json b/lerna.json new file mode 100644 index 0000000000000000000000000000000000000000..793042fdd123bda0e48b3342fd732d5e41360339 --- /dev/null +++ b/lerna.json @@ -0,0 +1,8 @@ +{ + "packages": [ + "packages/*" + ], + "version": "0.0.0", + "npmClient": "yarn", + "useWorkspaces": true +} diff --git a/package.json b/package.json index 2e96ad4a3c586a24a133627f22d34e461f767f7c..17d3c414139a230e052055d12bed62e5aedf7af2 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,15 @@ { - "name": "vue-devui", - "version": "0.0.0", - "license": "MIT", - "description": "DevUI components based on Vite and Vue3", + "name": "root", + "private": true, "scripts": { - "dev": "vite", - "build": "vite build", - "convert:route": "node ./scripts/convert-component-route.js" - }, - "dependencies": { - "@types/lodash-es": "^4.17.4", - "lodash-es": "^4.17.20", - "vue": "^3.0.5", - "vue-router": "^4.0.3" + "dev": "lerna exec --scope vue-devui yarn dev", + "build": "lerna exec --scope vue-devui yarn build", + "build:lib": "lerna exec --scope vue-devui yarn build:lib" }, "devDependencies": { - "@commitlint/cli": "^11.0.0", - "@commitlint/config-conventional": "^11.0.0", - "@vitejs/plugin-vue": "^1.0.4", - "@vitejs/plugin-vue-jsx": "^1.1.0", - "@vue/compiler-sfc": "^3.0.5", - "@vuedx/typecheck": "^0.4.1", - "@vuedx/typescript-plugin-vue": "^0.4.1", - "commander": "^7.1.0", - "husky": "^4.3.7", - "sass": "^1.32.2", - "shelljs": "^0.8.4", - "typescript": "^4.1.3", - "vite": "^2.0.5", - "vite-plugin-md": "^0.6.0" + "lerna": "^4.0.0" }, - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - } -} + "workspaces": [ + "packages/*" + ] +} \ No newline at end of file diff --git a/packages/devui-cli/README.md b/packages/devui-cli/README.md new file mode 100644 index 0000000000000000000000000000000000000000..57f82fe97ac7dbe14397043159e722ad20442d3e --- /dev/null +++ b/packages/devui-cli/README.md @@ -0,0 +1,3 @@ +# `devui-cli` + +> TODO: description \ No newline at end of file diff --git a/packages/devui-cli/package.json b/packages/devui-cli/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b0f4cb468b2743bf639d608363809c80ba747774 --- /dev/null +++ b/packages/devui-cli/package.json @@ -0,0 +1,49 @@ +{ + "name": "@devui/cli", + "version": "0.0.1", + "description": "Cli of devui", + "keywords": [ + "cli", + "devui", + "devui-cli" + ], + "author": "iel", + "homepage": "https://gitee.com/devui/vue-devui/tree/dev/packages/devui-vue/devui-cli#README.md", + "license": "MIT", + "main": "lib/bin.js", + "types": "types/bin.d.ts", + "bin": { + "dc": "lib/bin.js" + }, + "files": [ + "lib", + "types" + ], + "repository": { + "type": "git", + "url": "https://gitee.com/RootWater/vue-devui.git" + }, + "scripts": { + "dev": "esbuild --bundle ./src/bin.ts --format=cjs --platform=node --outfile=./lib/bin.js --external:esbuild --minify-whitespace --watch", + "build": "npm run build:lib & npm run build:dts", + "build:lib": "rimraf ./lib && esbuild --bundle ./src/bin.ts --format=cjs --platform=node --outfile=./lib/bin.js --external:esbuild --minify-whitespace", + "build:dts": "rimraf ./types && tsc -p ./tsconfig.json", + "cli": "node ./lib/bin.js" + }, + "devDependencies": { + "@types/fs-extra": "^9.0.13", + "@types/lodash-es": "^4.17.5", + "@types/node": "^16.11.6", + "@types/prompts": "^2.0.14", + "commander": "^8.3.0", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "kolorist": "^1.5.0", + "lodash-es": "^4.17.21", + "prompts": "^2.4.2", + "typescript": "^4.4.4" + }, + "dependencies": { + "esbuild": "^0.13.12" + } +} diff --git a/packages/devui-cli/src/bin.ts b/packages/devui-cli/src/bin.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf19b38a6e8707ee1e286a1770a3ec8c6e9e7fee --- /dev/null +++ b/packages/devui-cli/src/bin.ts @@ -0,0 +1,45 @@ +#!/usr/bin/env node +import { Command } from 'commander' +import baseAction from './commands/base' +import createAction, { validateCreateType } from './commands/create' +import { CliConfig, detectCliConfig } from './shared/config' +import { VERSION } from './shared/constant' +import { + DEFAULT_CLI_CONFIG_FILE_NAME +} from './shared/generate-config' + +// detect cli config +detectCliConfig() + +const program = new Command() + +program + .command('create [name...]') + .option( + '-c --config ', + `Specify a configuration file. By default, find the file at the beginning of "${DEFAULT_CLI_CONFIG_FILE_NAME}" in the current working directory.` + ) + .option('-t --type ', 'Select create type.', validateCreateType) + .option('--core', 'Include core when creating a component.') + .option('--service', 'Include service when creating a component.') + .option('--directive', 'Include service when creating a component.') + .option('-f --force', 'For force overwriting.') + .description('Create a component structure, library entry file or other...') + .action(createAction) + +program + .option('--init', 'Initialize the cli configuration file in the current working directory.') + .option( + '-c --config ', + `Specify a configuration file. By default, find the file at the beginning of "${DEFAULT_CLI_CONFIG_FILE_NAME}" in the current working directory.` + ) + .usage('[command] [options]') + .version(VERSION, '-v --version') + .description('Cli of devui.') + .action(baseAction) + +program.parse(process.argv) + +export function defineCliConfig(config: Partial = {}) { + return config +} diff --git a/packages/devui-cli/src/commands/base.ts b/packages/devui-cli/src/commands/base.ts new file mode 100644 index 0000000000000000000000000000000000000000..877dc955ad761565074b87f9c0c39e762607e366 --- /dev/null +++ b/packages/devui-cli/src/commands/base.ts @@ -0,0 +1,87 @@ +import { existsSync, statSync } from 'fs-extra' +import { dirname, extname, isAbsolute, resolve } from 'path' +import prompts from 'prompts' +import { mergeCliConfig } from '../shared/config' +import { CWD } from '../shared/constant' +import generateConfig from '../shared/generate-config' +import logger from '../shared/logger' +import { dynamicImport, onPromptsCancel } from '../shared/utils' +import buildAction from './build' +import createAction from './create' + +function getActions() { + const actionMap = new Map() + actionMap.set('create', { + title: 'create', + value: 'create', + selected: true, + action: createAction + }) + actionMap.set('build', { title: 'build', value: 'build', action: buildAction }) + + return actionMap +} + +export type BaseCmd = { + init?: boolean + config?: string +} + +export default async function baseAction(cmd: BaseCmd) { + if (cmd.init) { + return generateConfig() + } + + loadCliConfig(cmd) + + selectCommand() +} + +export function loadCliConfig(cmd: Pick) { + if (!cmd.config) return + + let configPath = resolve(CWD, cmd.config) + + if (!existsSync(configPath)) { + logger.error(`The path "${configPath}" not exist.`) + process.exit(1) + } + + if (statSync(configPath).isDirectory() || !['.js', '.ts'].includes(extname(configPath))) { + logger.error(`The path "${configPath}" is not a ".js" or ".ts" file.`) + process.exit(1) + } + + const config = dynamicImport(configPath) + if (!isAbsolute(config.cwd)) { + config.cwd = resolve(dirname(configPath), config.cwd) + } + + mergeCliConfig(config) +} + +async function selectCommand() { + const actions = getActions() + let result: any = {} + + try { + result = await prompts( + [ + { + name: 'command', + type: 'select', + message: 'Please select a command.', + choices: Array.from(actions.values()) + } + ], + { + onCancel: onPromptsCancel + } + ) + } catch (e: any) { + logger.error(e.message) + process.exit(1) + } + + actions.get(result.command)!.action() +} diff --git a/packages/devui-cli/src/commands/build.ts b/packages/devui-cli/src/commands/build.ts new file mode 100644 index 0000000000000000000000000000000000000000..bdfdf67aafee3f8a94215a07d61657a3540b888c --- /dev/null +++ b/packages/devui-cli/src/commands/build.ts @@ -0,0 +1,5 @@ +function buildAction() { + +} + +export default buildAction \ No newline at end of file diff --git a/packages/devui-cli/src/commands/create-component.ts b/packages/devui-cli/src/commands/create-component.ts new file mode 100644 index 0000000000000000000000000000000000000000..caaef584e5966bb7737981b0080c74fdc4d36c18 --- /dev/null +++ b/packages/devui-cli/src/commands/create-component.ts @@ -0,0 +1,128 @@ +import prompts from 'prompts' +import { cliConfig } from '../shared/config' +import genComponent from '../shared/generate-component' +import logger from '../shared/logger' +import { canSafelyOverwrite, onPromptsCancel, resolveComponentDir } from '../shared/utils' +import { CreateCMD } from './create' + +export function isValidComponentName(name: string) { + if (!name) return false + + const flag = /^[a-zA-Z]([\w-\d]*)$/.test(name) + + if (!flag) { + logger.warn(`The component name "${name}" is invalid.`) + logger.info(`The component name rule: letters, numbers, "-", and must start with a letter.`) + } + + return flag +} + +export default async function createComponentAction(names: string[] = [], cmd: CreateCMD = {}) { + let [name = '', title = '', category = ''] = names + const parts = [] + let targetDir = resolveComponentDir(name) + + cmd.core && parts.push('core') + cmd.service && parts.push('service') + cmd.directive && parts.push('directive') + + if (!isValidComponentName(name)) { + name = '' + targetDir = '' + } + + try { + const meta = await prompts( + [ + { + name: 'name', + type: () => (name ? null : 'text'), + message: 'Component name:', + validate: () => { + console.log('') // 防止错误输出于同一行 + + const isValid = isValidComponentName(name) + + return isValid + }, + onState: (state) => { + name = String(state.value).trim() + targetDir = resolveComponentDir(name) + } + }, + { + name: 'shouldOverwrite', + type: () => (canSafelyOverwrite(targetDir) || cmd.force ? null : 'confirm'), + message: () => { + return `Target directory "${targetDir}" is not empty. Remove existing files and continue?` + } + }, + { + name: 'overwriteChecker', + type: (prev, values: any = {}) => { + if (values.shouldOverwrite === false) { + throw new Error('Operation cancelled') + } + return null + } + }, + { + name: 'title', + type: () => (title ? null : 'text'), + message: 'Component title:', + validate: () => title !== '', + onState: (state) => (title = String(state.value).trim()) + }, + { + name: 'category', + type: () => (cliConfig.componentCategories.includes(category) ? null : 'select'), + message: 'Select a component category.', + choices: cliConfig.componentCategories.map((value, index) => ({ + title: value, + value, + selected: index === 0 + })) + }, + { + name: 'parts', + type: () => (parts.length === 3 ? null : 'multiselect'), + message: 'Select one or more parts.', + choices: [ + { + title: 'component', + value: 'core', + description: 'Contains components, types, style templates.', + selected: parts.includes('core') + }, + { + title: 'service', + value: 'service', + description: 'Contains service, types templates', + selected: parts.includes('service') + }, + { + title: 'directive', + value: 'directive', + description: 'Contains directive templates.', + selected: parts.includes('directive') + } + ], + min: 1 + } + ], + { onCancel: onPromptsCancel } + ) + + genComponent({ + name, + title, + category: meta.category ?? category, + parts: meta.parts ?? parts, + dir: targetDir + }) + } catch (e: any) { + logger.error(e.message) + process.exit(1) + } +} diff --git a/packages/devui-cli/src/commands/create-lib-entry.ts b/packages/devui-cli/src/commands/create-lib-entry.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b47aa2b22e691b93de78c75ee0c77e1511f9e40 --- /dev/null +++ b/packages/devui-cli/src/commands/create-lib-entry.ts @@ -0,0 +1,14 @@ +import { cliConfig } from '../shared/config' +import genLibEntry from '../shared/generate-lib-entry' +import logger from '../shared/logger' +import { resolveLibEntryDir } from '../shared/utils' +import { CreateCMD } from './create' + +export default async function createLibEntryAction(names: string[] = [], cmd: CreateCMD) { + try { + const [name = cliConfig.libEntryFileName] = names + genLibEntry(resolveLibEntryDir(name)) + } catch (e: any) { + logger.error(e.message) + } +} diff --git a/packages/devui-cli/src/commands/create.ts b/packages/devui-cli/src/commands/create.ts new file mode 100644 index 0000000000000000000000000000000000000000..67b1458a3c0582f1c1895f01d7208ebe0a546a31 --- /dev/null +++ b/packages/devui-cli/src/commands/create.ts @@ -0,0 +1,77 @@ +import prompts from 'prompts' +import logger from '../shared/logger' +import { onPromptsCancel } from '../shared/utils' +import { loadCliConfig } from './base' +import createComponentAction from './create-component' +import createLibEntryAction from './create-lib-entry' + +export type CreateCMD = { + config?: string + type?: keyof typeof CREATE_TYPE_ACTION + core?: boolean + service?: boolean + directive?: boolean + force?: boolean +} + +const CREATE_TYPES = ['component', 'component-test', 'component-doc', 'lib-entry', 'doc-nav'] +const UNFINISHED_CREATE_TYPES = ['component-test', 'component-doc', 'doc-nav'] +const CREATE_TYPE_ACTION = { + component: createComponentAction, + 'lib-entry': createLibEntryAction +} + +export function validateCreateType(type: string) { + const valid = CREATE_TYPES.includes(type) + + if (!valid) { + logger.error(`Create type error!.`) + logger.info( + `Optional type list: ${CREATE_TYPES.map((type) => + UNFINISHED_CREATE_TYPES.includes(type) ? `${type}(Unfinished)` : type + ).join(', ')}` + ) + } + + return valid ? type : '' +} + +export default async function createAction(names: string[] = [], cmd: CreateCMD = {}) { + loadCliConfig(cmd) + + let { type } = cmd + + if (!type) { + try { + const result = await prompts( + [ + { + name: 'type', + type: 'select', + message: 'Please select a type.', + choices: CREATE_TYPES.map((value, index) => ({ + title: value, + value, + selected: index === 0 + })) + } + ], + { + onCancel: onPromptsCancel + } + ) + + type = result.type + } catch (e: any) { + logger.error(e.message) + process.exit(1) + } + } + + const action = CREATE_TYPE_ACTION[type!] + if (action) { + action(names, cmd) + } else { + logger.warn('Sorry! The type is not completed.') + } +} diff --git a/packages/devui-cli/src/shared/config.ts b/packages/devui-cli/src/shared/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4818a33ec80ecc9cfb83848d8c9d7c1bb39b6f6 --- /dev/null +++ b/packages/devui-cli/src/shared/config.ts @@ -0,0 +1,92 @@ +import { readdirSync, statSync } from 'fs-extra' +import { merge } from 'lodash-es' +import { resolve } from 'path' +import { loadCliConfig } from '../commands/base' +import { CWD } from './constant' +import { DEFAULT_CLI_CONFIG_NAME } from './generate-config' + +export type CliConfig = { + /** + * current workspace directory + * + * ***Should be the root directory of the component library.*** + * + * @default process.cwd() + */ + cwd: string + /** + * Generate the root directory of component. + * + * ***Note that the path should be based on the `cwd` of configuration item.*** + * + * @default . + */ + componentRootDir: string + /** + * category of component + * + * @default ['通用', '导航', '反馈', '数据录入', '数据展示', '布局'] + */ + componentCategories: string[] + /** + * prefix of the component library + * + * @default '' + */ + libPrefix: string + /** + * component style file suffix of the component library + * + * @default .css + */ + libStyleFileSuffix: string + /** + * component class prefix of the component library + */ + libClassPrefix: string + /** + * component library entry file name + * + * @default index + */ + libEntryFileName: string + /** + * Generate the root directory of the lib entry file. + * + * ***Note that the path should be based on the `cwd` of configuration item.*** + * + * @default . + */ + libEntryRootDir: string + /** + * version of component library + * + * @default 0.0.0 + */ + version: string +} + +export const cliConfig: CliConfig = { + cwd: CWD, + componentRootDir: '.', + componentCategories: ['通用', '导航', '反馈', '数据录入', '数据展示', '布局'], + libPrefix: '', + libStyleFileSuffix: '.css', + libClassPrefix: '', + libEntryRootDir: '.', + libEntryFileName: 'index', + version: '0.0.0' +} + +export function mergeCliConfig(config: Partial = {}) { + return merge(cliConfig, config) +} + +export function detectCliConfig() { + const re = new RegExp(`^${DEFAULT_CLI_CONFIG_NAME}\.(js|ts)$`) + const file = readdirSync(CWD).find((f) => statSync(resolve(CWD, f)).isFile() && re.test(f)) + + if (!file) return + + loadCliConfig({ config: resolve(CWD, file) }) +} diff --git a/packages/devui-cli/src/shared/constant.ts b/packages/devui-cli/src/shared/constant.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc3cab561618de06b842fff7ef045c548b2cd788 --- /dev/null +++ b/packages/devui-cli/src/shared/constant.ts @@ -0,0 +1,7 @@ +import { name, version } from '../../package.json' + +export const CWD = process.cwd() + +export const VERSION = version + +export const PKG_NAME = name \ No newline at end of file diff --git a/packages/devui-cli/src/shared/generate-component.ts b/packages/devui-cli/src/shared/generate-component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a55d64e2090165c2c80d38c07c7aa9e58c9401a --- /dev/null +++ b/packages/devui-cli/src/shared/generate-component.ts @@ -0,0 +1,82 @@ +import { WriteFileOptions } from 'fs' +import { mkdirSync, writeFileSync } from 'fs-extra' +import { resolve } from 'path' +import genIndexTemplate from '../templates/component' +import genCoreTemplate from '../templates/component/core' +import genDirectiveTemplate from '../templates/component/directive' +import genDocTemplate from '../templates/component/doc' +import genMetaTemplate, { ComponentMeta, genMetaObj } from '../templates/component/meta' +import genServiceTemplate from '../templates/component/service' +import genStyleTemplate from '../templates/component/style' +import genTestTemplate from '../templates/component/test' +import genTypesTemplate from '../templates/component/types' +import { + coreFileName, + directiveFileName, + serviceFileName, + typesFileName +} from '../templates/component/utils' +import { cliConfig } from './config' +import logger from './logger' +import { bigCamelCase } from './utils' + +const WRITE_FILE_OPTIONS: WriteFileOptions = { encoding: 'utf-8' } + +export default function genComponent(meta: ComponentMeta) { + const componentDir = resolve(meta.dir!, 'src') + const docDir = resolve(meta.dir!, 'docs') + const testDir = resolve(meta.dir!, '__tests__') + + mkdirSync(componentDir, { recursive: true }) + mkdirSync(docDir, { recursive: true }) + mkdirSync(testDir, { recursive: true }) + + let needsTypes = false + meta = genMetaObj(meta) + + if (meta.parts.includes('core')) { + needsTypes = true + + const coreFilePath = resolve(componentDir, coreFileName(meta.name)) + writeFileSync(coreFilePath + '.tsx', genCoreTemplate(meta.name), WRITE_FILE_OPTIONS) + writeFileSync( + coreFilePath + cliConfig.libStyleFileSuffix, + genStyleTemplate(meta.name), + WRITE_FILE_OPTIONS + ) + } + + if (meta.parts.includes('service')) { + needsTypes = true + + const serviceFilePath = resolve(componentDir, serviceFileName(meta.name) + '.ts') + writeFileSync(serviceFilePath, genServiceTemplate(meta.name), WRITE_FILE_OPTIONS) + } + + if (meta.parts.includes('directive')) { + const directiveFilePath = resolve(componentDir, directiveFileName(meta.name) + '.ts') + writeFileSync(directiveFilePath, genDirectiveTemplate(), WRITE_FILE_OPTIONS) + } + + if (needsTypes) { + const typesFilePath = resolve(componentDir, typesFileName(meta.name) + '.ts') + writeFileSync(typesFilePath, genTypesTemplate(meta.name), WRITE_FILE_OPTIONS) + } + + if (meta.parts.length > 0) { + const indexFilePath = resolve(meta.dir!, 'index.ts') + const metaFilePath = resolve(meta.dir!, 'meta.json') + const testFilePath = resolve(testDir, 'index.spec.ts') + const docFilePath = resolve(docDir, 'index.md') + + writeFileSync(indexFilePath, genIndexTemplate(meta.name, meta.parts), WRITE_FILE_OPTIONS) + writeFileSync(metaFilePath, genMetaTemplate(meta), WRITE_FILE_OPTIONS) + writeFileSync(testFilePath, genTestTemplate(meta), WRITE_FILE_OPTIONS) + writeFileSync(docFilePath, genDocTemplate(meta), WRITE_FILE_OPTIONS) + } + + logger.success( + `The component "${bigCamelCase(meta.name)}" directory has been generated successfully.` + ) + logger.info(`Target directory: ${meta.dir}`) +} diff --git a/packages/devui-cli/src/shared/generate-config.ts b/packages/devui-cli/src/shared/generate-config.ts new file mode 100644 index 0000000000000000000000000000000000000000..109f5e55dda59401c15d0a245fb3eda7da53bdee --- /dev/null +++ b/packages/devui-cli/src/shared/generate-config.ts @@ -0,0 +1,23 @@ +import { existsSync, writeFileSync } from 'fs-extra' +import { resolve } from 'path' +import genConfigTemplate from '../templates/base/config' +import { CWD } from './constant' +import logger from './logger' + +export const DEFAULT_CLI_CONFIG_NAME = 'dc.config' +export const DEFAULT_CLI_CONFIG_EXT_NAME = '.ts' +export const DEFAULT_CLI_CONFIG_FILE_NAME = DEFAULT_CLI_CONFIG_NAME + DEFAULT_CLI_CONFIG_EXT_NAME + +export default function generateConfig() { + const configPath = resolve(CWD, DEFAULT_CLI_CONFIG_FILE_NAME) + + if (existsSync(configPath)) { + logger.error(`The configuration path "${configPath}" already exists.`) + process.exit(1) + } + + writeFileSync(configPath, genConfigTemplate(), { encoding: 'utf-8' }) + + logger.success(`The configuration file has been generated successfully.`) + logger.info(`Target file: ${configPath}`) +} diff --git a/packages/devui-cli/src/shared/generate-lib-entry.ts b/packages/devui-cli/src/shared/generate-lib-entry.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa19170b03e92f6576d0673778ab5f1651e67da5 --- /dev/null +++ b/packages/devui-cli/src/shared/generate-lib-entry.ts @@ -0,0 +1,15 @@ +import { writeFileSync } from 'fs-extra' +import { getComponentsMeta } from '../templates/component/utils' +import genLibEntryTemplate from '../templates/lib-entry/lib-entry' +import logger from './logger' + +export default async function genLibEntry(filePath: string = '') { + const componentsMeta = await getComponentsMeta() + + writeFileSync(filePath, genLibEntryTemplate(componentsMeta), { + encoding: 'utf-8' + }) + + logger.success(`The component library entry file has been generated successfully.`) + logger.info(`Target file: ${filePath}`) +} diff --git a/packages/devui-cli/src/shared/logger.ts b/packages/devui-cli/src/shared/logger.ts new file mode 100644 index 0000000000000000000000000000000000000000..b1f1e76681eb8070961021d68db4c90a5d85a089 --- /dev/null +++ b/packages/devui-cli/src/shared/logger.ts @@ -0,0 +1,19 @@ +import { lightBlue, lightGreen, lightRed, lightYellow } from 'kolorist' + +const logger = { + PREFIX: '[dev-cli]', + info(text: string) { + console.log(lightBlue(`✈ ${logger.PREFIX} - ${text}`)) + }, + success(text: string) { + console.log(lightGreen(`✔ ${logger.PREFIX} - ${text}`)) + }, + warn(text: string) { + console.log(lightYellow(`▶ ${logger.PREFIX} - ${text}`)) + }, + error(text: string) { + console.log(lightRed(`✖ ${logger.PREFIX} - ${text}`)) + } +} + +export default logger diff --git a/packages/devui-cli/src/shared/utils.ts b/packages/devui-cli/src/shared/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..882bed6bfdc857c88a199450a174641bfb7afc57 --- /dev/null +++ b/packages/devui-cli/src/shared/utils.ts @@ -0,0 +1,45 @@ +import { buildSync } from 'esbuild' +import { existsSync, readdirSync, unlinkSync } from 'fs-extra' +import { camelCase, upperFirst } from 'lodash-es' +import { extname, relative, resolve } from 'path' +import { coreFileName } from '../templates/component/utils' +import { cliConfig } from './config' + +export function bigCamelCase(str: string) { + return upperFirst(camelCase(str)) +} + +export function onPromptsCancel() { + throw new Error('Operation cancelled.') +} + +export function canSafelyOverwrite(dir: string) { + return !existsSync(dir) || readdirSync(dir).length === 0 +} + +export function resolveComponentDir(name: string) { + return resolve(cliConfig.cwd, cliConfig.componentRootDir, coreFileName(name)) +} + +export function resolveLibEntryDir(name: string) { + return resolve(cliConfig.cwd, cliConfig.libEntryRootDir, name + '.ts') +} + +export function dynamicImport(path: string) { + const tempPath = path.replace(extname(path), Date.now() + '.js') + const relativePath = relative(__dirname, tempPath) + + buildSync({ + bundle: true, + entryPoints: [path], + outfile: tempPath, + platform: 'node', + format: 'cjs', + external: ['esbuild', 'dev-cli'] + }) + + const config = require(relativePath).default ?? {} + unlinkSync(tempPath) + + return config +} diff --git a/packages/devui-cli/src/templates/base/config.ts b/packages/devui-cli/src/templates/base/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e2798cfaf3cf9b6aeaa4be111fdce0135b447a6 --- /dev/null +++ b/packages/devui-cli/src/templates/base/config.ts @@ -0,0 +1,10 @@ +import { CliConfig } from "../../shared/config"; +import { PKG_NAME } from "../../shared/constant"; + +export default function genConfigTemplate(config: Partial = {}) { + return `\ +import { defineCliConfig } from '${PKG_NAME}' + +export default defineCliConfig(${JSON.stringify(config, null, 2)}) +` +} \ No newline at end of file diff --git a/packages/devui-cli/src/templates/component/core.ts b/packages/devui-cli/src/templates/component/core.ts new file mode 100644 index 0000000000000000000000000000000000000000..18431482460eb4edb871663b8ce1b2deda53a22d --- /dev/null +++ b/packages/devui-cli/src/templates/component/core.ts @@ -0,0 +1,19 @@ +import { coreClassName, coreRealName, propsName, propsTypesName, typesFileName } from './utils' + +export default function genCoreTemplate(name: string) { + return `\ +import { defineComponent } from 'vue' +import { ${propsName(name)}, ${propsTypesName(name)} } from './${typesFileName(name)}' + +export default defineComponent({ + name: '${coreRealName(name)}', + props: ${propsName(name)}, + emits: [], + setup(props: ${propsTypesName(name)}, ctx) { + return () => { + return (
    ) + } + } +}) +` +} diff --git a/packages/devui-cli/src/templates/component/directive.ts b/packages/devui-cli/src/templates/component/directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..5333f99f4dad659e210af70bd4d21f5f451d2695 --- /dev/null +++ b/packages/devui-cli/src/templates/component/directive.ts @@ -0,0 +1,13 @@ +export default function genDirectiveTemplate() { + return `\ +// can export function. +export default { + created() { }, + beforeMount() { }, + mounted() { }, + beforeUpdate() { }, + updated() { }, + beforeUnmount() { }, + unmounted() { } +}` +} diff --git a/packages/devui-cli/src/templates/component/doc.ts b/packages/devui-cli/src/templates/component/doc.ts new file mode 100644 index 0000000000000000000000000000000000000000..641d6667fb27d45159248b8afa54fc36e636920f --- /dev/null +++ b/packages/devui-cli/src/templates/component/doc.ts @@ -0,0 +1,55 @@ +import { getPartName } from "../lib-entry/lib-entry"; +import { ComponentMeta } from "./meta"; + +export default function genDocTemplate(meta: ComponentMeta) { + return `\ +# ${meta.fullTitle} + +\/\/ todo 组件描述 + +### 何时使用 + +\/\/ todo 使用时机描述 + +### 基本用法 + +\/\/ todo 用法描述 + +:::demo \/\/ todo 展开代码的内部描述 + +\`\`\`vue + + + + + +\`\`\` + +::: + +### ${meta.realName} + +${meta.realName} 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| | | | | | | +| | | | | | | +| | | | | | | + +${meta.realName} 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | +` +} diff --git a/packages/devui-cli/src/templates/component/index.ts b/packages/devui-cli/src/templates/component/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f712e308559283c10c284b4b39a6c4759aaf208 --- /dev/null +++ b/packages/devui-cli/src/templates/component/index.ts @@ -0,0 +1,65 @@ +import { camelCase } from 'lodash-es' +import { + coreFileName, + coreName, + directiveFileName, + directiveName, + propsTypesName, + serviceFileName, + serviceName, + typesFileName +} from './utils' + +export default function genIndexTemplate(name: string, parts: string[]) { + const importParts = [] + const exportParts = [] + const installParts = [] + + let needsTypes = false + + if (parts.includes('core')) { + needsTypes = true + + importParts.push(`import ${coreName(name)} from './src/${coreFileName(name)}'`) + exportParts.push(coreName(name)) + installParts.push(`\tapp.component(${coreName(name)}.name, ${coreName(name)})`) + } + + if (parts.includes('service')) { + needsTypes = true + + importParts.push(`import ${serviceName(name)} from './src/${serviceFileName(name)}'`) + exportParts.push(serviceName(name)) + installParts.push( + `\tapp.config.globalProperties.$${camelCase(serviceName(name))} = ${serviceName(name)}` + ) + } + + if (parts.includes('directive')) { + importParts.push(`import ${directiveName(name)} from './src/${directiveFileName(name)}'`) + exportParts.push(directiveName(name)) + installParts.push(`\tapp.directive('${coreName(name)}', ${directiveName(name)})`) + } + + if (needsTypes) { + importParts.push(`import { ${propsTypesName(name)} } from './src/${typesFileName(name)}'`) + exportParts.push(propsTypesName(name)) + } + + return `\ +import type { App } from 'vue' +${importParts.join('\n')} + +${coreName(name)}.install = function (app: App) { +${installParts.join('\n')} +} + +export { ${exportParts.join(', ')} } + +export default { + install(app: App) { + app.use(${coreName(name)} as any) + } +} +` +} diff --git a/packages/devui-cli/src/templates/component/meta.ts b/packages/devui-cli/src/templates/component/meta.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5c37e25abd28ef6f8074d949304fd442b1fd384 --- /dev/null +++ b/packages/devui-cli/src/templates/component/meta.ts @@ -0,0 +1,49 @@ +import { isPlainObject } from 'lodash-es' +import { coreName, coreRealName } from './utils' + +export type ComponentMeta = { + name: string + realName?: string + title: string + fullTitle?: string + category: string + parts: string[] + status?: string + dir?: string +} + +export function isValidComponentMeta(obj: any) { + return isPlainObject(obj) && !!obj.name && Array.isArray(obj.parts) +} + +export function genMetaObj(meta: Partial = {}) { + return { + $name: '组件英文名称', + name: coreName(meta.name ?? ''), + + $realName: '组件 name 属性', + realName: meta.realName ?? coreRealName(meta.name ?? ''), + + $title: '组件中文名称', + title: meta.title ?? '', + + $fullTitle: '完整的组件标题,用于文档组件列表树使用', + fullTitle: meta.fullTitle ?? `${coreName(meta.name ?? '')} ${meta.title ?? ''}`, + + $category: '组件分类', + category: meta.category ?? '', + + $parts: '零部件集合', + parts: meta.parts ?? [], + + $status: '组件开发进度:可设置百分比进度(10%、80%)或文字状态(待开发、开发中、已完成)', + status: meta.status ?? '0%', + + $dir: '组件目录', + dir: meta.dir ?? '' + } +} + +export default function genMetaTemplate(meta: Partial = {}) { + return JSON.stringify(genMetaObj(meta), null, 2) +} diff --git a/packages/devui-cli/src/templates/component/service.ts b/packages/devui-cli/src/templates/component/service.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b67f135aeefd0c035ddfd2c4531d797a3c23f39 --- /dev/null +++ b/packages/devui-cli/src/templates/component/service.ts @@ -0,0 +1,13 @@ +import { propsTypesName, serviceName, typesFileName } from './utils' + +export default function genServiceTemplate(name: string) { + return `\ +import { ${propsTypesName(name)} } from './${typesFileName(name)}' + +const ${serviceName(name)} = { + // open(props: ${propsTypesName(name)}) { } +} + +export default ${serviceName(name)} +` +} diff --git a/packages/devui-cli/src/templates/component/style.ts b/packages/devui-cli/src/templates/component/style.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f7f217aa2a396aaa29240f56acf02c61887b16d --- /dev/null +++ b/packages/devui-cli/src/templates/component/style.ts @@ -0,0 +1,8 @@ +import { coreClassName } from "./utils" + +export default function genStyleTemplate(name: string) { + return `\ +.${coreClassName(name)} { + /* your style */ +}` +} \ No newline at end of file diff --git a/packages/devui-cli/src/templates/component/test.ts b/packages/devui-cli/src/templates/component/test.ts new file mode 100644 index 0000000000000000000000000000000000000000..78c56b9216ab4a74a362c819a472198dbf238226 --- /dev/null +++ b/packages/devui-cli/src/templates/component/test.ts @@ -0,0 +1,15 @@ +import { getPartName } from '../lib-entry/lib-entry' +import { ComponentMeta } from './meta' + +export default function genTestTemplate(meta: ComponentMeta) { + return `\ +import { mount } from '@vue/test-utils' +import { ${meta.parts.map((part) => getPartName(part, meta.name)).join(', ')} } from '../index' + +describe('${meta.name} test', () => { + it('${meta.name} init render', async () => { + \/\/ todo + }) +}) +` +} diff --git a/packages/devui-cli/src/templates/component/types.ts b/packages/devui-cli/src/templates/component/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d2656474bde2794969561f4cc806108430301b2 --- /dev/null +++ b/packages/devui-cli/src/templates/component/types.ts @@ -0,0 +1,15 @@ +import { propsName, propsTypesName } from './utils' + +export default function genTypesTemplate(name: string) { + return `\ +import type { PropType, ExtractPropTypes } from 'vue' + +export const ${propsName(name)}Props = { + \/\* test: { + type: Object as PropType<{ xxx: xxx }> + } \*\/ +} as const + +export type ${propsTypesName(name)}Props = ExtractPropTypes +` +} diff --git a/packages/devui-cli/src/templates/component/utils.ts b/packages/devui-cli/src/templates/component/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..a36a4f5a20a6f4372b382e885503b0bd8e6fa153 --- /dev/null +++ b/packages/devui-cli/src/templates/component/utils.ts @@ -0,0 +1,36 @@ +import glob from 'fast-glob' +import { readFileSync } from 'fs-extra' +import { camelCase, kebabCase } from 'lodash-es' +import { cliConfig } from '../../shared/config' +import { bigCamelCase } from '../../shared/utils' +import { ComponentMeta } from './meta' + +export const coreFileName = (name: string) => kebabCase(name) +export const typesFileName = (name: string) => kebabCase(name + '-types') +export const serviceFileName = (name: string) => kebabCase(name + '-service') +export const directiveFileName = (name: string) => kebabCase(name + '-directive') + +export const getRealLibPrefix = () => (cliConfig.libPrefix ? cliConfig.libPrefix + '-' : '') +export const getRealClassPrefix = () => + cliConfig.libClassPrefix ? cliConfig.libClassPrefix + '-' : '' + +export const coreName = (name: string) => bigCamelCase(name) +export const coreRealName = (name: string) => bigCamelCase(getRealLibPrefix() + name) +export const coreClassName = (name: string) => kebabCase(getRealClassPrefix() + name) +export const propsName = (name: string) => camelCase(name + 'Props') +export const propsTypesName = (name: string) => bigCamelCase(name + 'Props') +export const serviceName = (name: string) => bigCamelCase(name + 'Service') +export const directiveName = (name: string) => bigCamelCase(name + 'Directive') + +export async function getComponentMetaFiles() { + return glob('./**/meta.json', { + cwd: cliConfig.cwd, + absolute: true, + deep: 2 + }) +} + +export async function getComponentsMeta() { + const metaFiles = await getComponentMetaFiles() + return metaFiles.map((f) => JSON.parse(readFileSync(f, { encoding: 'utf-8' })) as ComponentMeta) +} diff --git a/packages/devui-cli/src/templates/lib-entry/lib-entry.ts b/packages/devui-cli/src/templates/lib-entry/lib-entry.ts new file mode 100644 index 0000000000000000000000000000000000000000..9450fe0bd2a6939b207e89fdec6fe74e99e3fea2 --- /dev/null +++ b/packages/devui-cli/src/templates/lib-entry/lib-entry.ts @@ -0,0 +1,78 @@ +import { relative, resolve } from 'path' +import { cliConfig } from '../../shared/config' +import logger from '../../shared/logger' +import { ComponentMeta, isValidComponentMeta } from '../component/meta' +import { coreFileName, coreName, directiveName, serviceName } from '../component/utils' + +export function resolveImportRelativePath(coreName: string) { + const libEntryPath = resolve(cliConfig.cwd, cliConfig.libEntryRootDir) + const corePath = resolve(cliConfig.cwd, cliConfig.componentRootDir, coreName) + + let relativePath = relative(libEntryPath, corePath) + + if (relativePath.startsWith(coreName)) { + relativePath = './' + relativePath + } + + return relativePath.replace(/\\/g, '/') +} + +export function getPartName(part: string, name: string) { + const partNameFn = { + core: coreName, + service: serviceName, + directive: directiveName + }[part] + + if (partNameFn === undefined) { + logger.warn( + `The component part must be one of core, service, or directive, but it gets an invalid value ${part}.` + ) + } + + return partNameFn?.(name) ?? name +} + +export default function genLibEntryTemplate(componentsMeta: ComponentMeta[]) { + const imports = [] + const installs = [] + const packages = [] + + for (const meta of componentsMeta) { + if (!isValidComponentMeta(meta)) { + logger.warn( + `The component meta information must include the name and parts attributes, and the parts attribute must be an array.` + ) + continue + } + + const parts = meta.parts.map((part) => getPartName(part, meta.name)) + const install = coreName(meta.name) + 'Install' + const importPkgPath = resolveImportRelativePath(coreFileName(meta.name)) + + installs.push(install) + imports.push(`import ${install}, { ${parts.join(', ')} } from '${importPkgPath}'`) + packages.push(...parts) + } + + return `\ +import type { App } from 'vue' + +${imports.join('\n')} + +const installs = [ +\t${installs.join(',\n\t')} +] + +export { +\t${packages.join(',\n\t')} +} + +export default { + version: '${cliConfig.version}', + install(app: App): void { + installs.forEach((p) => app.use(p as any)) + } +} +` +} diff --git a/packages/devui-cli/tsconfig.json b/packages/devui-cli/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..e799e8ac906c673ea7079f540e1f1f0b7f462049 --- /dev/null +++ b/packages/devui-cli/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": [ + "esnext", + "dom" + ], + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "declaration": true, + "emitDeclarationOnly": true, + "downlevelIteration": true, + "declarationDir": "./types", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "include": [ + "./src/**/*.ts", + "./src/**/*.d.ts" + ] +} \ No newline at end of file diff --git a/packages/devui-vue/.eslintrc.js b/packages/devui-vue/.eslintrc.js new file mode 100644 index 0000000000000000000000000000000000000000..34ce586d93ea2cc2c029520c9fc5637852efdac9 --- /dev/null +++ b/packages/devui-vue/.eslintrc.js @@ -0,0 +1,50 @@ +module.exports = { + parser: 'vue-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser', + sourceType: 'module', + ecmaVersion: 6, + ecmaFeatures: { + jsx: true, + tsx: true, + }, + }, + env: { + browser: true, + node: true, + jest: true, + es6: true, + }, + plugins: ['@typescript-eslint'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:vue/vue3-recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + ], + rules: { + quotes: [ + 'error', + 'single', + { avoidEscape: true, allowTemplateLiterals: true }, + ], + 'no-undef': 2, + 'vue/max-attributes-per-line': 'off', + 'vue/no-multiple-template-root': 'off', + 'vue/script-setup-uses-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/member-delimiter-style': [ + 'error', + { + multiline: { + delimiter: 'none', + requireLast: false, + }, + singleline: { + delimiter: 'semi', + requireLast: true, + }, + }, + ], + }, +} diff --git a/packages/devui-vue/.ls-lint.yml b/packages/devui-vue/.ls-lint.yml new file mode 100644 index 0000000000000000000000000000000000000000..b367ef20412250a261672cceb85fb3cf7dcf1930 --- /dev/null +++ b/packages/devui-vue/.ls-lint.yml @@ -0,0 +1,15 @@ +ls: + /{devui,src}/*: + .dir: kebab-case | regex:__[a-z0-9]+__ + .scss: kebab-case + .vue: kebab-case + .js: kebab-case + .ts: kebab-case + .tsx: kebab-case + .spec.ts: kebab-case + .route.ts: kebab-case + .type.ts: kebab-case + +ignore: + - devui/style + - node_modules diff --git a/packages/devui-vue/.stylelintrc.json b/packages/devui-vue/.stylelintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..ece2ed8c5c52208c562d50eda48688f73f721f65 --- /dev/null +++ b/packages/devui-vue/.stylelintrc.json @@ -0,0 +1,50 @@ +{ + "extends": [ + "stylelint-config-standard", + "stylelint-config-recommended-scss" + ], + "plugins": [ + "stylelint-scss" + ], + "rules": { + "string-quotes": "single", + "property-no-unknown": true, + "selector-pseudo-class-no-unknown": true, + "at-rule-empty-line-before": ["always",{ + "except":["blockless-after-same-name-blockless","first-nested","inside-block"], + "ignore": ["after-comment", "first-nested"] + }], + "rule-empty-line-before":["always",{ + "except": [ "after-single-line-comment", "first-nested"] + }], + "block-no-empty": true, + "selector-pseudo-element-no-unknown": [ + true, + { + "ignorePseudoElements": [ + "ng-deep" + ] + } + ], + "selector-type-no-unknown": [ + true, + { + "ignoreTypes": [ + "/^d-/" + ] + } + ], + "color-hex-length": "long", + "no-descending-specificity": null, + "font-family-no-missing-generic-family-keyword": null, + "no-duplicate-selectors": null, + "declaration-block-no-duplicate-properties": [ + true, + { + "ignore": [ + "consecutive-duplicates" + ] + } + ] + } +} diff --git a/packages/devui-vue/.yarnrc b/packages/devui-vue/.yarnrc new file mode 100644 index 0000000000000000000000000000000000000000..f4074f57d780e95aa353cc4b0bbb5a36708fa35f --- /dev/null +++ b/packages/devui-vue/.yarnrc @@ -0,0 +1 @@ +registry "https://registry.npm.taobao.org" \ No newline at end of file diff --git a/packages/devui-vue/LICENSE b/packages/devui-vue/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..e3a2b0425c06727332e53b757349d33b0c5835df --- /dev/null +++ b/packages/devui-vue/LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2019 - present DevUI. +Copyright (c) 2019 - present Huawei Technologies Co., Ltd. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. + diff --git a/packages/devui-vue/README.md b/packages/devui-vue/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7032a70ee6a51adac432ab6b7df70bea3d641396 --- /dev/null +++ b/packages/devui-vue/README.md @@ -0,0 +1,172 @@ +

    + + DevUI Logo + +

    + +Vue DevUI 是 Vue3 版本的 DevUI 组件库,基于 [https://github.com/devcloudfe/ng-devui](https://github.com/devcloudfe/ng-devui),倡导`沉浸`、`灵活`、`至简`的设计价值观。 + +DevUI 官方网站:[https://devui.design](https://devui.design) + +# 当前状态: Beta + +该项目还处于孵化和演进阶段,欢迎大家参与到 Vue DevUI 项目的建设中来!🎉🎉 + +通过参与 Vue DevUI 项目,你可以: +- 🔥 学习最新的 `Vite`+`Vue3`+`TypeScript`+`JSX` 技术 +- 🎁 学习如何设计和开发组件 +- ⭐ 参与到开源社区中来 +- 🎊 结识一群热爱学习、热爱开源的朋友 + +[贡献指南](https://gitee.com/devui/vue-devui/wikis/【必看】快速开始) + +# 快速开始 + +## 1 安装依赖 + +``` +yarn(推荐) + +or + +npm i +``` + +## 2 启动 + +``` +yarn dev(推荐) + +or + +npm run dev +``` + +## 3 访问 + +[http://localhost:3000/](http://localhost:3000/) + +## 4 生产打包 + +``` +yarn build(推荐) + +or + +npm run build +``` + +# 使用 Vue DevUI + +## 1. 安装 + +``` +yarn add vue-devui +``` + +## 2. 全量引入 + +``` +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入 Vue DevUI 组件库 +import DevUI from 'vue-devui' +// Step 2: 引入组件库样式 +import 'vue-devui/style.css' + +createApp(App) +.use(DevUI) // Step 3: 使用 Vue DevUI +.mount('#app') +``` + +## 3. 按需引入 + +除了全量引入,我们也支持单个组件按需引入。 + +``` +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入单个组件 +import { Button } from 'vue-devui' +// or import Button from 'vue-devui/button' +// Step 2: 引入组件样式 +import 'vue-devui/button/style.css' + +createApp(App) +.use(Button) // Step 3: 使用组件 +.mount('#app') +``` + +## 4. 使用 + +``` + +``` + +# 图标库 + +图标库可以使用[DevUI图标库](https://devui.design/icon/ruleResource),也可以使用第三方图标库,比如:iconfont。 + +## 使用DevUI图标库 + +### 安装 + +``` +yarn add @devui-design/icons(推荐) + +or + +npm i @devui-design/icons +``` + +### 引入 + +在`main.ts`文件中,编写以下代码: + +``` +import '@devui-design/icons/icomoon/devui-icon.css' +``` + +### 使用 + +``` + +``` + +## 使用第三方图标库 + +如果有第三方图标库,可以用类似的方式引入。 + +### 引入 + +在`main.ts`文件中,编写以下代码: + +``` +import 'your-folder/my-icon.css' +``` + +### 使用 + +``` + +``` + +其中的`classPrefix`参数的值,应该和你的字体图标样式文件`my-icon.css`里定义的样式前缀保持一致。 + +比如`my-icon.css`里的图标样式: + +```css +.my-icon-branch-node:before { + content: "\E001"; +} +``` + +那么`classPrefix`就是`my-icon`。 + +# License + +[MIT](https://gitee.com/devui/vue-devui/blob/dev/LICENSE) diff --git a/packages/devui-vue/__mocks__/file-mock.ts b/packages/devui-vue/__mocks__/file-mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c645e42fb75c2cb63a74ee7081fba37f511818e --- /dev/null +++ b/packages/devui-vue/__mocks__/file-mock.ts @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/packages/devui-vue/__mocks__/style-mock.ts b/packages/devui-vue/__mocks__/style-mock.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c645e42fb75c2cb63a74ee7081fba37f511818e --- /dev/null +++ b/packages/devui-vue/__mocks__/style-mock.ts @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/commitlint.config.js b/packages/devui-vue/commitlint.config.js similarity index 100% rename from commitlint.config.js rename to packages/devui-vue/commitlint.config.js diff --git a/packages/devui-vue/devui-cli/commands/build.js b/packages/devui-vue/devui-cli/commands/build.js new file mode 100644 index 0000000000000000000000000000000000000000..48c472f47b673f88f715fc4b738f97ea93d45a35 --- /dev/null +++ b/packages/devui-vue/devui-cli/commands/build.js @@ -0,0 +1,87 @@ +const path = require('path') +const fs = require('fs') +const fsExtra = require('fs-extra') +const { defineConfig, build } = require('vite') +const vue = require('@vitejs/plugin-vue') +const vueJsx = require('@vitejs/plugin-vue-jsx') + +const entryDir = path.resolve(__dirname, '../../devui') +const outputDir = path.resolve(__dirname, '../../build') + +const baseConfig = defineConfig({ + configFile: false, + publicDir: false, + plugins: [ vue(), vueJsx() ] +}) + +const rollupOptions = { + external: ['vue', 'vue-router'], + output: { + globals: { + vue: 'Vue' + } + } +} + +const buildSingle = async (name) => { + await build(defineConfig({ + ...baseConfig, + build: { + rollupOptions, + lib: { + entry: path.resolve(entryDir, name), + name: 'index', + fileName: 'index', + formats: ['es', 'umd'] + }, + outDir: path.resolve(outputDir, name) + } + })) +} + +const buildAll = async () => { + await build(defineConfig({ + ...baseConfig, + build: { + rollupOptions, + lib: { + entry: path.resolve(entryDir, 'vue-devui.ts'), + name: 'vue-devui', + fileName: 'vue-devui', + formats: ['es', 'umd'] + }, + outDir: outputDir + } + })) +} + +const createPackageJson = (name) => { + const fileStr = `{ + "name": "${name}", + "version": "0.0.0", + "main": "index.umd.js", + "module": "index.es.js", + "style": "style.css" +}` + + fsExtra.outputFile( + path.resolve(outputDir, `${name}/package.json`), + fileStr, + 'utf-8' + ) +} + +exports.build = async () => { + await buildAll() + + const components = fs.readdirSync(entryDir).filter(name => { + const componentDir = path.resolve(entryDir, name) + const isDir = fs.lstatSync(componentDir).isDirectory() + return isDir && fs.readdirSync(componentDir).includes('index.ts') + }) + + for(const name of components) { + await buildSingle(name) + createPackageJson(name) + } +} diff --git a/packages/devui-vue/devui-cli/commands/create.js b/packages/devui-vue/devui-cli/commands/create.js new file mode 100644 index 0000000000000000000000000000000000000000..91433ada765ab462e4ed653fca4eecaf3aa28150 --- /dev/null +++ b/packages/devui-vue/devui-cli/commands/create.js @@ -0,0 +1,234 @@ +const logger = require('../shared/logger') +const { + bigCamelCase, + resolveDirFilesInfo, + parseExportByFileInfo, + parseComponentInfo +} = require('../shared/utils') +const fs = require('fs-extra') +const { resolve } = require('path') +const { + DEVUI_NAMESPACE, + DEVUI_DIR, + TESTS_DIR_NAME, + COMPONENT_PARTS_MAP, + INDEX_FILE_NAME, + DOCS_FILE_NAME, + VUE_DEVUI_FILE, + VUE_DEVUI_IGNORE_DIRS, + VUE_DEVUI_FILE_NAME, + CREATE_SUPPORT_TYPES, + CREATE_UNFINISHED_TYPES, + CREATE_SUPPORT_TYPE_MAP, + SITES_COMPONENTS_DIR, + VITEPRESS_SIDEBAR_FILE, + VITEPRESS_SIDEBAR_FILE_NAME +} = require('../shared/constant') +const { isEmpty, kebabCase } = require('lodash') +const inquirer = require('inquirer') +const { selectCreateType } = require('../inquirers/create') +const { selectCategory, selectParts, typeName, typeTitle } = require('../inquirers/component') +const { + createComponentTemplate, + createStyleTemplate, + createTypesTemplate, + createDirectiveTemplate, + createServiceTemplate, + createIndexTemplate, + createTestsTemplate, + createDocumentTemplate +} = require('../templates/component') +const { createVueDevuiTemplate } = require('../templates/vue-devui') +const ora = require('ora') +const { createVitepressSidebarTemplate } = require('../templates/vitepress-sidebar') + +exports.validateCreateType = (type) => { + const re = new RegExp('^(' + CREATE_SUPPORT_TYPES.map((t) => `(${t})`).join('|') + ')$') + const flag = re.test(type) + + !flag && logger.error(`类型错误,可选类型为:${CREATE_SUPPORT_TYPES.join(', ')}`) + + return flag ? type : null +} + +// TODO: 待优化代码结构 +exports.create = async (cwd) => { + let { type } = cwd + + if (isEmpty(type)) { + const result = await inquirer.prompt([selectCreateType()]) + type = result.type + } + + if (CREATE_UNFINISHED_TYPES.includes(type)) { + logger.info('抱歉,该功能暂未完成!') + process.exit(0) + } + + let params = {} + + try { + switch (type) { + case CREATE_SUPPORT_TYPE_MAP.component: + params = await inquirer.prompt([typeName(), typeTitle(), selectCategory(), selectParts()]) + params.hasComponent = params.parts.includes('component') + params.hasDirective = params.parts.includes('directive') + params.hasService = params.parts.includes('service') + + await createComponent(params, cwd) + break + case CREATE_SUPPORT_TYPE_MAP['vue-devui']: + // 创建 devui/vue-devui.ts + await createVueDevui(params, cwd) + // 创建 docs/.vitepress/config/sidebar.ts + await createVitepressSidebar() + break + default: + break + } + } catch (e) { + logger.error(e.toString()) + process.exit(1) + } +} + +async function createComponent(params = {}) { + let { name, hasComponent, hasDirective, hasService } = params + + const componentName = kebabCase(name) + const styleName = kebabCase(name) + const typesName = kebabCase(name) + '-types' + const directiveName = kebabCase(name) + '-directive' + const serviceName = kebabCase(name) + '-service' + const testName = kebabCase(name) + '.spec' + + const _params = { + ...params, + componentName, + typesName, + directiveName, + serviceName, + styleName, + testName + } + + const componentTemplate = createComponentTemplate(_params) + const styleTemplate = createStyleTemplate(_params) + const typesTemplate = createTypesTemplate(_params) + const directiveTemplate = createDirectiveTemplate(_params) + const serviceTemplate = createServiceTemplate(_params) + const indexTemplate = createIndexTemplate(_params) + // 增加测试模板 + const testsTemplate = createTestsTemplate(_params) + // 增加文档模板 + const docTemplate = createDocumentTemplate(_params) + + const componentDir = resolve(DEVUI_DIR, componentName) + const srcDir = resolve(componentDir, 'src') + const testsDir = resolve(DEVUI_DIR, componentName, TESTS_DIR_NAME) + const docsDir = resolve(SITES_COMPONENTS_DIR, componentName) + + if (fs.pathExistsSync(componentDir)) { + logger.error(`${bigCamelCase(componentName)} 组件目录已存在!`) + process.exit(1) + } + + let spinner = ora(`创建组件 ${bigCamelCase(componentName)} 开始...`).start() + + try { + await Promise.all([fs.mkdirs(componentDir), fs.mkdirs(srcDir), fs.mkdirs(testsDir)]) + + const writeFiles = [ + fs.writeFile(resolve(componentDir, INDEX_FILE_NAME), indexTemplate), + fs.writeFile(resolve(testsDir, `${testName}.ts`), testsTemplate), + ] + + if (!fs.existsSync(docsDir)) { + fs.mkdirSync(docsDir) + writeFiles.push(fs.writeFile(resolve(docsDir, DOCS_FILE_NAME), docTemplate)) + } else { + logger.warning(`\n${bigCamelCase(componentName)} 组件文档已存在:${resolve(docsDir, DOCS_FILE_NAME)}`) + } + + if (hasComponent || hasService) { + writeFiles.push(fs.writeFile(resolve(srcDir, `${typesName}.ts`), typesTemplate)) + } + + if (hasComponent) { + writeFiles.push( + fs.writeFile(resolve(srcDir, `${componentName}.tsx`), componentTemplate), + fs.writeFile(resolve(srcDir, `${styleName}.scss`), styleTemplate) + ) + } + + if (hasDirective) { + writeFiles.push(fs.writeFile(resolve(srcDir, `${directiveName}.ts`), directiveTemplate)) + } + + if (hasService) { + writeFiles.push(fs.writeFile(resolve(srcDir, `${serviceName}.ts`), serviceTemplate)) + } + + await Promise.all(writeFiles) + + spinner.succeed(`创建组件 ${bigCamelCase(componentName)} 成功!`) + logger.info(`组件目录:${componentDir}`) + } catch (e) { + spinner.fail(e.toString()) + process.exit(1) + } +} + +async function createVueDevui(params, { ignoreParseError }) { + const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS) + const exportModules = [] + + fileInfo.forEach((f) => { + const em = parseExportByFileInfo(f, ignoreParseError) + + if (isEmpty(em)) return + + exportModules.push(em) + }) + + const template = createVueDevuiTemplate(exportModules) + + let spinner = ora(`创建 ${VUE_DEVUI_FILE_NAME} 文件开始...`).start() + + try { + await fs.writeFile(VUE_DEVUI_FILE, template, { encoding: 'utf-8' }) + + spinner.succeed(`创建 ${VUE_DEVUI_FILE_NAME} 文件成功!`) + logger.info(`文件地址:${VUE_DEVUI_FILE}`) + } catch (e) { + spinner.fail(e.toString()) + process.exit(1) + } +} + +async function createVitepressSidebar() { + const fileInfo = resolveDirFilesInfo(DEVUI_DIR, VUE_DEVUI_IGNORE_DIRS) + const componentsInfo = [] + + fileInfo.forEach((f) => { + const info = parseComponentInfo(f.dirname) + + if (isEmpty(info)) return + + componentsInfo.push(info) + }) + + const template = createVitepressSidebarTemplate(componentsInfo) + + let spinner = ora(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件开始...`).start() + + try { + await fs.writeFile(VITEPRESS_SIDEBAR_FILE, template, { encoding: 'utf-8' }) + + spinner.succeed(`创建 ${VITEPRESS_SIDEBAR_FILE_NAME} 文件成功!`) + logger.info(`文件地址:${VITEPRESS_SIDEBAR_FILE}`) + } catch (e) { + spinner.fail(e.toString()) + process.exit(1) + } +} diff --git a/packages/devui-vue/devui-cli/commands/generate-theme.js b/packages/devui-vue/devui-cli/commands/generate-theme.js new file mode 100644 index 0000000000000000000000000000000000000000..3acfa026b87d7bc467abdb1015a9d2cae6cc2d0b --- /dev/null +++ b/packages/devui-vue/devui-cli/commands/generate-theme.js @@ -0,0 +1,16 @@ +require('esbuild-register') +const path = require('path') +const fs = require('fs-extra') +const theme = require('../../devui/theme/themes/light.ts').default + +const fileStr = Object.entries(theme) +.map(([key, value]) => `$${key}: var(--${key}, ${value})`) +.join(';\n') + +exports.generateTheme = async () => { + await fs.outputFile( + path.resolve(__dirname, '../../devui/theme/theme.scss'), + fileStr, + 'utf-8' + ) +} \ No newline at end of file diff --git a/packages/devui-vue/devui-cli/index.js b/packages/devui-vue/devui-cli/index.js new file mode 100755 index 0000000000000000000000000000000000000000..d4ed9906e6fe7e2f2b8c41cab1765391bdae6fd0 --- /dev/null +++ b/packages/devui-vue/devui-cli/index.js @@ -0,0 +1,28 @@ +#!/usr/bin/env node +const { Command } = require('commander') +const { create, validateCreateType } = require('./commands/create') +const { build } = require('./commands/build') +const { generateTheme } = require('./commands/generate-theme') +const { VERSION, CREATE_SUPPORT_TYPES } = require('./shared/constant') + +const program = new Command() + +program + .command('create') + .description('创建一个组件模板或配置文件') + .option('-t --type ', `创建类型,可选值:${CREATE_SUPPORT_TYPES.join(', ')}`, validateCreateType) + .option('--ignore-parse-error', '忽略解析错误', false) + .option('--cover', '覆盖原文件', false) + .action(create) + +program + .command('build') + .description('打包组件库') + .action(build) + +program + .command('generate:theme') + .description('生成主题变量文件') + .action(generateTheme) + +program.parse().version(VERSION) diff --git a/packages/devui-vue/devui-cli/inquirers/component.js b/packages/devui-vue/devui-cli/inquirers/component.js new file mode 100644 index 0000000000000000000000000000000000000000..355a2b09470c21a9c0f78df8314393d67da0f72d --- /dev/null +++ b/packages/devui-vue/devui-cli/inquirers/component.js @@ -0,0 +1,53 @@ +const { COMPONENT_PARTS_MAP, VITEPRESS_SIDEBAR_CATEGORY } = require('../shared/constant') + +exports.typeName = () => ({ + name: 'name', + type: 'input', + message: '(必填)请输入组件 name ,将用作目录及文件名:', + validate: (value) => { + if (value.trim() === '') { + return '组件 name 是必填项!' + } + return true + } +}) + +exports.typeTitle = () => ({ + name: 'title', + type: 'input', + message: '(必填)请输入组件中文名称,将用作文档列表显示:', + validate: (value) => { + if (value.trim() === '') { + return '组件名称是必填项!' + } + return true + } +}) + +exports.selectCategory = () => ({ + name: 'category', + type: 'list', + message: '(必填)请选择组件分类,将用作文档列表分类:', + choices: VITEPRESS_SIDEBAR_CATEGORY, + default: 0 +}) + +exports.typeAliasName = () => ({ + name: 'alias', + type: 'input', + message: '(选填)请输入组件 name 别名,将用作组件别名被导出:' +}) + +exports.selectParts = () => ({ + name: 'parts', + type: 'checkbox', + message: '(必填)请选择包含部件,将自动生成部件文件:', + choices: COMPONENT_PARTS_MAP, + default: [], + validate: (value) => { + if (value.length === 0) { + return '部件必须包含至少一项' + } + return true + } +}) diff --git a/packages/devui-vue/devui-cli/inquirers/create.js b/packages/devui-vue/devui-cli/inquirers/create.js new file mode 100644 index 0000000000000000000000000000000000000000..5bc07766b51469dd82c4cd1a75ac125ad5d81065 --- /dev/null +++ b/packages/devui-vue/devui-cli/inquirers/create.js @@ -0,0 +1,9 @@ +const { CREATE_SUPPORT_TYPES } = require('../shared/constant') + +exports.selectCreateType = () => ({ + name: 'type', + type: 'list', + message: '(必填)请选择创建类型:', + choices: CREATE_SUPPORT_TYPES, + default: 0 +}) diff --git a/packages/devui-vue/devui-cli/shared/constant.js b/packages/devui-vue/devui-cli/shared/constant.js new file mode 100644 index 0000000000000000000000000000000000000000..6288409782d590df0d3e450b4f279a854a627793 --- /dev/null +++ b/packages/devui-vue/devui-cli/shared/constant.js @@ -0,0 +1,46 @@ +const { resolve } = require('path') +const { version } = require('../../package.json') + +exports.VERSION = version +exports.CWD = process.cwd() +exports.DEVUI_DIR = resolve(this.CWD, 'devui') +exports.DEVUI_NAMESPACE = 'd' +exports.CSS_CLASS_PREFIX = 'devui' +exports.TESTS_DIR_NAME = '__tests__' +exports.INDEX_FILE_NAME = 'index.ts' +exports.DOCS_FILE_NAME = 'index.md' +exports.VUE_DEVUI_IGNORE_DIRS = ['shared', 'style'] +exports.VUE_DEVUI_FILE_NAME = 'vue-devui.ts' +exports.VUE_DEVUI_FILE = resolve(this.DEVUI_DIR, this.VUE_DEVUI_FILE_NAME) +exports.SITES_DIR = resolve(this.CWD, 'docs') +exports.SITES_COMPONENTS_DIR_NAME = 'components' +exports.SITES_COMPONENTS_DIR = resolve(this.SITES_DIR, this.SITES_COMPONENTS_DIR_NAME) +exports.VITEPRESS_DIR = resolve(this.SITES_DIR, '.vitepress') +exports.VITEPRESS_SIDEBAR_FILE_NAME = 'sidebar.ts' +exports.VITEPRESS_SIDEBAR_FILE = resolve(this.VITEPRESS_DIR, `config/${this.VITEPRESS_SIDEBAR_FILE_NAME}`) + +// 这里的分类顺序将会影响最终生成的页面侧边栏顺序 +exports.VITEPRESS_SIDEBAR_CATEGORY = ['通用', '导航', '反馈', '数据录入', '数据展示', '布局'] + +exports.COMPONENT_PARTS_MAP = [ + { + name: 'component(组件)', + value: 'component' + }, + { + name: 'directive(指令)', + value: 'directive' + }, + { + name: 'service(服务)', + value: 'service' + } +] + +exports.CREATE_SUPPORT_TYPE_MAP = Object.freeze({ + component: 'component', + 'vue-devui': 'vue-devui', + 'theme-variable': 'theme-variable', +}) +exports.CREATE_SUPPORT_TYPES = Object.keys(this.CREATE_SUPPORT_TYPE_MAP) +exports.CREATE_UNFINISHED_TYPES = [] diff --git a/packages/devui-vue/devui-cli/shared/logger.js b/packages/devui-vue/devui-cli/shared/logger.js new file mode 100644 index 0000000000000000000000000000000000000000..4b97da0e33d88dd6405d4b16747d46d099617f4f --- /dev/null +++ b/packages/devui-vue/devui-cli/shared/logger.js @@ -0,0 +1,16 @@ +const chalk = require('chalk') + +module.exports = { + info(text) { + console.log(chalk.hex('#00afef')(text)) + }, + success(text) { + console.log(chalk.hex('#00c48f')(text)) + }, + warning(text) { + console.log(chalk.hex('#ff9800')(text)) + }, + error(text) { + console.log(chalk.hex('#f44336')(text)) + } +} diff --git a/packages/devui-vue/devui-cli/shared/utils.js b/packages/devui-vue/devui-cli/shared/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..11fb60c7065a929734587fda721d59df57f0960a --- /dev/null +++ b/packages/devui-vue/devui-cli/shared/utils.js @@ -0,0 +1,124 @@ +const { camelCase, upperFirst } = require('lodash') +const { INDEX_FILE_NAME, DEVUI_DIR } = require('./constant') +const { resolve } = require('path') +const logger = require('./logger') +const fs = require('fs-extra') +const traverse = require("@babel/traverse").default +const babelParser = require("@babel/parser") + +exports.bigCamelCase = (str) => { + return upperFirst(camelCase(str)) +} + +exports.resolveDirFilesInfo = (targetDir, ignoreDirs = []) => { + return fs + .readdirSync(targetDir) + .filter( + (dir) => + // 过滤:必须是目录,且不存在与忽略目录内,拥有 INDEX_FILE_NAME + fs.statSync(resolve(targetDir, dir)).isDirectory() && + !ignoreDirs.includes(dir) && + fs.existsSync(resolve(targetDir, dir, INDEX_FILE_NAME)) + ) + .map((dir) => ({ + name: this.bigCamelCase(dir), + dirname: dir, + path: resolve(targetDir, dir, INDEX_FILE_NAME) + })) +} + +exports.parseExportByFileInfo = (fileInfo, ignoreParseError) => { + const exportModule = {} + const indexContent = fs.readFileSync(fileInfo.path, { encoding: 'utf-8' }) + + const ast = babelParser.parse(indexContent, { + sourceType: 'module', + plugins: [ + 'typescript' + ] + }) + + const exportName = [] + let exportDefault = null + + traverse(ast, { + ExportNamedDeclaration({node}) { + if (node.specifiers.length) { + node.specifiers.forEach(specifier => { + exportName.push(specifier.local.name) + }) + } else if (node.declaration) { + if (node.declaration.declarations) { + node.declaration.declarations.forEach(dec => { + exportName.push(dec.id.name) + }) + } else if (node.declaration.id) { + exportName.push(node.declaration.id.name) + } + } + }, + ExportDefaultDeclaration() { + exportDefault = fileInfo.name + 'Install' + } + }) + + if (!exportDefault) { + logger.error(`${fileInfo.path} must have "export default".`) + + if (ignoreParseError) { + return exportModule + } else { + process.exit(1) + } + } + + if (!exportName.length) { + logger.error(`${fileInfo.path} must have "export xxx".`) + + if (ignoreParseError) { + return exportModule + } else { + process.exit(1) + } + } + + exportModule.default = exportDefault + exportModule.parts = exportName + exportModule.fileInfo = fileInfo + + return exportModule +} + +exports.parseComponentInfo = (name) => { + const componentInfo = { + name: this.bigCamelCase(name) + } + let hasExportDefault = false + const indexContent = fs.readFileSync(resolve(DEVUI_DIR, name, INDEX_FILE_NAME), { encoding: 'utf-8' }) + + const ast = babelParser.parse(indexContent, { + sourceType: 'module', + plugins: [ + 'typescript' + ] + }) + traverse(ast, { + ExportDefaultDeclaration({node}) { + hasExportDefault = true + if (node.declaration && node.declaration.properties) { + const properties = node.declaration.properties + properties.forEach(pro => { + if (pro.type === 'ObjectProperty') { + componentInfo[pro.key.name] = pro.value.value + } + }) + } + } + }) + + if (!hasExportDefault) { + logger.warning(`${componentInfo.name} must have "export default" and component info.`) + } + + return componentInfo +} diff --git a/packages/devui-vue/devui-cli/templates/component.js b/packages/devui-vue/devui-cli/templates/component.js new file mode 100644 index 0000000000000000000000000000000000000000..8e0909c48621ec4cf315e1321554456a05282cc7 --- /dev/null +++ b/packages/devui-vue/devui-cli/templates/component.js @@ -0,0 +1,212 @@ +const { DEVUI_NAMESPACE, CSS_CLASS_PREFIX } = require('../shared/constant') +const { camelCase } = require('lodash') +const { bigCamelCase } = require('../shared/utils') + +// 创建组件模板 +exports.createComponentTemplate = ({ styleName, componentName, typesName }) => `\ +import { defineComponent } from 'vue' +import { ${camelCase(componentName)}Props, ${bigCamelCase(componentName)}Props } from './${typesName}' +import './${styleName}.scss' + +export default defineComponent({ + name: '${bigCamelCase(DEVUI_NAMESPACE)}${bigCamelCase(componentName)}', + props: ${camelCase(componentName)}Props, + emits: [], + setup(props: ${bigCamelCase(componentName)}Props, ctx) { + return () => { + return (
    ) + } + } +}) +` + +// 创建类型声明模板 +exports.createTypesTemplate = ({ componentName }) => `\ +import type { PropType, ExtractPropTypes } from 'vue' + +export const ${camelCase(componentName)}Props = { + \/\* test: { + type: Object as PropType<{ xxx: xxx }> + } \*\/ +} as const + +export type ${bigCamelCase(componentName)}Props = ExtractPropTypes +` + +// 创建指令模板 +exports.createDirectiveTemplate = () => `\ +// can export function. +export default { + created() { }, + beforeMount() { }, + mounted() { }, + beforeUpdate() { }, + updated() { }, + beforeUnmount() { }, + unmounted() { } +} +` +// 创建server模板 +exports.createServiceTemplate = ({ componentName, typesName, serviceName }) => `\ +import { ${bigCamelCase(componentName)}Props } from './${typesName}' + +const ${bigCamelCase(serviceName)} = { + // open(props: ${bigCamelCase(componentName)}Props) { } +} + +export default ${bigCamelCase(serviceName)} +` + +// 创建scss模板 +exports.createStyleTemplate = ({ componentName }) => `\ +.${CSS_CLASS_PREFIX}-${componentName} { + // +} +` + +// 创建index模板 +exports.createIndexTemplate = ({ + title, + category, + hasComponent, + hasDirective, + hasService, + componentName, + directiveName, + serviceName +}) => { + const importComponentStr = `\nimport ${bigCamelCase(componentName)} from './src/${componentName}'` + const importDirectiveStr = `\nimport ${bigCamelCase(directiveName)} from './src/${directiveName}'` + const importServiceStr = `\nimport ${bigCamelCase(serviceName)} from './src/${serviceName}'` + + const installComponentStr = ` app.use(${bigCamelCase(componentName)} as any)` + const installDirectiveStr = `\n app.directive('${bigCamelCase(componentName)}', ${bigCamelCase(directiveName)})` + const installServiceStr = `\n app.config.globalProperties.$${camelCase(serviceName)} = ${bigCamelCase( + serviceName + )}` + + const getPartStr = (state, str) => (state ? str : '') + + const importStr = getPartStr(hasComponent, importComponentStr) + + getPartStr(hasDirective, importDirectiveStr) + + getPartStr(hasService, importServiceStr) + + const installStr = getPartStr(hasComponent, installComponentStr) + + getPartStr(hasDirective, installDirectiveStr) + + getPartStr(hasService, installServiceStr) + + return `\ +import type { App } from 'vue'\ +${importStr} +${ + hasComponent + ? `\n${bigCamelCase(componentName)}.install = function(app: App): void { + app.component(${bigCamelCase(componentName)}.name, ${bigCamelCase(componentName)}) +}\n` + : '' +} +export { ${[ + hasComponent ? bigCamelCase(componentName) : null, + hasDirective ? bigCamelCase(directiveName) : null, + hasService ? bigCamelCase(serviceName) : null + ] + .filter((p) => p !== null) + .join(', ')} } + +export default { + title: '${bigCamelCase(componentName)} ${title}', + category: '${category}', + status: undefined, \/\/ TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + ${installStr} + } +} +` +} + +// 创建测试模板 +exports.createTestsTemplate = ({ + componentName, + directiveName, + serviceName, + hasComponent, + hasDirective, + hasService +}) => `\ +import { mount } from '@vue/test-utils'; +import { ${[ + hasComponent ? bigCamelCase(componentName) : null, + hasDirective ? bigCamelCase(directiveName) : null, + hasService ? bigCamelCase(serviceName) : null + ] + .filter((p) => p !== null) + .join(', ')} } from '../index'; + +describe('${componentName} test', () => { + it('${componentName} init render', async () => { + // todo + }) +}) +` + +// 创建文档模板 +exports.createDocumentTemplate = ({ + componentName, + title +}) => `\ +# ${bigCamelCase(componentName)} ${title} + +// todo 组件描述 + +### 何时使用 + +// todo 使用时机描述 + + +### 基本用法 +// todo 用法描述 +:::demo // todo 展开代码的内部描述 + +\`\`\`vue + + + + + +\`\`\` + +::: + +### d-${componentName} + +d-${componentName} 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| | | | | | | +| | | | | | | +| | | | | | | + +d-${componentName} 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | + +` diff --git a/packages/devui-vue/devui-cli/templates/vitepress-sidebar.js b/packages/devui-vue/devui-cli/templates/vitepress-sidebar.js new file mode 100644 index 0000000000000000000000000000000000000000..ee079340e486e227daea5c8190784cbeea83c7ad --- /dev/null +++ b/packages/devui-vue/devui-cli/templates/vitepress-sidebar.js @@ -0,0 +1,35 @@ +const { kebabCase } = require('lodash') +const { SITES_COMPONENTS_DIR_NAME, VITEPRESS_SIDEBAR_CATEGORY } = require('../shared/constant') +const logger = require('../shared/logger') + +function buildComponentOptions(text, name, status) { + return { text, link: `/${SITES_COMPONENTS_DIR_NAME}/${kebabCase(name)}/`, status } +} + +function buildCategoryOptions(text, children = []) { + return { text, children } +} + +exports.createVitepressSidebarTemplate = (componentsInfo = []) => { + const rootNav = { text: '快速开始', link: '/' } + const categoryMap = VITEPRESS_SIDEBAR_CATEGORY.reduce((map, cate) => map.set(cate, []), new Map()) + + componentsInfo.forEach((info) => { + if (categoryMap.has(info.category)) { + categoryMap.get(info.category).push(buildComponentOptions(info.title, info.name, info.status)) + } else { + logger.warning(`组件 ${info.name} 的分类 ${info.category} 不存在!`) + } + }) + + const sidebar = [].concat( + rootNav, + Array.from(categoryMap).map(([k, v]) => buildCategoryOptions(k, v)) + ) + + return `\ +export default { + '/': ${JSON.stringify(sidebar, null, 2).replace(/\n/g, '\n\t')} +} +` +} diff --git a/packages/devui-vue/devui-cli/templates/vue-devui.js b/packages/devui-vue/devui-cli/templates/vue-devui.js new file mode 100644 index 0000000000000000000000000000000000000000..c6def01b3867c322248f3e06ce151b9f4d15b30e --- /dev/null +++ b/packages/devui-vue/devui-cli/templates/vue-devui.js @@ -0,0 +1,45 @@ +const { relative } = require('path') +const { INDEX_FILE_NAME, VERSION, VUE_DEVUI_FILE } = require('../shared/constant') + +exports.createVueDevuiTemplate = (exportModules = []) => { + const packages = [] + const imports = [] + const installs = [] + + exportModules.forEach((m) => { + const { fileInfo } = m + const relativePath = relative(VUE_DEVUI_FILE, fileInfo.path) + .replace(/\\/g, '/') + .replace('..', '.') + .replace('/' + INDEX_FILE_NAME, '') + + const importStr = `import ${m.default}, { ${m.parts.join(', ')} } from '${relativePath}'` + + packages.push(...m.parts) + imports.push(importStr) + installs.push(m.default) + }) + + const template = `\ +import type { App } from 'vue' + +${imports.join('\n')} + +const installs = [ + ${installs.join(',\n\t')} +] + +export { + ${packages.join(',\n\t')} +} + +export default { + version: '${VERSION}', + install(app: App): void { + installs.forEach((p) => app.use(p as any)) + } +} +` + + return template +} diff --git a/packages/devui-vue/devui/accordion/index.ts b/packages/devui-vue/devui/accordion/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0bd6b8014d31b5384bae8dfd384a85b0f29c3405 --- /dev/null +++ b/packages/devui-vue/devui/accordion/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Accordion from './src/accordion' + +Accordion.install = function(app: App) { + app.component(Accordion.name, Accordion) +} + +export { Accordion } + +export default { + title: 'Accordion 手风琴', + category: '导航', + status: '10%', + install(app: App): void { + app.use(Accordion as any) + } +} diff --git a/devui/accordion/accordion-item.tsx b/packages/devui-vue/devui/accordion/src/accordion-item.tsx similarity index 76% rename from devui/accordion/accordion-item.tsx rename to packages/devui-vue/devui/accordion/src/accordion-item.tsx index 150a364d0894acf6a607dba4d21b073dea3e3719..77389aa8537918cf67f72656a0f211d425e647a7 100644 --- a/devui/accordion/accordion-item.tsx +++ b/packages/devui-vue/devui/accordion/src/accordion-item.tsx @@ -1,11 +1,11 @@ import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-accordion-item', + name: 'DAccordionItem', props: { }, - setup(props, ctx) { + setup() { return () => { return
  • d-accordion-item
  • } diff --git a/devui/accordion/accordion-list.tsx b/packages/devui-vue/devui/accordion/src/accordion-list.tsx similarity index 79% rename from devui/accordion/accordion-list.tsx rename to packages/devui-vue/devui/accordion/src/accordion-list.tsx index f6b5d91f6d103e1ea36c47d4d9254f9595097a07..362cae3e585c1af33208f82104f3fe57a8903fb7 100644 --- a/devui/accordion/accordion-list.tsx +++ b/packages/devui-vue/devui/accordion/src/accordion-list.tsx @@ -2,23 +2,27 @@ import { defineComponent } from 'vue' import { AccordionMenuItem } from './accordion.type' export default defineComponent({ - name: 'd-accordion-list', + name: 'DAccordionList', inheritAttrs: false, props: { - data: Array as () => Array, + data: { + type: Array as () => Array, + default: null + }, deepth: { type: Number, default: 0 }, - parent: Object as () => AccordionMenuItem, + parent: { + type: Object as () => AccordionMenuItem, + default: null + }, innerListTemplate: Boolean, }, setup(props, ctx) { - const { data, deepth, innerListTemplate } = props; - return () => { - return (!innerListTemplate || deepth === 0) &&
      - { data.map(item => { + return (!props.innerListTemplate || props.deepth === 0) &&
        + { props.data.map(item => { return
      • { // TODO 菜单类型 d-accordion-menu @@ -39,6 +43,7 @@ export default defineComponent({
        { component.title } + { component.done && 已完成 }
      • diff --git a/devui/accordion/accordion-menu.tsx b/packages/devui-vue/devui/accordion/src/accordion-menu.tsx similarity index 76% rename from devui/accordion/accordion-menu.tsx rename to packages/devui-vue/devui/accordion/src/accordion-menu.tsx index 5aaa91e60a8b060628f5daf7e5d245f051b6943c..c5280a3b4d5a3355d8f445327de69a98828020db 100644 --- a/devui/accordion/accordion-menu.tsx +++ b/packages/devui-vue/devui/accordion/src/accordion-menu.tsx @@ -1,11 +1,11 @@ import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-accordion-menu', + name: 'DAccordionMenu', props: { }, - setup(props, ctx) { + setup() { return () => { return
      • d-accordion-menu
      • } diff --git a/devui/accordion/accordion.scss b/packages/devui-vue/devui/accordion/src/accordion.scss similarity index 89% rename from devui/accordion/accordion.scss rename to packages/devui-vue/devui/accordion/src/accordion.scss index 2bb5ed4a209903865031e9ab4db07927ee35a680..a6f4317d37ece561d874963ff04c5c8bbca90256 100644 --- a/devui/accordion/accordion.scss +++ b/packages/devui-vue/devui/accordion/src/accordion.scss @@ -1,7 +1,8 @@ -@import '../style/mixins/index'; -@import '../style/theme/color'; -@import '../style/theme/shadow'; -@import '../style/theme/corner'; +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/font'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; :host { display: block; @@ -246,8 +247,24 @@ d-accordion-item-routerlink { .devui-accordion-item > a { padding: 0 10px 0 20px; - color: var(--devui-text-weak,#575d6c); + color: var(--devui-text-weak, #575d6c); display: block; text-decoration: none; width: 100%; -} \ No newline at end of file +} + +.devui-accordion-item-title .tag-done { + display: inline-block; + height: 18px; + min-height: 20px; + padding: 0 10px; + margin-left: 8px; + line-height: 18px; + color: #fa9841; + border: solid 1px #fa9841; + background: $devui-base-bg; + font-size: $devui-font-size; + border-radius: $devui-border-radius; + text-indent: 0; + cursor: default; +} diff --git a/devui/accordion/accordion.tsx b/packages/devui-vue/devui/accordion/src/accordion.tsx similarity index 60% rename from devui/accordion/accordion.tsx rename to packages/devui-vue/devui/accordion/src/accordion.tsx index 062d44a79f56d0547ec85d69559cf63580ea7ce0..9935f71d21e52aa811e6db1ac5dafa6284bdbbd8 100644 --- a/devui/accordion/accordion.tsx +++ b/packages/devui-vue/devui/accordion/src/accordion.tsx @@ -1,12 +1,15 @@ -import { defineComponent } from 'vue' +import { defineComponent, reactive } from 'vue' import AccordionList from './accordion-list' import { AccordionMenuType } from './accordion.type' import './accordion.scss' export default defineComponent({ - name: 'd-accordion', + name: 'DAccordion', props: { - data: Array as () => Array | AccordionMenuType, + data: { + type: Array as () => Array | AccordionMenuType, + default: null + }, /* Key值定义, 用于自定义数据结构 */ titleKey: { type : String, default: 'title' }, // 标题的key,item[titleKey]类型为string,为标题显示内容 loadingKey: { type : String, default: 'loading' }, // 子菜单动态加载item[loadingKey]类型为boolean @@ -16,23 +19,35 @@ export default defineComponent({ openKey: { type : String, default: 'open' }, // 菜单是否打开 /* 菜单模板 */ - menuItemTemplate: { type: String }, // 可展开菜单内容条模板 - itemTemplate: { type: String }, // 可点击菜单内容条模板 + menuItemTemplate: { type: String, default: '' }, // 可展开菜单内容条模板 + itemTemplate: { type: String, default: '' }, // 可点击菜单内容条模板 - menuToggle: Function as unknown as () => ((event: MouseEvent) => void), // 可展开菜单展开事件 - itemClick: Function as unknown as () => ((event: MouseEvent) => void), // 可点击菜单点击事件 - activeItemChange: Function as unknown as () => ((event: MouseEvent) => void), + menuToggle: { + type: Function as unknown as () => ((event: MouseEvent) => void), + default: null + }, // 可展开菜单展开事件 + itemClick: { + type: Function as unknown as () => ((event: MouseEvent) => void), + default: null + }, // 可点击菜单点击事件 + activeItemChange: { + type: Function as unknown as () => ((event: MouseEvent) => void), + default: null + }, /** 高级选项和模板 */ restrictOneOpen: { type: Boolean, default: false }, // 限制一级菜单同时只能打开一个 autoOpenActiveMenu: { type: Boolean, default: false }, // 自动展开活跃菜单 showNoContent: { type: Boolean, default: true }, // 没有内容的时候是否显示没有数据 - noContentTemplate: { type: String }, // 没有内容的时候使用自定义模板 - loadingTemplate: { type: String }, // 加载中使用自定义模板 - innerListTemplate: { type: String }, // 可折叠菜单内容完全自定义,用做折叠面板 + noContentTemplate: { type: String, default: '' }, // 没有内容的时候使用自定义模板 + loadingTemplate: { type: String, default: '' }, // 加载中使用自定义模板 + innerListTemplate: { type: String, default: '' }, // 可折叠菜单内容完全自定义,用做折叠面板 /* 内置路由/链接/动态判断路由或链接类型 */ - linkType: { type: String as () => 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | '' | string, default: '' }, + linkType: { + type: String as () => 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | '' | string, + default: '' + }, linkTypeKey: { type: String, default: 'linkType' }, // linkType为'dependOnLinkTypeKey'时指定对象linkType定义区 linkKey: { type: String, default: 'link' }, // 链接内容的key linkTargetKey: { type: String, default: 'target' }, // 链接目标窗口的key @@ -40,8 +55,8 @@ export default defineComponent({ accordionType: { type: String as () => 'normal' | 'embed', default: 'normal' }, }, - setup(props, ctx) { - const { data, accordionType } = props + setup(props) { + const { data, accordionType } = reactive(props) return () => { return
        diff --git a/devui/accordion/accordion.type.ts b/packages/devui-vue/devui/accordion/src/accordion.type.ts similarity index 36% rename from devui/accordion/accordion.type.ts rename to packages/devui-vue/devui/accordion/src/accordion.type.ts index 10d525fc02ffa0b72433016f13897cda2e59caad..2a4cb0bf283ef755ea30d78382db92ec48ceec62 100755 --- a/devui/accordion/accordion.type.ts +++ b/packages/devui-vue/devui/accordion/src/accordion.type.ts @@ -1,29 +1,27 @@ -import { TemplateRef } from '@angular/core'; - /* 基础数据类型 */ type AccordionMenuItemLinkType = 'routerLink' | 'hrefLink' | string; export interface AccordionBase { - title: string; - disabled?: boolean; - [prop: string]: any; + title: string + disabled?: boolean + [prop: string]: any } interface IAccordionActiveable { - active?: boolean; + active?: boolean } interface IAccordionFoldable { - open?: boolean; - loading?: boolean; - children?: Array; + open?: boolean + loading?: boolean + children?: Array } interface IAccordionLinkable { - link?: string; - target?: boolean; - linkType?: AccordionMenuItemLinkType; + link?: string + target?: boolean + linkType?: AccordionMenuItemLinkType } export interface AccordionBaseItem extends AccordionBase, - IAccordionActiveable { + IAccordionActiveable { } export interface AccordionBaseMenu extends AccordionBase, @@ -37,92 +35,60 @@ export interface AccordionLinkableItem } export interface AccordionMenuItem extends AccordionBase, - IAccordionActiveable, - IAccordionFoldable, - IAccordionLinkable { + IAccordionActiveable, + IAccordionFoldable, + IAccordionLinkable { } export type AccordionMenuType = Array; /* 基础事件类型 */ export interface AccordionMenuToggleEvent { - item: any; - open: boolean; - parent: any; - event: MouseEvent; + item: any + open: boolean + parent: any + event: MouseEvent } export interface AccordionItemClickEvent { - item: any; - prevActiveItem?: any; - parent: any; - event: MouseEvent; -} - -/* 通用公共配置数据类型 */ -interface AccordionMenuKeyGroup { - titleKey?: string; - activeKey?: string; - disabledKey?: string; - openKey?: string; - loadingKey?: string; - childrenKey?: string; - linkKey?: string; - linkTargetKey?: string; - linkTypeKey?: string; -} - -type AccordionTemplateRefArray = 'itemTemplate' | 'menuItemTemplate' | 'noContentTemplate' | 'loadingTemplate' | 'innerListTemplate'; -type AccordionTemplateRefGroup = { - [p in AccordionTemplateRefArray]: TemplateRef -}; -interface AccordionConfigOptions { - restrictOneOpen?: boolean; - autoOpenActiveMenu?: boolean; - showNoContent?: boolean; - linkDefaultTarget?: string; - i18nCommonText?: any; - i18nText?: any; - linkType: 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | '' | string; -} -export interface AccordionOptions - extends AccordionConfigOptions, - AccordionMenuKeyGroup, - AccordionTemplateRefGroup { + item: any + prevActiveItem?: any + parent: any + event: MouseEvent } /* 废弃接口 */ /** @deprecated merge into `AccordionMenuItem`*/ export interface AccordionSubMenuItem { - title: string; - active?: boolean; - disabled?: boolean; - [prop: string]: any; + title: string + active?: boolean + disabled?: boolean + [prop: string]: any } /** @deprecated use `AccordionLinkableItem` instead*/ export interface AccordionSubMenuItemHrefLink { - title: string; - link: string; - target?: string; - active?: boolean; - disabled?: boolean; - [prop: string]: any; + title: string + link: string + target?: string + active?: boolean + disabled?: boolean + [prop: string]: any } /** @deprecated use `AccordionLinkableItem` instead*/ export interface AccordionSubMenuItemRouterLink { - title: string; - link: string; - target?: string; - active?: boolean; - disabled?: boolean; - [prop: string]: any; + title: string + link: string + target?: string + active?: boolean + disabled?: boolean + [prop: string]: any } /** @deprecated use `AccordionLinkableItem` instead*/ -export interface AccordionSubMenuItemDynamicLink { - title: string; - link: string; - linkType: 'routerLink' | 'hrefLink' | string; - target?: string; - active?: boolean; - disabled?: boolean; - [prop: string]: any; +export interface AccordionSubMenuItemDynamicLink { + title: string + link: string + linkType: 'routerLink' | 'hrefLink' | string + target?: string + active?: boolean + disabled?: boolean + [prop: string]: any } diff --git a/packages/devui-vue/devui/alert/__tests__/alert.spec.ts b/packages/devui-vue/devui/alert/__tests__/alert.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..08830e625075f5fe495d15abd4e63e6561d2607d --- /dev/null +++ b/packages/devui-vue/devui/alert/__tests__/alert.spec.ts @@ -0,0 +1,121 @@ +import { mount } from '@vue/test-utils' +import { h } from 'vue' +import Alert from '../src/alert' +describe('alert', () => { + describe('alert basic', () => { + it('should create alert component correctly', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + }) + it('should alert show content correct', () => { + const wrapper = mount(Alert, { + slots: { + default: h('span', {}, 'Vue DevUI'), + }, + }) + expect(wrapper.find('.devui-alert').text()).toBe('Vue DevUI') + }) + }) + + describe('alert type', () => { + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'success', + }, + }) + expect(wrapper.find('.devui-icon-success').exists()).toBe(true) + }) + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'warning', + }, + }) + expect(wrapper.find('.devui-icon-warning').exists()).toBe(true) + }) + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'danger', + }, + }) + expect(wrapper.find('.devui-icon-error').exists()).toBe(true) + }) + it('alert should has info type', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-icon-info').exists()).toBe(true) + }) + it('alert should has simple type', () => { + const wrapper = mount(Alert, { + props: { + type: 'simple', + }, + }) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(false) + }) + }) + + describe('alert cssClass', () => { + it('alert should append cssClass', () => { + const wrapper = mount(Alert, { + props: { + cssClass: 'cssClass', + }, + }) + expect(wrapper.find('.cssClass').exists()).toBe(true) + }) + }) + + describe('alert icon', () => { + it('alert should show icon', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(true) + }) + it('alert should not show icon', () => { + const wrapper = mount(Alert, { + props: { + showIcon: false, + }, + }) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(false) + }) + }) + + describe('alert close', () => { + it('alert should close', async () => { + const wrapper = mount(Alert) + await wrapper.find('.devui-close').trigger('click') + setTimeout(() => { + expect(wrapper.find('.devui-alert').exists()).toBe(false) + }, 0) + }) + it('alert should emit close event', async () => { + const wrapper = mount(Alert) + await wrapper.find('.devui-close').trigger('click') + expect(wrapper.emitted()).toHaveProperty('close') + expect(wrapper.emitted().close).toHaveLength(1) + }) + }) + + describe('alert dismiss', () => { + beforeEach(() => { + jest.useFakeTimers() + }) + it('alert should not dismiss before 3000ms', async () => { + const wrapper = mount(Alert, { + props: { + dismissTime: 3000, + }, + }) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + await wrapper.find('.devui-close').trigger('click') + jest.advanceTimersByTime(2000) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + jest.advanceTimersByTime(1000) + setTimeout(() => { + expect(wrapper.find('.devui-alert').exists()).toBe(false) + }, 0) + }) + }) +}) diff --git a/packages/devui-vue/devui/alert/index.ts b/packages/devui-vue/devui/alert/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d4b1075057600aff426cb8d4dff29b82e7190fb --- /dev/null +++ b/packages/devui-vue/devui/alert/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Alert from './src/alert' + +Alert.install = function (app: App) { + app.component(Alert.name, Alert) +} + +export { Alert } + +export default { + title: 'Alert 警告', + category: '反馈', + status: '已完成', + install(app: App): void { + app.use(Alert as any) + }, +} diff --git a/packages/devui-vue/devui/alert/src/alert-close-icon.tsx b/packages/devui-vue/devui/alert/src/alert-close-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..869b979aa6c5b416e2f5536f1b66d50b993bdbdd --- /dev/null +++ b/packages/devui-vue/devui/alert/src/alert-close-icon.tsx @@ -0,0 +1,16 @@ +const AlertCloseIcon = () => ( + + + + + + + +) +export default AlertCloseIcon diff --git a/packages/devui-vue/devui/alert/src/alert-type-icon.tsx b/packages/devui-vue/devui/alert/src/alert-type-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e409dbb719c0046667de953d09ad7b10f4025333 --- /dev/null +++ b/packages/devui-vue/devui/alert/src/alert-type-icon.tsx @@ -0,0 +1,84 @@ +import { AlertType } from './alert' + +const AlertTypeIcon = (props: { type: AlertType; }) => ( + + {(() => { + switch (props.type) { + case 'success': + return ( + + + + + ) + case 'warning': + return ( + + + + + ) + case 'info': + return ( + + + + + + + ) + case 'danger': + return ( + + + + + + + ) + default: + return null + } + })()} + +) + +export default AlertTypeIcon diff --git a/packages/devui-vue/devui/alert/src/alert.scss b/packages/devui-vue/devui/alert/src/alert.scss new file mode 100644 index 0000000000000000000000000000000000000000..c4bd6eb234e60806aee3dc5809022119fa1fd9fd --- /dev/null +++ b/packages/devui-vue/devui/alert/src/alert.scss @@ -0,0 +1,182 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/theme/font'; + +.devui-alert { + color: $devui-text; + font-size: $devui-font-size; + border: 1px solid transparent; + padding: 10px; + line-height: 20px; + border-radius: $devui-border-radius; + padding-left: 16px; + word-break: normal; + word-wrap: break-word; + + button.devui-close { + color: $devui-text; + opacity: 1; + + & > svg path { + fill: $devui-light-text; + } + + span { + color: $devui-text; + font-size: $devui-font-size; + font-weight: bold; + } + } + + &.devui-alert-success { + background-color: $devui-success-bg; + border-color: $devui-success-line; + color: $devui-text; + + button.devui-close { + & > svg path { + fill: $devui-success-line; + } + } + } + + &.devui-alert-info { + background-color: $devui-info-bg; + border-color: $devui-info-line; + color: $devui-text; + + button.devui-close { + & > svg path { + fill: $devui-info-line; + } + } + } + + &.devui-alert-warning { + background-color: $devui-warning-bg; + border-color: $devui-warning-line; + color: $devui-text; + + button.devui-close { + & > svg path { + fill: $devui-warning-line; + } + } + } + + &.devui-alert-danger { + background-color: $devui-danger-bg; + border-color: $devui-danger-line; + color: $devui-text; + + button.devui-close { + & > svg path { + fill: $devui-danger-line; + } + } + } + + &.devui-alert-simple { + border-color: $devui-line; + color: $devui-text; + + .devui-close { + & > svg path { + fill: $devui-text-weak; + } + } + } + + svg.devui-icon { + width: 16px; + height: 16px; + vertical-align: middle; + transform: translateY(-1px); //字体14px图标16px对齐问题,微调 + } + + .devui-icon.devui-icon-success { + & > g { + path { + fill: $devui-success-line; + } + + polygon { + fill: $devui-light-text; + stroke: $devui-light-text; + } + } + } + + .devui-icon.devui-icon-warning { + & > g { + path.devui-icon-warning-outer { + fill: $devui-warning-line; + } + + path.devui-icon-warning-inner { + fill: $devui-light-text; + stroke: $devui-light-text; + } + } + } + + .devui-icon.devui-icon-info { + & > g { + path.devui-icon-info-outer { + fill: $devui-info-line; + } + + path.devui-icon-info-inner { + fill: $devui-light-text; + stroke: $devui-light-text; + } + } + } + + .devui-icon.devui-icon-error { + & > g { + path.devui-icon-error-outer { + fill: $devui-danger-line; + } + + path.devui-icon-error-inner { + fill: $devui-light-text; + stroke: $devui-light-text; + } + } + } +} + +.devui-alert-icon { + margin-right: 4px; +} + +.devui-alter-close { + height: 0 !important; + margin: 0; + padding-top: 0; + padding-bottom: 0; + transform-origin: 50% 0; + transition: all 0.3s ease-in-out; +} + +.devui-alert-leave-active { + animation: alertUpOut 0.3s ease-in-out; + animation-fill-mode: both; +} + +@keyframes alertUpOut { + 0% { + transform: scaleY(1); + transform-origin: 0% 0%; + opacity: 1; + } + + 100% { + transform: scaleY(0); + transform-origin: 0% 0%; + opacity: 0; + } +} diff --git a/packages/devui-vue/devui/alert/src/alert.tsx b/packages/devui-vue/devui/alert/src/alert.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d9e42d0ce019d033721a31bab4dbddaf7a2d50f0 --- /dev/null +++ b/packages/devui-vue/devui/alert/src/alert.tsx @@ -0,0 +1,88 @@ +import { defineComponent, ref, Transition, onMounted } from 'vue' + +import AlertCloseIcon from './alert-close-icon' +import AlertTypeIcon from './alert-type-icon' + +import './alert.scss' + +export type AlertType = 'success' | 'danger' | 'warning' | 'info' | 'simple' + +export default defineComponent({ + name: 'DAlert', + props: { + type: { + type: String as () => AlertType, + default: 'info', + }, + cssClass: { + type: String, + default: '', + }, + closeable: { + type: Boolean, + default: true, + }, + showIcon: { + type: Boolean, + default: true, + }, + dismissTime: { + type: Number, + default: 0, + }, + }, + emits: ['close'], + setup(props, ctx) { + const hide = ref(false) + const closing = ref(false) + const alertEl = ref() + + const close = (event?: MouseEvent) => { + const dom = alertEl.value + dom.style.height = `${dom.offsetHeight}px` + // 重复一次后才能正确设置 height + dom.style.height = `${dom.offsetHeight}px` + closing.value = true + ctx.emit('close', event) + } + + const afterLeave = () => { + hide.value = true + closing.value = false + } + + onMounted(() => { + if (props.dismissTime) { + setTimeout(() => { + close() + }, props.dismissTime) + } + }) + + return () => { + return !hide.value ? ( + +
        + {props.closeable ? ( + + ) : null} + {props.showIcon !== false && props.type !== 'simple' ? ( + + + + ) : null} + {ctx.slots.default?.()} +
        +
        + ) : null + } + }, +}) diff --git a/packages/devui-vue/devui/anchor/index.ts b/packages/devui-vue/devui/anchor/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..37726e1ba5d89f6a4e9b212387c936e131afb764 --- /dev/null +++ b/packages/devui-vue/devui/anchor/index.ts @@ -0,0 +1,24 @@ +import { App } from 'vue' +import Anchor from './src/anchor' +import dAnchorBox from './src/d-anchor-box' +import dAnchorLink from './src/d-anchor-link' +import dAnchor from './src/d-anchor' +import './src/anchor.scss'; + +Anchor.install = function(Vue: App) { + Vue.directive(dAnchor.name, dAnchor); + Vue.directive(dAnchorLink.name, dAnchorLink); + Vue.directive(dAnchorBox.name, dAnchorBox); + Vue.component(Anchor.name, Anchor) +}; + +export { Anchor } + +export default { + title: 'Anchor 锚点', + category: '导航', + status: '50%', + install(app: App): void { + app.use(Anchor as any) + } +} diff --git a/packages/devui-vue/devui/anchor/src/anchor.scss b/packages/devui-vue/devui/anchor/src/anchor.scss new file mode 100644 index 0000000000000000000000000000000000000000..0e6c03cd355c35d70914b15afa8f05837b7fa7f7 --- /dev/null +++ b/packages/devui-vue/devui/anchor/src/anchor.scss @@ -0,0 +1,211 @@ +.mysidebar { + width: 240px; + position: absolute; + top: 0; + left: 0; + height: auto; +} + +.scrollTarget { + height: 450px !important; + overflow-y: auto; +} + +.mycontainer { + height: auto; + + // overflow-y: auto; +} + +.devui-scrollbar::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.devui-scrollbar::-webkit-scrollbar-track { + background-color: transparent; +} + +.devui-scrollbar::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: #adb0b8; + background-color: var(--devui-line, #adb0b8); +} + +.devui-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: #8a8e99; + background-color: var(--devui-placeholder, #8a8e99); +} + +body > * ::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +body > * ::-webkit-scrollbar-track { + background-color: transparent; +} + +body > * ::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: #adb0b8; + background-color: var(--devui-line, #adb0b8); +} + +body > * ::-webkit-scrollbar-thumb:hover { + background-color: #8a8e99; + background-color: var(--devui-placeholder, #8a8e99); +} + +body > * ::-webkit-scrollbar-corner { + background-color: transparent; +} + +.step-nav { + padding-top: 8px; + width: 240px; +} + +.step-nav > li { + list-style: none; + counter-increment: stepli; + padding: 0; + cursor: pointer; + height: 30px; + line-height: 1.5; + font-size: 12px; + font-size: var(--devui-font-size, 12px); + color: #575d6c; + color: var(--devui-text-weak, #575d6c); + position: relative; + display: flex; + align-items: center; +} + +.step-nav > li.active, +.step-nav > li:hover { + color: #526ecc; + color: var(--devui-brand-active, #526ecc); +} + +.step-nav > li.active::before { + border-color: #526ecc; + border-color: var(--devui-brand-active, #526ecc); +} + +.step-nav > li::before { + content: ''; + display: inline-block; + width: 12px; + height: 12px; + text-align: center; + line-height: 26px; + border-radius: 50%; + background-color: #ffffff; + background-color: var(--devui-base-bg, #ffffff); + margin-right: 20px; + border: 2px solid #dfe1e6; + border: 2px solid var(--devui-dividing-line, #dfe1e6); +} + +.step-nav > li:not(:first-of-type) { + margin-top: 32px; +} + +.step-nav > li:not(:first-of-type)::after { + content: ''; + display: block; + position: absolute; + top: -32px; + left: 5px; + width: 1px; + height: 32px; + border-left: 2px solid #dfe1e6; + border-left: 2px solid var(--devui-dividing-line, #dfe1e6); +} + +.mymain { + position: relative; +} + +.mycontent { + padding: 8px; + margin-left: 240px; + border-left: 1px solid #adb0b8; + border-left: 1px solid var(--devui-line, #adb0b8); +} + +.section-block { + min-height: 200px; + border-bottom: 1px dashed #adb0b8; + border-bottom: 1px dashed var(--devui-line, #adb0b8); +} + +.section-block.active.anchor-active-by-anchor-link { + -webkit-animation: hightlight-and-disapear 3s linear 1; + animation: hightlight-and-disapear 3s linear 1; +} + +@-webkit-keyframes hightlight-and-disapear { + 0% { + outline: medium none invert; + } + + 2% { + outline: 0 none hsla(0, 0%, 100%, 0); + } + + 10% { + outline: 1px solid #5e7ce0; + outline: 1px solid var(--devui-brand, #5e7ce0); + } + + 50% { + outline: 1px solid #5e7ce0; + outline: 1px solid var(--devui-brand, #5e7ce0); + } + + 90% { + outline: 1px solid hsla(0, 0%, 100%, 0); + } + + 99% { + outline: 0 none hsla(0, 0%, 100%, 0); + } + + to { + outline: medium none invert; + } +} + +@keyframes hightlight-and-disapear { + 0% { + outline: medium none invert; + } + + 2% { + outline: 0 none hsla(0, 0%, 100%, 0); + } + + 10% { + outline: 1px solid #5e7ce0; + outline: 1px solid var(--devui-brand, #5e7ce0); + } + + 50% { + outline: 1px solid #5e7ce0; + outline: 1px solid var(--devui-brand, #5e7ce0); + } + + 90% { + outline: 1px solid hsla(0, 0%, 100%, 0); + } + + 99% { + outline: 0 none hsla(0, 0%, 100%, 0); + } + + to { + outline: medium none invert; + } +} diff --git a/devui/rate/rate.tsx b/packages/devui-vue/devui/anchor/src/anchor.tsx similarity index 61% rename from devui/rate/rate.tsx rename to packages/devui-vue/devui/anchor/src/anchor.tsx index 33a175e38f39d5cf163b03b141797c723d93b0bb..297b31c8736cb193b9d44e45464acbebb1ade0b1 100644 --- a/devui/rate/rate.tsx +++ b/packages/devui-vue/devui/anchor/src/anchor.tsx @@ -1,12 +1,14 @@ import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-rate', + name: 'DAnchor', props: { }, - setup(props, ctx) { + setup() { return () => { - return
        devui-rate
        + return ( +
        + ) } } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/anchor/src/d-anchor-box.ts b/packages/devui-vue/devui/anchor/src/d-anchor-box.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ad8a390bc72f553fdc35577e14d0ebd1966eccf --- /dev/null +++ b/packages/devui-vue/devui/anchor/src/d-anchor-box.ts @@ -0,0 +1,94 @@ +import { setActiveLink, onScroll, randomId } from './util'; +import { inBrowser } from '../../shared/util/common-var'; +export default { + name: 'd-anchor-box', + // 滚动区域 + // 1.监听window滚动或滚动容器滚动,切换link+active,改变# + mounted(el: HTMLElement): void { + const timeId = 'm' + randomId(8); + el.id = timeId; + // 添加ng class名 + const classList = el.classList; + classList.add('mycontainer', 'mymain', timeId); + // 监听window + let windoScrollTop; + const div = document.querySelector(`#${timeId}`) as HTMLElement; + + const mysidebar = document.querySelector( + `#${timeId} .mysidebar` + ) as HTMLElement; + + const mysidebarHeight = mysidebar.clientHeight; + window.addEventListener('resize', () => { + cssChange(mysidebar, 'absolute', 0, 0); + }); + window.onscroll = function () { + //为了保证兼容性,这里取两个值,哪个有值取哪一个 + //scrollTop就是触发滚轮事件时滚轮的高度 + windoScrollTop = document.documentElement.scrollTop || document.body.scrollTop; + // 16为padding 8px *2 (上下边距) + if (!document.getElementsByClassName('scrollTarget').length) { + if ( windoScrollTop + mysidebarHeight - 16 >= div.offsetTop + div.clientHeight ) { + // 看不见 d-anchor-box区域 + cssChange( + mysidebar, + 'absolute', + div.clientHeight - mysidebarHeight - 8, + 0 + ); + } else if (windoScrollTop > div.offsetTop) { + // 即将隐藏部分 box + cssChange( + mysidebar, + 'fixed', + div.offsetTop, + div.getBoundingClientRect().left + ); + } else if (div.offsetTop >= windoScrollTop && windoScrollTop >= 0) { + // 刚开始滚动 + cssChange(mysidebar, 'absolute', 0, 0); + } else { + cssChange(mysidebar, 'absolute', div.clientHeight - mysidebarHeight - 8, 0); + } + } else { + // 刚开始滚动 + cssChange(mysidebar, 'absolute', div.scrollTop, 0); + } + }; + + addEvent(div, 'scroll', function () { + if (document.getElementsByClassName('scrollTarget').length) { + cssChange( + mysidebar, + 'fixed', + div.getBoundingClientRect().top, + div.getBoundingClientRect().left + ); + } + }); + + // 监听window滚动或滚动容器滚动,切换link+active,改变# + setActiveLink(timeId); + document.getElementsByClassName('scrollTarget').length + ? addEvent(div, 'scroll', onScroll) + : window.addEventListener('scroll', onScroll); + }, +}; + +const cssChange = ( + mysidebar: HTMLElement, + postion: string, + top: number, + left: number +) => { + mysidebar.style.position = postion; + mysidebar.style.top = top + 'px'; + mysidebar.style.left = left + 'px'; +}; +const addEvent = (function () { + if (inBrowser && window.addEventListener) { + return function (elm, type, handle) { + elm.addEventListener(type, handle, false); + }; + } +})(); diff --git a/packages/devui-vue/devui/anchor/src/d-anchor-link.ts b/packages/devui-vue/devui/anchor/src/d-anchor-link.ts new file mode 100644 index 0000000000000000000000000000000000000000..743106942d1fc6829b6b9dca1cdf1750ac71d493 --- /dev/null +++ b/packages/devui-vue/devui/anchor/src/d-anchor-link.ts @@ -0,0 +1,31 @@ +import { scrollToControl } from './util'; +interface Bind { + value: string +} + +export default { + name: 'd-anchor-link', + // 当被绑定的元素挂载到 DOM 中时…… + // 1.点击滚动到对应位置,并且高亮 + // 2.到对应位置后,改变url后hash + + mounted(el: HTMLElement,binding: Bind):void { + const parent: Element = el.parentNode as Element; + if (!parent.className) { + parent.className = 'mysidebar step-nav'; + } + el.className = 'bar-link-item'; + el.innerHTML += ''; + el.setAttribute('id', binding.value); + + el.onclick = () => { + let scrollContainer: any; + const scollToDomY = document.getElementsByName(binding.value)[0]; + document.getElementsByClassName('scrollTarget').length + ? scrollContainer = document.getElementsByClassName('scrollTarget')[0] + : scrollContainer = window + scrollToControl(scollToDomY, scrollContainer); + + } + } +}; diff --git a/packages/devui-vue/devui/anchor/src/d-anchor.ts b/packages/devui-vue/devui/anchor/src/d-anchor.ts new file mode 100644 index 0000000000000000000000000000000000000000..c594a4524fb4d3be2470eb9881e21a8709c3e92b --- /dev/null +++ b/packages/devui-vue/devui/anchor/src/d-anchor.ts @@ -0,0 +1,28 @@ +import {hightLightFn} from './util' +interface Bind { + value: string + } + +export default { + name: 'd-anchor', + // 挂载事件到dom + // 1.点击对应link高亮 + // 2.href+#+bing.value + + mounted(el: HTMLElement, binding: Bind):void { + const parent: Element = el.parentNode as Element; + if (!parent.className) { + parent.className = 'mycontent' + } + el.innerHTML = '' + el.innerHTML + el.className = 'section-block'; + // anchor-active-by-scroll + el.setAttribute('name',binding.value); + el.onclick = e => { + hightLightFn(binding.value); + + } + } +}; + + \ No newline at end of file diff --git a/packages/devui-vue/devui/anchor/src/util.ts b/packages/devui-vue/devui/anchor/src/util.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ddbbece992f74ab8556c5e63a35a74d7968b7eb --- /dev/null +++ b/packages/devui-vue/devui/anchor/src/util.ts @@ -0,0 +1,199 @@ +let repeatCount = 0; +let cTimeout; +const timeoutIntervalSpeed = 10; +let hashName:string; +// 滚动是由于点击产生 +let scollFlag = false; +function elementPosition(obj: HTMLElement) { + let curleft = 0, curtop = 0; + curleft = obj.offsetLeft; + curtop = obj.offsetTop; + return { x: curleft, y: curtop }; +} + +export function scrollToControl(elem: HTMLElement, container: HTMLElement):void { + hashName = elem.getAttribute('name'); + scollFlag = true; + const tops = container.scrollTop>=0 ? container.scrollTop : -(document.getElementsByClassName('mycontainer')[0] as HTMLElement).offsetTop; + let scrollPos: number = elementPosition(elem).y - tops ; + + scrollPos = scrollPos - document.documentElement.scrollTop; + const remainder: number = scrollPos % timeoutIntervalSpeed; + const repeatTimes = Math.abs((scrollPos - remainder) / timeoutIntervalSpeed); + if (scrollPos < 0 && container || elem.getBoundingClientRect().top < container.offsetTop) { + window.scrollBy(0, elem.getBoundingClientRect().top-container.offsetTop-16) + } + // 多个计时器达到平滑滚动效果 + scrollSmoothly(scrollPos, repeatTimes, container) +} + + +function scrollSmoothly(scrollPos: number, repeatTimes: number, container: HTMLElement):void { + if (repeatCount <= repeatTimes) { + scrollPos > 0 + ? container.scrollBy(0, timeoutIntervalSpeed) + : container.scrollBy(0, -timeoutIntervalSpeed) + } + else { + repeatCount = 0; + clearTimeout(cTimeout); + history.replaceState(null, null, document.location.pathname + '#' + hashName); + + hightLightFn(hashName) + setTimeout(() => { + scollFlag = false; + }, 310) + return ; + + } + repeatCount++; + cTimeout = setTimeout(() => { + scrollSmoothly(scrollPos, repeatTimes, container) + }, 10) +} + +// 高亮切换 +export function hightLightFn(hashName:string):void { + + const childLength = document.getElementsByClassName('mysidebar')[0].children.length; + + for (let i = 0; i < childLength; i++) { + + if (document.getElementsByClassName('mysidebar')[0].children[i].classList.value.indexOf('active') > -1) { + + document.getElementsByClassName('mysidebar')[0].children[i].classList.remove('active') + } + } + document.getElementById(hashName).classList.add('active'); + + + +} +let activeLink = null; +let rootActiveLink = null; +let rootClassName = ''; +export const setActiveLink = (timeId:string):void => { + if (scollFlag) { return } + timeId ? rootClassName = timeId : rootClassName = document.getElementsByClassName('mymain')[0].id + + const sidebarLinks = getSidebarLinks(rootClassName); + const anchors = getAnchors(sidebarLinks); + try { + anchors.forEach((index,i)=> { + + const anchor:HTMLAnchorElement = anchors[i]; + const nextAnchor:HTMLAnchorElement = anchors[i + 1]; + + const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor); + if (isActive) { + history.replaceState(null, document.title, hash ? hash as string : ' '); + activateLink(hash); + throw Error(hash+''); + } + }) + } catch (e) { + } + +} + +function throttleAndDebounce(fn:any, delay:number):any { + let timeout:any; + let called = false; + return () => { + if (timeout) { + clearTimeout(timeout); + } + if (!called) { + fn(); + called = true; + setTimeout(() => { + called = false; + }, delay); + } + else { + timeout = setTimeout(fn, delay); + } + }; +} + +export const onScroll = throttleAndDebounce(setActiveLink, 300); + +function activateLink(hash:string | boolean):void { + deactiveLink(activeLink); + deactiveLink(rootActiveLink); + hash + ? activeLink = document.querySelector(`${hash}`) + : activeLink = document.querySelector(`.${rootClassName} ul li`) + if (!activeLink) { + return; + } + + if (!scollFlag) { + hash && hightLightFn((hash as string).split('#')[1] ) + }else { + hightLightFn(hashName) + } + // + // also add active class to parent h2 anchors + const rootLi = activeLink.closest('.mycontainer > ul > li'); + if (rootLi && rootLi !== activeLink.parentElement) { + rootActiveLink = rootLi; + rootActiveLink && rootActiveLink.classList.add('active'); + } + else { + rootActiveLink = null; + } +} +function deactiveLink(link:HTMLElement):void { + link && link.classList.remove('active'); +} +function getPageOffset():number { + return (document.querySelector('.mysidebar ') as HTMLElement).getBoundingClientRect().y; +} + +function getAnchorTop(anchor:HTMLAnchorElement):number { + const pageOffset = getPageOffset(); + return anchor.parentElement.offsetTop - pageOffset - 5; +} + +function isAnchorActive(index:number, anchor:HTMLAnchorElement, nextAnchor:HTMLAnchorElement) { + let scrollTop:number; + document.getElementsByClassName('scrollTarget').length + ? scrollTop = document.getElementsByClassName('scrollTarget')[0].scrollTop + : scrollTop = document.documentElement.scrollTop || document.body.scrollTop + if (index === 0 && scrollTop === 0) { + return [true, null]; + } + + if (scrollTop < getAnchorTop(anchor)) { + return [false, null]; + } + if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) { + + return [true, decodeURIComponent(anchor.hash)]; + } + + return [false, null]; +} + +function getSidebarLinks(rootClassName:string):Array { + return [].slice.call(document.querySelectorAll(`.${rootClassName} > .step-nav > li.bar-link-item > a`)); +} + +function getAnchors(sidebarLinks:Array):Array { + return [].slice + .call(document.querySelectorAll('.box-anchor')) + .filter((anchor:HTMLAnchorElement) => sidebarLinks.some(( sidebarLink:HTMLAnchorElement ) => sidebarLink.hash === anchor.hash )); +} + + +export const randomId = function(n=8):string { // 生成n位长度的字符串 + const str = 'abcdefghijklmnopqrstuvwxyz0123456789'; // 可以作为常量放到random外面 + let result = ''; + for(let i = 0; i < n; i++) { + result += str[parseInt((Math.random() * str.length).toString())]; + } + return result; +} + + diff --git a/packages/devui-vue/devui/avatar/__tests__/avatar.spec.ts b/packages/devui-vue/devui/avatar/__tests__/avatar.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..18dc946597b8ff4152c7ead3833c369a1afa1f14 --- /dev/null +++ b/packages/devui-vue/devui/avatar/__tests__/avatar.spec.ts @@ -0,0 +1,113 @@ +import { mount } from '@vue/test-utils' +import Avatar from '../src/avatar' + +describe('avatar', () => { + describe('name text shown correctly', () => { + it('chinese name pick last two character', async () => { + const wrapper = mount(Avatar, { + props: { + name: '组件头像', + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('头像') + }) + it('should only show one character when width less than 30', () => { + const wrapper = mount(Avatar, { + props: { + name: '组件头像', + width: 25, + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('组') + }) + it('one word name pick first two character', () => { + const name = 'MyAvatar' + const wrapper = mount(Avatar, { + props: { + name, + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('MY') + }) + it('display origin name when name length less than 2', () => { + const wrapper = mount(Avatar, { + props: { + name: 'A', + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('A') + }) + it('should empty name display none text', () => { + const wrapper = mount(Avatar, { + props: { + name: '', + }, + }) + expect(wrapper.find('svg').exists()).toBe(true) + }) + it('two words name pick first character of two words', () => { + const wrapper = mount(Avatar, { + props: { + name: 'Avatar1 Avatar2', + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('AA') + }) + }) + + describe('background should be ok', () => { + it('should be male background', () => { + const wrapper = mount(Avatar, { + props: { + name: 'avatar', + gender: 'male', + }, + }) + expect(wrapper.find('.devui-avatar-background-1').exists()).toBe(true) + }) + it('should be female background', () => { + const wrapper = mount(Avatar, { + props: { + name: 'avatar', + gender: 'female', + }, + }) + expect(wrapper.find('.devui-avatar-background-0').exists()).toBe(true) + }) + it('gender error should throw error', () => { + expect(() => { + mount(Avatar, { + props: { + name: 'avatar', + gender: 'unknown', + }, + }) + }).toThrowError('gender must be "Male" or "Female"') + }) + }) + + describe('custom avatar', () => { + it('should custom text display correct', () => { + const wrapper = mount(Avatar, { + props: { + customText: '自定义', + width: 80, + height: 80, + }, + }) + expect(wrapper.find('.devui-avatar-style').text()).toBe('自定义') + expect( + wrapper + .find('.devui-avatar-style') + .attributes('style') + .includes('height: 80px') + ).toBe(true) + expect( + wrapper + .find('.devui-avatar-style') + .attributes('style') + .includes('width: 80px') + ).toBe(true) + }) + }) +}) diff --git a/packages/devui-vue/devui/avatar/index.ts b/packages/devui-vue/devui/avatar/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea509fcd8dab3782785243f7e52004cd02e942da --- /dev/null +++ b/packages/devui-vue/devui/avatar/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Avatar from './src/avatar' + +Avatar.install = function (app: App) { + app.component(Avatar.name, Avatar) +} + +export { Avatar } + +export default { + title: 'Avatar 头像', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Avatar as any) + }, +} diff --git a/packages/devui-vue/devui/avatar/src/avatar-body-icon.tsx b/packages/devui-vue/devui/avatar/src/avatar-body-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..361bf136aec32eca71a82fdc22d79ef286d986dc --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/avatar-body-icon.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue' +import { IconBody } from './icon-body' +export default defineComponent({ + name: 'AvatarBodyIcon', + props: { + width: { + type: Number, + default: 16, + }, + height: { + type: Number, + default: 16, + }, + }, + render() { + const { width, height } = this + return + }, +}) diff --git a/packages/devui-vue/devui/avatar/src/avatar-nobody-icon.tsx b/packages/devui-vue/devui/avatar/src/avatar-nobody-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9553ad45caca31558ad50d7aa791b6e8aa22554f --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/avatar-nobody-icon.tsx @@ -0,0 +1,20 @@ +import { defineComponent } from 'vue' +import { IconNobody } from './icon-nobody' + +export default defineComponent({ + name: 'AvatarNobodyIcon', + props: { + width: { + type: Number, + default: 16, + }, + height: { + type: Number, + default: 16, + }, + }, + render() { + const { width, height } = this + return + }, +}) diff --git a/packages/devui-vue/devui/avatar/src/avatar.scss b/packages/devui-vue/devui/avatar/src/avatar.scss new file mode 100644 index 0000000000000000000000000000000000000000..8637a12534650b31448ad6a9b75736b2737a5204 --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/avatar.scss @@ -0,0 +1,19 @@ +@import '../../style/theme/color'; + +.devui-avatar { + display: inline-block; +} + +.devui-avatar-style { + display: inline-block; + text-align: center; + color: $devui-light-text; +} + +.devui-avatar-background-0 { + background-color: #ff8b87; +} + +.devui-avatar-background-1 { + background-color: #7693f5; +} diff --git a/packages/devui-vue/devui/avatar/src/avatar.tsx b/packages/devui-vue/devui/avatar/src/avatar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3eda9d2b79aeefc8ec0a0a89def55c45e9c5ad8e --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/avatar.tsx @@ -0,0 +1,207 @@ +import { defineComponent, watch, toRefs, ref } from 'vue' + +import AvatarBodyIcon from './avatar-body-icon' +import AvatarNoBodyIcon from './avatar-nobody-icon' + +import './avatar.scss' + +export default defineComponent({ + name: 'DAvatar', + props: { + name: { + type: String, + default: null, + }, + gender: { + type: String as () => 'male' | 'female' | string, + default: null, + }, + width: { + type: Number, + default: 36, + }, + height: { + type: Number, + default: 36, + }, + isRound: { + type: Boolean, + default: true, + }, + imgSrc: { + type: String, + default: '', + }, + customText: { + type: String, + default: null, + }, + }, + setup(props) { + const { name, width, height, customText, gender, imgSrc, isRound } = + toRefs(props) + const isNobody = ref(true) + const isErrorImg = ref(false) + const fontSize = ref(12) + const code = ref() + const nameDisplay = ref() + + const calcValues = (nameInput: string): void => { + const userName = nameInput + const minNum = Math.min(width.value, height.value) + if (userName) { + isNobody.value = false + setDisplayName(userName, minNum) + } else if (userName === '') { + isNobody.value = false + nameDisplay.value = '' + } else { + isNobody.value = true + } + fontSize.value = minNum / 4 + 3 + } + + const setDisplayName = (name: string, width: number): void => { + if (customText.value) { + nameDisplay.value = customText.value + getBackgroundColor(customText.value.substr(0, 1)) + return + } + if (name.length < 2) { + nameDisplay.value = name + } else { + // 以中文开头显示最后两个字符 + if (/^[\u4e00-\u9fa5]/.test(name)) { + nameDisplay.value = name.substr(name.length - 2, 2) + // 英文开头 + } else if (/^[A-Za-z]/.test(name)) { + // 含有两个及以上,包含空格,下划线,中划线分隔符的英文名取前两个字母的首字母 + if (/[_ -]/.test(name)) { + const str_before = name.split(/_|-|\s+/)[0] + const str_after = name.split(/_|-|\s+/)[1] + nameDisplay.value = + str_before.substr(0, 1).toUpperCase() + + str_after.substr(0, 1).toUpperCase() + } else { + // 一个英文名的情况显示前两个字母 + nameDisplay.value = name.substr(0, 2).toUpperCase() + } + } else { + // 非中英文开头默认取前两个字符 + nameDisplay.value = name.substr(0, 2) + } + } + if (width < 30) { + nameDisplay.value = name.substr(0, 1).toUpperCase() + } + getBackgroundColor(name.substr(0, 1)) + } + + const getBackgroundColor = (char: string): void => { + if (gender.value) { + if (gender.value.toLowerCase() === 'male') { + code.value = 1 + } else if (gender.value.toLowerCase() === 'female') { + code.value = 0 + } else { + throw new Error('gender must be "Male" or "Female"') + } + return + } + const unicode = char.charCodeAt(0) + code.value = unicode % 2 + } + const showErrorAvatar = (): void => { + isErrorImg.value = true + } + + calcValues(customText.value ? customText.value : name.value) + + watch([name, width, height, customText, gender], () => { + calcValues(customText.value ? customText.value : name.value) + }) + return { + showErrorAvatar, + isErrorImg, + code, + fontSize, + nameDisplay, + isNobody, + } + }, + render() { + const { + imgSrc, + showErrorAvatar, + height, + width, + isRound, + isErrorImg, + code, + fontSize, + nameDisplay, + isNobody, + } = this + const imgElement = ( + + ) + const hasImgSrc = imgSrc && !isErrorImg ? imgElement : null + + const nameElement = ( + + {nameDisplay} + + ) + const hasNameDisplay = + !imgSrc && !isNobody && nameDisplay?.length !== 0 ? nameElement : null + + const noNameElement = ( + + + + ) + const hasNoDisplayName = + !imgSrc && !isNobody && nameDisplay?.length === 0 ? noNameElement : null + + const noBodyElement = ( + + + + ) + const noBody = (!imgSrc && isNobody) || isErrorImg ? noBodyElement : null + return ( + + {hasImgSrc} + {hasNameDisplay} + {hasNoDisplayName} + {noBody} + + ) + }, +}) diff --git a/packages/devui-vue/devui/avatar/src/icon-body.tsx b/packages/devui-vue/devui/avatar/src/icon-body.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f9078521a8851c3f8d1b5bebf0255bded9149ae9 --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/icon-body.tsx @@ -0,0 +1,30 @@ +export const IconBody = (props: { width: number; height: number; }) => { + const { width, height } = props + return ( + + + + + + + ) +} diff --git a/packages/devui-vue/devui/avatar/src/icon-nobody.tsx b/packages/devui-vue/devui/avatar/src/icon-nobody.tsx new file mode 100644 index 0000000000000000000000000000000000000000..20359e40f34b74b0692c7d4b2bca9d1607060697 --- /dev/null +++ b/packages/devui-vue/devui/avatar/src/icon-nobody.tsx @@ -0,0 +1,29 @@ +export const IconNobody = (props: { width: number; height: number; }) => { + const { width, height } = props + return ( + + + + + + + ) +} diff --git a/packages/devui-vue/devui/back-top/__tests__/back-top.spec.ts b/packages/devui-vue/devui/back-top/__tests__/back-top.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..81a160a5a19ee2ecb1f5b34b6b34689c50a30784 --- /dev/null +++ b/packages/devui-vue/devui/back-top/__tests__/back-top.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { BackTop } from '../index'; + +describe('back-top test', () => { + it('back-top init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/back-top/index.ts b/packages/devui-vue/devui/back-top/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a5f745c6a7af46599e3d69424067a3c2bea361b --- /dev/null +++ b/packages/devui-vue/devui/back-top/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import BackTop from './src/back-top' + +BackTop.install = function (app: App): void { + app.component(BackTop.name, BackTop) +} + +export { BackTop } + +export default { + title: 'BackTop 回到顶部', + category: '导航', + status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(BackTop as any) + } +} diff --git a/packages/devui-vue/devui/back-top/src/assets/top.svg b/packages/devui-vue/devui/back-top/src/assets/top.svg new file mode 100644 index 0000000000000000000000000000000000000000..85155751f6a829d715675be6cb168316cf29ab65 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/assets/top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/devui-vue/devui/back-top/src/back-top-types.ts b/packages/devui-vue/devui/back-top/src/back-top-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f76d1cda94731627d7ff7f283a1370b35a56c66 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/back-top-types.ts @@ -0,0 +1,20 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export type Position = { + position: 'fixed' + bottom: string + right: string +} + +export const backTopProps = { + bottom: { + type: String, + default: '50px' + }, + right: { + type: String, + default: '30px' + } +} as const + +export type BackTopProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/back-top/src/back-top.scss b/packages/devui-vue/devui/back-top/src/back-top.scss new file mode 100644 index 0000000000000000000000000000000000000000..18685214660f54b68cde866f7200e44b75ac0883 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/back-top.scss @@ -0,0 +1,28 @@ +@import '../../styles-var/devui-var'; + +.devui-back-top { + width: 40px; + height: 40px; + cursor: pointer; + z-index: 9; + .devui-back-top-base { + width: 40px; + height: 40px; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + opacity: 1; + } + } + .devui-back-top-content { + opacity: 0.4; + background-color: $devui-text-weak; + } + .devui-backtop-custom { + background-color: #fff; + } +} diff --git a/packages/devui-vue/devui/back-top/src/back-top.tsx b/packages/devui-vue/devui/back-top/src/back-top.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b95b0405dff3bc0134ca1a3fa90f7869303aea1c --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/back-top.tsx @@ -0,0 +1,44 @@ +import { defineComponent, ref } from 'vue' +import { backTopProps, BackTopProps } from './back-top-types' +import { usePosition } from './hooks' +import './back-top.scss' +import IconTop from './assets/top.svg' + +export default defineComponent({ + name: 'DBackTop', + props: backTopProps, + emits: [], + setup(props: BackTopProps, ctx) { + const position = usePosition(props) + const slots = ctx.slots + + const scrollToTop = () => { + // 运行在浏览器则调用该方法 + window && + window.scrollTo({ + top: 0, + left: 0, + behavior: 'smooth' //平滑滚动 + }) + } + + return () => ( +
        +
        + {slots.default ? slots.default() : } +
        +
        + ) + } +}) diff --git a/packages/devui-vue/devui/back-top/src/hooks/index.ts b/packages/devui-vue/devui/back-top/src/hooks/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..22441ce6b655e4804964563e2d8beac34ad0aa73 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/hooks/index.ts @@ -0,0 +1,3 @@ +import usePosition from './usePosition.ts' + +export { usePosition } diff --git a/packages/devui-vue/devui/back-top/src/hooks/usePosition.ts b/packages/devui-vue/devui/back-top/src/hooks/usePosition.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7c80f161f86ed297e7faf125afdba93e01beeb6 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/hooks/usePosition.ts @@ -0,0 +1,11 @@ +import { BackTopProps, Position } from '../back-top-types' + +export default function (props: BackTopProps): Position { + const { bottom, right } = props + + return { + position: 'fixed', + bottom, + right + } +} diff --git a/packages/devui-vue/devui/badge/__tests__/badge.spec.ts b/packages/devui-vue/devui/badge/__tests__/badge.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f18aa0e254a397e99319bf19d2d8c69741810dfb --- /dev/null +++ b/packages/devui-vue/devui/badge/__tests__/badge.spec.ts @@ -0,0 +1,50 @@ +import { mount } from '@vue/test-utils' +import DBadge from '../src/badge' + +const SLOT = 'This is a slot test' + +describe('badge', () => { + it('badge base', () => { + const wrapper = mount(DBadge, { + props: { count: 80 }, + slots: { default: SLOT } + }) + expect(wrapper.vm.count).toEqual(80) + }) + + it('badge dot', () => { + const wrapper = mount(DBadge, { + props: { showDot: true }, + slots: { default: SLOT } + }) + expect(wrapper.find('.devui-badge-content.devui-badge-content-dot').exists()).toBe(true) + }) + + it('badge max', () => { + const wrapper = mount(DBadge, { + props: { count: 100 } + }) + expect(wrapper.find('.devui-badge-content').text()).toBe('99+') + + const wrapper2 = mount(DBadge, { + props: { count: 100, maxCount: 1000 } + }) + expect(wrapper2.find('.devui-badge-content').text()).toBe('100') + }) + + it('badge bgColor', () => { + const wrapper = mount(DBadge, { + props: { bgColor: 'red' }, + slots: { default: SLOT } + }) + expect(wrapper.find('.devui-badge-content').attributes().style).toBe('background: red;') + }) + + it('badge offsetXY', () => { + const wrapper = mount(DBadge, { + props: { offsetXY: [-10, 10], badgePos: 'top-right' }, + slots: { default: SLOT } + }) + expect(wrapper.find('.devui-badge-content').attributes().style).toBe('top: 10px; right: -10px;') + }) +}) diff --git a/packages/devui-vue/devui/badge/index.ts b/packages/devui-vue/devui/badge/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff57b3149ea04db69e5e042f4b38f618534cb5ad --- /dev/null +++ b/packages/devui-vue/devui/badge/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Badge from './src/badge' + +Badge.install = function (app: App) { + app.component(Badge.name, Badge) +} + +export { Badge } + +export default { + title: 'Badge 徽标', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Badge as any) + } +} diff --git a/packages/devui-vue/devui/badge/src/badge-types.ts b/packages/devui-vue/devui/badge/src/badge-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0a5ba2fdf16423c9c7d9c949cef2e977eaa4239 --- /dev/null +++ b/packages/devui-vue/devui/badge/src/badge-types.ts @@ -0,0 +1,41 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +type BadgeStatusType = PropType<'danger' | 'warning' | 'waiting' | 'success' | 'info'> +type BadgePositionType = PropType<'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'> + +const badgeStatusType = ['danger', 'warning', 'waiting', 'success', 'info'] +const badgePositionType = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] + +export const badgeProps = { + count: { + type: [Number, String] + }, + maxCount: { + type: Number, + default: 99 + }, + showDot: { + type: Boolean, + default: false + }, + status: { + type: String as BadgeStatusType, + validator: (val: string) => badgeStatusType.includes(val) + }, + badgePos: { + type: String as BadgePositionType, + default: 'top-right', + validator: (val: string) => badgePositionType.includes(val) + }, + offsetXY: { + type: Array + }, + bgColor: { + type: String + }, + textColor: { + type: String + } +} + +export type BadgeProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/badge/src/badge.scss b/packages/devui-vue/devui/badge/src/badge.scss new file mode 100644 index 0000000000000000000000000000000000000000..9f72576e39863b6417ab074cc7425a3f5c320a33 --- /dev/null +++ b/packages/devui-vue/devui/badge/src/badge.scss @@ -0,0 +1,76 @@ +@import '../../style/theme/color'; +@import '../../style/theme/font'; + +.devui-badge { + position: relative; + display: inline-block; + + .devui-badge-content { + font-size: $devui-font-size; + color: $devui-light-text; + + &-count { + padding: 0 4px; + min-width: 16px; + height: 16px; + line-height: 16px; + border-radius: 8px; + background: $devui-brand; + text-align: center; + } + + &-danger { + background: $devui-danger; + } + + &-warning { + background: $devui-warning; + } + + &-waiting { + background: $devui-waiting; + } + + &-success { + background: $devui-success; + } + + &-info { + background: $devui-info; + } + + &-top-left { + left: 0; + top: 0; + transform: translate(-50%, -50%); + } + + &-top-right { + right: 0; + top: 0; + transform: translate(50%, -50%); + } + + &-bottom-left { + left: 0; + bottom: 0; + transform: translate(-50%, 50%); + } + + &-bottom-right { + right: 0; + bottom: 0; + transform: translate(50%, 50%); + } + + &-fixed { + position: absolute; + } + + &-dot { + width: 6px; + height: 6px; + border-radius: 50%; + } + } +} diff --git a/packages/devui-vue/devui/badge/src/badge.tsx b/packages/devui-vue/devui/badge/src/badge.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ad6024bd19b25e1ff888002fe2bd261115625e86 --- /dev/null +++ b/packages/devui-vue/devui/badge/src/badge.tsx @@ -0,0 +1,65 @@ +import './badge.scss' + +import { defineComponent, computed } from 'vue' +import { badgeProps, BadgeProps } from './badge-types' + +export default defineComponent({ + name: 'DBadge', + props: badgeProps, + emits: [], + setup(props: BadgeProps, ctx) { + const className = computed(() => { + const base = 'devui-badge-content' + return [ + base, + props.showDot ? `${base}-dot` : `${base}-count`, + props.status && `${base}-${props.status}`, + ctx.slots.default && props.badgePos && `${base}-${props.badgePos}`, + ctx.slots.default && `${base}-fixed` + ].join(' ') + }) + + const style = computed(() => { + const styleMap = { + bgColor: 'background', + textColor: 'color' + } + const ret = Object.keys(styleMap).reduce((ret, key) => { + if (props[key]) { + ret[styleMap[key]] = props[key] + } + return ret + }, {}) + // 偏移量 + if (ctx.slots.default && props.offsetXY) { + const [x, y]: Array = props.offsetXY as Array + const [yName, xName] = (props.badgePos as string).split('-') + ret[yName] = y + 'px' + ret[xName] = x + 'px' + } + + return ret + }) + + const text = computed(() => { + if (props.showDot) { + return + } + if (typeof props.count === 'number' && typeof props.maxCount === 'number') { + return props.count > props.maxCount ? `${props.maxCount}+` : props.count + } + return props.count + }) + + return () => { + return ( +
        + {ctx.slots.default?.()} +
        + {text.value} +
        +
        + ) + } + } +}) diff --git a/packages/devui-vue/devui/breadcrumb/__tests__/breadcrumb.spec.ts b/packages/devui-vue/devui/breadcrumb/__tests__/breadcrumb.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f05cf80d70b205cc2d6e103c1dd970cef04f98c0 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/__tests__/breadcrumb.spec.ts @@ -0,0 +1,55 @@ +import { mount } from '@vue/test-utils' +import DBreadcrumb from '../src/breadcrumb' +import DBreadcrumbItem from '../src/breadcrumb-item' + +describe('breadcrumb', () => { + it('should breadcrumb display correctly', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + DevUI + + + Breadcrumb + + ` + }) + const items = wrapper.findAll('.devui-breadcrumb-item') + const separators = wrapper.findAll('.devui-breadcrumb-separator') + expect(items.length).toBe(2) + expect(separators.length).toBe(2) + }) + it('should separator support custom', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + A + + ` + }) + expect(wrapper.find('.devui-breadcrumb-separator').text()).toBe('?') + }) + + it('should `to` work correctly', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + A + + ` + }) + expect(wrapper.find('.is-link')).toBeTruthy() + }) +}) diff --git a/packages/devui-vue/devui/breadcrumb/index.ts b/packages/devui-vue/devui/breadcrumb/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d481edf86ea83c715f7589d49b2ee025e94b8834 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/index.ts @@ -0,0 +1,19 @@ +import type { App } from 'vue' +import Breadcrumb from './src/breadcrumb' +import BreadcrumbItem from './src/breadcrumb-item' + +Breadcrumb.install = function (app: App): void { + app.component(Breadcrumb.name, Breadcrumb) + app.component(BreadcrumbItem.name, BreadcrumbItem) +} + +export { Breadcrumb } + +export default { + title: 'Breadcrumb 面包屑', + category: '导航', + status: '50%', + install(app: App): void { + app.use(Breadcrumb as any) + }, +} diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item-types.ts b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..a118789c0dfba2cdb45d2128fd0a244a7220ef1b --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item-types.ts @@ -0,0 +1,46 @@ +import type { ExtractPropTypes, PropType } from 'vue' + +export interface MenuConfig { + name: string // 显示的名称 + link: string // 跳转的路径,可为绝对路径与相对路径,注意需要与路由的配置一致 + target?: string // 规定在何处打开链接文档 +} + +export const breadcrumbItemProps = { + /** + * 可选,是否需要显示下拉箭头及下拉列表内容 + */ + showMenu: { + type: Boolean, + default: false + }, + /** + * 可选,showMenu 为 true 时传入,下拉列表的显示内容 + */ + menuList: { + type: Array as PropType> + }, + /** + * 可选,showMenu 为 true 时传入,下拉列表是否需要搜索功能 + */ + isSearch: { + type: Boolean, + dafault: false + }, + /** + * 路由跳转对象,同 vue-router 的 to + */ + to: { + type: [String, Object] as PropType>, + default: '' + }, + /** + * 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 + */ + replace: { + type: Boolean, + default: false + } +} as const + +export type BreadcrumbItemProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.scss b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.scss new file mode 100644 index 0000000000000000000000000000000000000000..5c3a604685145422edde0ea44ec1e0bee8dc9d51 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.scss @@ -0,0 +1,48 @@ +@import '../../style/theme/color'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; + +.devui-breadcrumb-font-style { + font-size: $devui-font-size; + color: $devui-aide-text; + line-height: 18px; +} + +.devui-breadcrumb-item { + @extend.devui-breadcrumb-font-style; + + cursor: auto; + + a { + @extend.devui-breadcrumb-font-style; + + cursor: pointer; + + &:hover { + color: $devui-text; + text-decoration: none; + } + } + + a, + span { + transition: + color $devui-animation-duration-slow + $devui-animation-ease-in-out-smooth; + } + + .is-link { + cursor: pointer; + + &:hover { + color: $devui-text; + text-decoration: none; + } + } +} + +.devui-breadcrumb-separator { + @extend.devui-breadcrumb-font-style; + + margin: 0 4px; +} diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.tsx b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f8f1ff686f9fa5f973ad8512de8f311ea15aaa72 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-item.tsx @@ -0,0 +1,51 @@ +import { + defineComponent, + inject, + onMounted, + onBeforeUnmount, + ref, + getCurrentInstance +} from 'vue' + +import { + breadcrumbItemProps, + BreadcrumbItemProps +} from './breadcrumb-item-types' +import './breadcrumb-item.scss' + +export default defineComponent({ + name: 'DBreadcrumbItem', + props: breadcrumbItemProps, + setup(props: BreadcrumbItemProps, { slots }) { + const separatorIcon = inject('separatorIcon') + const linkClass = props.to ? 'is-link' : '' + const link = ref(null) + const instance = getCurrentInstance() + const router = instance.appContext.config.globalProperties.$router + const handleClickLink = () => { + if (!props.to || !router) return + props.replace ? router.replace(props.to) : router.push(props.to) + } + onMounted(() => { + link.value.addEventListener('click', handleClickLink) + }) + + onBeforeUnmount(() => { + link.value.removeEventListener('click', handleClickLink) + }) + + return () => { + const renderBreadcrumbSperator = () => { + return {separatorIcon} + } + return ( +
        + + {slots?.default()} + + {renderBreadcrumbSperator()} +
        + ) + } + } +}) diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb-types.ts b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..caebf81bf3e903663ea1946f586e2925af6e3859 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb-types.ts @@ -0,0 +1,28 @@ +import type { ExtractPropTypes, PropType } from 'vue' + +export interface SourceConfig { + title: string // 显示的名称 + link?: string // 跳转的路径 + target?: string // 规定在何处打开链接文档 + noNavigation?: boolean // 链接是否不可跳转,一般用于当前所处位置不可跳转的配置 + linkType?: 'hrefLink' | 'routerLink' // 链接类型,默认为'hrefLink'方式,可选'hrefLink' 或 'routerLink' + replace: boolean // 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 +} + +export const breadcrumbProps = { + /** + * 可选,面包屑根据配置的 source 按照默认渲染方式显示 + */ + source: { + type: Array as PropType>, + default: [] + }, + /** + * 可选,自定义分隔符样式 + */ + separatorIcon: { + type: String + } +} as const + +export type BreadcrumbProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb.scss b/packages/devui-vue/devui/breadcrumb/src/breadcrumb.scss new file mode 100644 index 0000000000000000000000000000000000000000..231d8ebbc8e2fd86184367490f4e05d45d513a7b --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb.scss @@ -0,0 +1,10 @@ +.devui-breadcrumb { + display: flex; + align-items: center; + + .devui-breadcrumb-item:last-child { + .devui-breadcrumb-separator { + display: none; + } + } +} diff --git a/packages/devui-vue/devui/breadcrumb/src/breadcrumb.tsx b/packages/devui-vue/devui/breadcrumb/src/breadcrumb.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6b5ffeb24d2c3eef01f5af35e43ff5e71bfbaf28 --- /dev/null +++ b/packages/devui-vue/devui/breadcrumb/src/breadcrumb.tsx @@ -0,0 +1,58 @@ +import { defineComponent, provide } from 'vue' +import { + breadcrumbProps, + BreadcrumbProps, + SourceConfig +} from './breadcrumb-types' +import DBreadcrumbItem from './breadcrumb-item' +import { getPropsSlot } from '../../shared/util/props-util' +import './breadcrumb.scss' + +export default defineComponent({ + name: 'DBreadcrumb', + components: { + DBreadcrumbItem + }, + props: breadcrumbProps, + setup(props: BreadcrumbProps, { slots }) { + const separatorIcon = getPropsSlot(slots, props, 'separatorIcon') ?? '/' + provide('separatorIcon', separatorIcon) + + const renderBreadcrumbItemRouted = (item) => { + return ( + + {item.title} + + ) + } + const renderBreadItemList = (source: SourceConfig[]) => { + return source.map((item: SourceConfig) => { + if (!item.noNavigation && item.linkType === 'routerLink') { + return renderBreadcrumbItemRouted(item) + } + return ( + + {/* hrefLink */} + {!item.noNavigation && + (!item.linkType || item.linkType === 'hrefLink') ? ( + + {item.title} + + ) : null} + {/* normal */} + {item.noNavigation ? {item.title} : null} + + ) + }) + } + return () => { + return ( +
        + {props.source && props.source.length + ? renderBreadItemList(props.source) + : slots?.default()} +
        + ) + } + } +}) diff --git a/packages/devui-vue/devui/button/__tests__/button.spec.ts b/packages/devui-vue/devui/button/__tests__/button.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..a03789608d779bd85e599bcd55322d7e4de1907e --- /dev/null +++ b/packages/devui-vue/devui/button/__tests__/button.spec.ts @@ -0,0 +1,73 @@ +import { mount } from '@vue/test-utils'; +import Button from '../src/button'; + +describe('d-button', () => { + it('btnStyle', () => { + const wrapper = mount(Button, { + props: { btnStyle: 'danger' }, + }); + expect(wrapper.find('.devui-btn').classes()).toContain('devui-btn-danger'); + }); + + it('size', () => { + const wrapper = mount(Button, { + props: { size: 'sm' }, + }); + expect(wrapper.find('.devui-btn-sm').exists()).toBeTruthy(); + }); + + it('type', () => { + const wrapper = mount(Button, { + props: { type: 'submit' }, + }).find('button'); + expect(wrapper.attributes('type')).toBe('submit'); + }); + + it('click', async () => { + const handleClick = jest.fn(); + const wrapper = mount(Button, { + props: { + showLoading: false, + onClick: handleClick + }, + }); + await wrapper.find('.devui-btn').trigger('click'); + expect(handleClick).toBeCalled(); + }); + + // 目前还不支持 loading + // it('loading', async () => { + // const handleClick = jest.fn(); + // const wrapper = mount(Button, { + // props: { + // showLoading: true, + // btnClick: handleClick + // }, + // }); + // await wrapper.trigger('click'); + // expect(handleClick).not.toBeCalled(); + // }); + + it('disabled', async () => { + const handleClick = jest.fn(); + const wrapper = mount(Button, { + props: { + showLoading: false, + disabled: true, + onClick: handleClick + }, + }); + await wrapper.trigger('click'); + expect(handleClick).not.toBeCalled(); + }); + + it('slot', () => { + const btnText = 'vue3 devui'; + const wrapper = mount(Button, { + slots: { + default: btnText + } + }); + expect(wrapper.text()).toEqual(btnText); + }); +}); diff --git a/packages/devui-vue/devui/button/index.ts b/packages/devui-vue/devui/button/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0fa3b4a26d6970ea2a42720991c3cf72d9a6525e --- /dev/null +++ b/packages/devui-vue/devui/button/index.ts @@ -0,0 +1,19 @@ +import type { App } from 'vue' +import Button from './src/button' + +Button.install = function (app: App) { + app.component(Button.name, Button) +} + +export * from './src/button-types'; + +export { Button } + +export default { + title: 'Button 按钮', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(Button as any) + } +} diff --git a/packages/devui-vue/devui/button/src/button-types.ts b/packages/devui-vue/devui/button/src/button-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c09d2a67a7acba6e928302bbefdd4776d1dce3e --- /dev/null +++ b/packages/devui-vue/devui/button/src/button-types.ts @@ -0,0 +1,54 @@ +import { ExtractPropTypes, PropType } from 'vue'; + +export type IButtonType = 'button' | 'submit' | 'reset'; +export type IButtonStyle = 'common' | 'primary' | 'text' | 'text-dark' | 'danger'; +export type IButtonPosition = 'left' | 'right' | 'default'; +export type IButtonSize = 'lg' | 'md' | 'sm' | 'xs'; + +export const buttonProps = { + type: { + type: String as PropType, + default: 'button' + }, + btnStyle: { + type: String as PropType, + default: 'primary' + }, + size: { + type: String as PropType, + default: 'md' + }, + position: { + type: String as PropType, + default: 'default' + }, + bordered: { + type: Boolean, + default: false + }, + icon: { + type: String, + default: '' + }, + showLoading: { + type: Boolean, + default: false + }, + width: { + type: String, + }, + disabled: { + type: Boolean, + default: false + }, + autofocus: { + type: Boolean, + default: false + }, + onClick: { + type: Function as PropType<(event: MouseEvent) => void> + } +} as const; + + +export type ButtonProps = ExtractPropTypes; \ No newline at end of file diff --git a/devui/button/button.scss b/packages/devui-vue/devui/button/src/button.scss similarity index 97% rename from devui/button/button.scss rename to packages/devui-vue/devui/button/src/button.scss index fa3055b3c4f462b982c2b9f21b8b628d4bcb6477..1577e7abb8ba12e1b98083926dbc562cc86ab710 100644 --- a/devui/button/button.scss +++ b/packages/devui-vue/devui/button/src/button.scss @@ -1,8 +1,8 @@ -@import '../style/mixins/index'; -@import '../style/theme/color'; -@import '../style/theme/variables'; -@import '../style/theme/font'; -@import '../style/theme/corner'; +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/theme/font'; +@import '../../style/theme/corner'; $devui-btn-loading-color: $devui-text; $devui-btn-xs-padding: 1px 5px; @@ -310,7 +310,7 @@ $devui-btn-pseudo-config: ( } } -:host { +.devui-btn-host { display: inline-block; } @@ -387,4 +387,4 @@ $devui-btn-pseudo-config: ( .clear-right-5 { margin-right: 5px; -} \ No newline at end of file +} diff --git a/packages/devui-vue/devui/button/src/button.tsx b/packages/devui-vue/devui/button/src/button.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0130fd820a7151583ec583d97548412f3b6b0a62 --- /dev/null +++ b/packages/devui-vue/devui/button/src/button.tsx @@ -0,0 +1,75 @@ +import { computed, defineComponent, ref } from 'vue'; +import { Icon } from '../../icon'; +import { buttonProps } from './button-types'; + +import './button.scss'; + +export default defineComponent({ + name: 'DButton', + props: buttonProps, + setup(props, ctx) { + const buttonContent = ref(null); + + const onClick = (e: MouseEvent) => { + if (props.showLoading) { + return; + } + props.onClick?.(e); + } + + const hasContent = computed(() => ctx.slots.default); + + const btnClass = computed(() => { + const { btnStyle, size, position, bordered, icon } = props; + const origin = `devui-btn devui-btn-${btnStyle} devui-btn-${size} devui-btn-${position}`; + const borderedClass = bordered ? 'bordered' : ''; + const btnIcon = !!icon && !hasContent.value && btnStyle !== 'primary' ? 'd-btn-icon' : ''; + const btnIconWrap = !!icon ? 'd-btn-icon-wrap' : ''; + return `${origin} ${borderedClass} ${btnIcon} ${btnIconWrap}`; + }); + + const iconClass = computed(() => { + if (!props.icon) { + return; + } + const origin = 'devui-icon-fix icon'; + if (hasContent.value) { + return `${origin} clear-right-5`; + } else { + return origin; + } + }); + + return () => { + const { + icon, + type, + disabled, + showLoading, + width + } = props; + return ( +
        + +
        + ); + } + } +}); diff --git a/packages/devui-vue/devui/card/__tests__/card.spec.ts b/packages/devui-vue/devui/card/__tests__/card.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f5bc5531001f129e889dd77e3c13d17dacaddf12 --- /dev/null +++ b/packages/devui-vue/devui/card/__tests__/card.spec.ts @@ -0,0 +1,194 @@ +import { mount } from '@vue/test-utils'; +import DCard from '../src/card'; +import DAvatar from '../../avatar/src/avatar'; + +describe('card', () => { + it('should render correctly', async () => { + const wrapper = mount(DCard); + expect(wrapper.element).toMatchSnapshot() + }) + it('should render correctly avatar', async () => { + const wrapper = mount({ + components: { + DCard, + DAvatar + }, + template: ` + + + + `, + }); + const avatar = wrapper.findAllComponents({ name: 'dAvatar' })[0]; + expect(avatar.classes()).toContain('devui-avatar'); + }) + it('in v-slot mode should render correctly avatar', async () => { + const wrapper = mount({ + components: { + DCard, + DAvatar + }, + template: ` + + + + `, + }); + const avatar = wrapper.findAllComponents({ name: 'dAvatar' })[0]; + expect(avatar.classes()).toContain('devui-avatar'); + }) + it('should render correctly title', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-title').text()).toBe('DevUI') + }) + it('in v-slot mode should render title', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-title').text()).toBe('DEVUI Course') + }) + it('should render correctly subtitle', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-subtitle').text()).toBe('DevUI') + }) + it('in v-slot mode should render subtitle', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-subtitle').text()).toBe('DevUI') + }) + it('should render correctly content', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-content').text()).toBe('DevUI') + }) + it('in v-slot mode should render content', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-content').text()).toBe('DevUI') + }) + it('should render correctly actions', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-actions').exists()).toBeTruthy(); + expect(wrapper.find('.card-block').text()).toBe('btn') + }) + it('in v-slot mode should render actions', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + + `, + }); + expect(wrapper.find('.devui-card-actions').exists()).toBeTruthy(); + expect(wrapper.find('.card-block').text()).toBe('btn') + }) + it('should render correctly image', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + `, + }); + expect(wrapper.find('.devui-card-meta').attributes('src').includes('https://devui.design/components/assets/image1.png')).toBeTruthy(); + }) + it('should render correctly align', async () => { + const wrapper = mount({ + components: { + DCard, + }, + template: ` + + + `, + }); + expect(wrapper.find('.devui-card-actions-align-spaceBetween').exists()).toBeTruthy(); + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/card/index.ts b/packages/devui-vue/devui/card/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7e3961fa2a593e54dd029f70ef8f906ef30f581 --- /dev/null +++ b/packages/devui-vue/devui/card/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Card from './src/card' + +Card.install = function(app: App) { + app.component(Card.name, Card) +} + +export { Card } + +export default { + title: 'Card 卡片', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Card as any) + } +} diff --git a/packages/devui-vue/devui/card/src/card.scss b/packages/devui-vue/devui/card/src/card.scss new file mode 100644 index 0000000000000000000000000000000000000000..87c97e53926962525096afb3036c93bfad7dbf30 --- /dev/null +++ b/packages/devui-vue/devui/card/src/card.scss @@ -0,0 +1,77 @@ +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; + +$card-ele-space: var(--card-ele-space, 8px); +$card-block-space: var(--card-block-space, 16px); +$card-border-radius: $devui-border-radius-card; +$card-title-font-size: $devui-font-size-card-title; +$card-subtitle-font-size: $devui-font-size; +$card-content-font-size: $devui-font-size; + +.devui-card { + position: relative; + display: block; + padding: 16px 20px; + border-radius: $card-border-radius; + box-shadow: $devui-shadow-length-base $devui-light-shadow; +} + +.devui-card-title { + display: block; + font-size: $card-title-font-size; + font-weight: 600; + color: $devui-text; +} + +.devui-card-subtitle { + display: block; + font-size: $card-subtitle-font-size; + color: $devui-aide-text-stress; +} + +.devui-card-header { + display: flex; + flex-direction: row; + align-items: center; + margin-bottom: $card-block-space; +} + +.devui-card-avatar { + margin-right: $card-block-space; +} + +.devui-card-content { + font-size: $card-content-font-size; + color: $devui-aide-text; +} + +.devui-card-actions { + margin-top: $card-block-space; + display: flex; + justify-content: flex-start; + align-items: center; +} + +.devui-card-title + .devui-card-subtitle { + margin-top: $card-ele-space; +} + +.devui-card-actions-align-end { + justify-content: flex-end; +} + +.devui-card-actions-align-spaceBetween { + justify-content: space-between; +} + +.devui-card-meta { + width: calc(100% + 40px); + margin: 0 -20px $card-block-space -20px; + height: auto; +} + +.devui-card-meta:first-child { + margin-top: -$card-block-space; +} diff --git a/packages/devui-vue/devui/card/src/card.tsx b/packages/devui-vue/devui/card/src/card.tsx new file mode 100644 index 0000000000000000000000000000000000000000..249a3cc8823f6fed103c4f58bdb6c343dc69cdb2 --- /dev/null +++ b/packages/devui-vue/devui/card/src/card.tsx @@ -0,0 +1,55 @@ +import { defineComponent, PropType } from 'vue'; +import './card.scss'; + +const cardProps = { + align: { + type: String as PropType<'start' | 'end' | 'spaceBetween'>, + default: 'start' + }, + src: { + type: String, + default: '' + } +} as const; + +export default defineComponent({ + name: 'DCard', + props: cardProps, + + render () { + const { + align, + src + } = this; + const alignCls = { + 'd-card-actions':true, + 'devui-card-actions': true, + [`devui-card-actions-align-${align}`]: align !== 'start', + }; + return ( +
        + {this.$slots.default?.()} +
        + { this.$slots.cardAvatar?.()?
        + {this.$slots.cardAvatar?.()} +
        :'' } +
        +
        + {this.$slots.cardTitle?.()} +
        +
        + {this.$slots.cardSubtitle?.()} +
        +
        +
        + {src!==''?:''} +
        + {this.$slots.cardContent?.()} +
        +
        + {this.$slots.cardActions?this.$slots.cardActions?.():''} +
        +
        + ); + } +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/carousel/__tests__/carousel.spec.ts b/packages/devui-vue/devui/carousel/__tests__/carousel.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..525d71d7692531a36fe0c585f59b2a3117ccff7d --- /dev/null +++ b/packages/devui-vue/devui/carousel/__tests__/carousel.spec.ts @@ -0,0 +1,237 @@ +import { ref, nextTick } from 'vue' +import { mount } from '@vue/test-utils'; +import Carousel from '../carousel'; +import CarouselItem from '../item'; +import Button from '../../button' + +const wait = (ms = 100) => + new Promise(resolve => setTimeout(() => resolve(), ms)) + +describe('d-carousel', () => { + it('arrowTrigger-never', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'never', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(false); + }); + + it('arrowTrigger-hover-out', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'hover', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(false); + }); + it('arrowTrigger-hover-in', async () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'hover', + height: '200px', + }, + }); + wrapper.find('.devui-carousel-container').trigger('mouseenter') + await nextTick() + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(true); + }); + + it('arrowTrigger-always', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'always', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(true); + }); + + it('showDots-false', () => { + const wrapper = mount(Carousel, { + props: { + showDots: false, + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-dots').exists()).toBe(false); + }); + + it('showDots-click', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(0) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + + await nextTick() + wrapper.findAll('.dot-item')[1].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(1); + }); + + it('showDots-enter', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(0) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + await nextTick() + wrapper.findAll('.dot-item')[1].trigger('mouseenter') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(1); + }); + + it('operate', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + 'd-button': Button, + }, + template: ` + + {{ item }} + + + `, + setup() { + const items = ref(["page 1", 'page 2', 'page 3', 'page 4']) + const activeIndex = ref(0) + + const carousel = ref() + + const onPrev = () => { + carousel.value?.prev?.() + } + const onNext = () => { + carousel.value?.next?.() + } + const onGoFirst = () => { + carousel.value?.goto?.(0) + } + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + items, + + carousel, + onPrev, + onNext, + onGoFirst, + onChange, + } + } + }); + + await nextTick() + wrapper.find('.arrow-left').trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(3) + wrapper.find('.arrow-right').trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(0) + + wrapper.findAll('.devui-btn')[0].trigger('click') + await nextTick() + wrapper.findAll('.devui-btn')[0].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(2) + + wrapper.findAll('.devui-btn')[1].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(3) + + wrapper.findAll('.devui-btn')[2].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(0) + }); + + it('autoplay', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(2) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + + await wait(4500) + expect(wrapper.vm.activeIndex).toBe(1) + await wait(4600) + expect(wrapper.vm.activeIndex).toBe(3) + }, 10000); +}); diff --git a/packages/devui-vue/devui/carousel/index.ts b/packages/devui-vue/devui/carousel/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..792419a4fce0ef7f2ae8cf41f849845883c07035 --- /dev/null +++ b/packages/devui-vue/devui/carousel/index.ts @@ -0,0 +1,23 @@ +import type { App } from 'vue' +import Carousel from './src/carousel' +import CarouseItem from './src/item' + +Carousel.install = function(app: App) { + app.component(Carousel.name, Carousel) +} + +CarouseItem.install = function(app: App) { + app.component(CarouseItem.name, CarouseItem); +} + +export { Carousel } + +export default { + title: 'Carousel 走马灯', + category: '数据展示', + status: '80%', + install(app: App): void { + app.use(Carousel as any) + app.use(CarouseItem as any) + } +} diff --git a/packages/devui-vue/devui/carousel/src/carousel.scss b/packages/devui-vue/devui/carousel/src/carousel.scss new file mode 100644 index 0000000000000000000000000000000000000000..a60d1de502cef420144c8f1e1570c999a1cd3d47 --- /dev/null +++ b/packages/devui-vue/devui/carousel/src/carousel.scss @@ -0,0 +1,111 @@ +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/core/animation'; + +@mixin fixed-arrow-button() { + position: absolute; + top: -18px; + z-index: 2; + cursor: pointer; + width: 36px; + height: 36px; + border-radius: 18px; + background: $devui-highlight-overlay; + box-shadow: $devui-shadow-length-hover $devui-light-shadow; + display: inline-flex; + align-items: center; + justify-content: center; + + &:hover { + background: $devui-area; + } + + svg polygon { + fill: $devui-text; + } +} + +.devui-carousel-container { + display: block; + position: relative; + + .devui-carousel-arrow { + position: absolute; + width: 100%; + top: 50%; + + .arrow-left { + @include fixed-arrow-button(); + + left: 10px; + } + + .arrow-right { + @include fixed-arrow-button(); + + right: 10px; + } + } + + .devui-carousel-item-wrapper { + position: relative; + overflow: hidden; + height: 100%; + + .devui-carousel-item-container { + display: flex; + height: 100%; + position: relative; + + .d-carousel-item { + flex: 1; + position: relative; + height: 100%; + } + } + } + + .devui-carousel-dots { + position: absolute; + display: flex; + justify-content: center; + width: 100%; + list-style: none; + + &.bottom { + bottom: 8px; + } + + &.top { + top: 8px; + } + + .dot-item { + width: 6px; + height: 6px; + border-radius: 3px; + margin-right: 8px; + background: $devui-icon-fill; + + &:hover { + cursor: pointer; + background: $devui-list-item-hover-bg; + } + + &.active { + width: 24px; + background: $devui-list-item-active-bg; + transition: all $devui-animation-duration-slow $devui-animation-ease-in-smooth; + } + } + } +} + +.devui-carousel-container { + .devui-carousel-arrow { + .arrow-left, + .arrow-right { + transition: background-color $devui-animation-duration-slow $devui-animation-ease-in-smooth; + } + } +} diff --git a/packages/devui-vue/devui/carousel/src/carousel.tsx b/packages/devui-vue/devui/carousel/src/carousel.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bd9f54f29cc6a8727e90e602eab11e560913d574 --- /dev/null +++ b/packages/devui-vue/devui/carousel/src/carousel.tsx @@ -0,0 +1,273 @@ +/* eslint-disable */ +import { defineComponent, ref, watch, onMounted, onBeforeUnmount, Fragment, Comment } from 'vue'; +import { carouselProps, DotTrigger } from './types'; + +import Icon from '../../icon/src/icon' + +import './carousel.scss'; + +export default defineComponent({ + name: 'DCarousel', + props: carouselProps, + emits: ['update:activeIndex'], + setup(props, { emit }) { + const { + arrowTrigger, + autoplay, + autoplaySpeed, + dotTrigger, + activeIndex, + activeIndexChange + } = props; + const transitionSpeed = 500; + + const itemCount = ref(0); + const showArrow = ref(false); + const currentIndex = ref(0); + const wrapperRef = ref(null); + const containerRef = ref(null); + const scheduledId = ref | null>(null); + + watch( + () => arrowTrigger, + () => { + showArrow.value = arrowTrigger === 'always'; + }, + { immediate: true } + ); + watch( + () => activeIndex, + () => { + currentIndex.value = activeIndex; + }, + { immediate: true } + ); + + // 翻页位移 + const translatePosition = (size: number) => { + if (containerRef.value) containerRef.value.style.left = `${-size * 100}%`; + }; + // 调整首尾翻页后的动画 + const adjustTransition = (targetEl: HTMLElement) => { + setTimeout(() => { + if (containerRef.value) containerRef.value.style.transition = ''; + + targetEl.style.transform = ''; + translatePosition(currentIndex.value); + }, transitionSpeed); + }; + + // 调整首尾翻动时的位置 + const adjustPosition = (targetEl: HTMLElement, firstToLast: boolean) => { + if (wrapperRef.value) { + const wrapperRect = wrapperRef.value.getBoundingClientRect(); + + targetEl.style.transform = `translateX(${ + (firstToLast ? -itemCount.value : itemCount.value) * wrapperRect.width + }px)`; + } + }; + + // 指定跳转位置 + const goto = (index: number) => { + if ( + index === currentIndex.value || + !wrapperRef.value || + !containerRef.value + ) { + return; + } + + containerRef.value.style.transition = `left ${transitionSpeed}ms ease`; + + let latestIndex = currentIndex.value; + if (index < 0 && currentIndex.value === 0) { + // 第一个卡片向前切换 + latestIndex = itemCount.value - 1; + const targetEl = containerRef.value.children[ + latestIndex + ] as HTMLElement; + adjustPosition(targetEl, true); + translatePosition(-1); + adjustTransition(targetEl); + } else if ( + index >= itemCount.value && + currentIndex.value === itemCount.value - 1 + ) { + // 最后一个卡片向后切换 + latestIndex = 0; + + const targetEl = containerRef.value.children[ + latestIndex + ] as HTMLElement; + adjustPosition(targetEl, false); + translatePosition(itemCount.value); + adjustTransition(targetEl); + } else { + latestIndex = + index < 0 + ? 0 + : ( + index > itemCount.value - 1 + ? itemCount.value - 1 + : index + ) + + translatePosition(latestIndex); + } + + currentIndex.value = latestIndex; + emit('update:activeIndex', latestIndex); + activeIndexChange?.(latestIndex) + autoScheduleTransition(); + }; + // 向前切换 + const prev = () => { + goto(currentIndex.value - 1); + }; + // 向后切换 + const next = () => { + goto(currentIndex.value + 1); + }; + + // 切换箭头监听事件,用于处理hover方式 + const arrowMouseEvent = (type: 'enter' | 'leave') => { + if (arrowTrigger !== 'hover') return; + + showArrow.value = type === 'enter'; + }; + // 指示器触发切换函数 + const switchStep = (index: number, type: DotTrigger) => { + if (type === dotTrigger) goto(index); + }; + + // 清除自动轮播任务 + const clearScheduledTransition = () => { + if (scheduledId.value) { + clearTimeout(scheduledId.value); + scheduledId.value = null; + } + }; + // 自动轮播调度任务 + const autoScheduleTransition = () => { + clearScheduledTransition(); + if (autoplay && autoplaySpeed) { + scheduledId.value = setTimeout(() => { + next(); + }, autoplaySpeed); + } + }; + const changeItemCount = (val: number) => { + itemCount.value = val; + autoScheduleTransition(); + }; + + onMounted(() => { + if (containerRef.value) { + containerRef.value.style.transition = `left ${transitionSpeed}ms ease`; + containerRef.value.style.left = '0%'; + } + + autoScheduleTransition(); + }); + onBeforeUnmount(() => { + clearScheduledTransition() + }) + + return { + wrapperRef, + containerRef, + + showArrow, + currentIndex, + itemCount, + changeItemCount, + + goto, + prev, + next, + arrowMouseEvent, + switchStep, + }; + }, + + render() { + const { + showArrow, + currentIndex, + itemCount, + + arrowTrigger, + height, + showDots, + dotPosition, + + prev, + next, + arrowMouseEvent, + switchStep, + changeItemCount, + + $slots, + } = this; + const slot: any[] = $slots.default?.() ?? []; + + // 在jsx中,使用map生成slot项会在外层包裹一个Fragment + let children = slot; + if (children.length === 1 && children[0].type === Fragment) { + children = (children[0].children || []).filter( + (item) => item?.type !== Comment + ); + } + if (children.length !== itemCount) { + changeItemCount(children.length); + } + + return ( + + ); + }, +}); diff --git a/packages/devui-vue/devui/carousel/src/item.tsx b/packages/devui-vue/devui/carousel/src/item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c5c367ac12ae94cc633a8a6a6006002e512ce44d --- /dev/null +++ b/packages/devui-vue/devui/carousel/src/item.tsx @@ -0,0 +1,17 @@ +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'DCarouselItem', + render() { + const { + $slots + } = this + const children = $slots.default?.() + + return ( + + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/carousel/src/types.ts b/packages/devui-vue/devui/carousel/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc35b2d6acc85e02e68eda00f4654b671433047c --- /dev/null +++ b/packages/devui-vue/devui/carousel/src/types.ts @@ -0,0 +1,43 @@ +import { PropType } from 'vue'; + +export type ArrowTrigger = 'hover' | 'never' | 'always'; +export type DotTrigger = 'click' | 'hover'; +export type DotPosition = 'bottom' | 'top'; + +export const carouselProps = { + arrowTrigger: { + type: String as PropType, + default: 'hover' + }, + autoplay: { + type: Boolean, + default: false, + }, + autoplaySpeed: { + type: Number, + default: 3000 + }, + height: { + type: String, + default: '100%', + }, + showDots: { + type: Boolean, + default: true + }, + dotTrigger: { + type: String as PropType, + default: 'click', + }, + dotPosition: { + type: String as PropType, + default: 'bottom', + }, + activeIndex: { + type: Number, + default: 0 + }, + activeIndexChange: { + type: Function as unknown as () => ((index: number) => void) + }, +} as const; \ No newline at end of file diff --git a/packages/devui-vue/devui/cascader/components/cascader-item/index.scss b/packages/devui-vue/devui/cascader/components/cascader-item/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..459a91366bdb41b186b4a21c989d59286dfb9404 --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-item/index.scss @@ -0,0 +1,22 @@ +@import '../../../style/mixins/flex'; +@import '../../../style/theme/color'; +@import '../../../style/core/font'; + +.devui-cascader-li { + &.devui-dropdown-item { + height: 32px; + padding: 8px 12px; + color: $devui-text; + cursor: pointer; + @include flex(flex-start); + } + + .dropdown-item-label { + display: inline-block; + flex: 1; + width: 0; + overflow: hidden; + text-overflow: ellipsis; + font-size: $devui-font-size; + } +} diff --git a/packages/devui-vue/devui/cascader/components/cascader-item/index.tsx b/packages/devui-vue/devui/cascader/components/cascader-item/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5182dd221b1773743c2b7bf4a48cd6ff4f27aa9f --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-item/index.tsx @@ -0,0 +1,21 @@ +import { getRootClass } from './use-class' +import { optionsHandles } from '../../hooks/use-cascader-options' +import './index.scss' +export const DCascaderItem = (props) => { + const { cascaderli, ulIndex } = props + const { changeCascaderIndexs } = optionsHandles() + const rootClasses = getRootClass() + const mouseHover = () => { + changeCascaderIndexs(cascaderli, ulIndex) + } + return ( +
      • + + { + cascaderli?.children?.length > 0 && + } +
      • + ) +} diff --git a/packages/devui-vue/devui/cascader/components/cascader-item/use-class.ts b/packages/devui-vue/devui/cascader/components/cascader-item/use-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a5ec3e21b6bd16e8fafc7da41ea55a592f0760b --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-item/use-class.ts @@ -0,0 +1,11 @@ +/** + * 定义组件class + */ + import { computed, ComputedRef } from 'vue'; + + export const getRootClass = (): ComputedRef => { + return computed(() => ({ + 'devui-cascader-li devui-dropdown-item': true, + })) + } + \ No newline at end of file diff --git a/packages/devui-vue/devui/cascader/components/cascader-list/cascader-list-types.ts b/packages/devui-vue/devui/cascader/components/cascader-list/cascader-list-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..85e2152df95d7ff7843a6db28e084074b8c38f24 --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-list/cascader-list-types.ts @@ -0,0 +1,23 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { CascaderItem } from '../../src/cascader-types' +export const cascaderulProps = { + /** + * 每个ul中的li + * @type {CascaderItem[]} + * @default [] + */ + cascaderlis: { + type: Array as PropType, + default: [], + }, + /** + * 当前选中的ul下标 + * @type {Number} + * @default 0 + */ + ulIndex: { + type: Number, + default: 0 + } +} +export type CascaderulProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/cascader/components/cascader-list/index.scss b/packages/devui-vue/devui/cascader/components/cascader-list/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..a5ff2f80f31e199faf7c02531b3cbcaebf8d86d7 --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-list/index.scss @@ -0,0 +1,14 @@ +@import '../../../style/mixins/flex'; +@import '../../../style/theme/color'; + +.devui-cascader-ul { + width: 200px; + height: 180px; + background: $devui-connected-overlay-bg; + display: block; + list-style: none; + margin: 0; + padding: 0; + overflow-y: auto; + border-left: 1px solid $devui-dividing-line; +} diff --git a/packages/devui-vue/devui/cascader/components/cascader-list/index.tsx b/packages/devui-vue/devui/cascader/components/cascader-list/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4fa19244988f5997d37de3f902b5ab75bf8b2ecf --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-list/index.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue' +import { getRootClass } from './use-class' +import './index.scss' +import { cascaderulProps, CascaderulProps } from './cascader-list-types' +import { DCascaderItem } from '../cascader-item' +export default defineComponent({ + name: 'DCascaderList', + props: cascaderulProps, + setup(props: CascaderulProps) { + const rootClasses = getRootClass() + return () => ( +
          + {props.cascaderlis.map((item, index) => { + return + })} +
        + ) + } +}) diff --git a/packages/devui-vue/devui/cascader/components/cascader-list/use-class.ts b/packages/devui-vue/devui/cascader/components/cascader-list/use-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb0109c76ad6d5e3a8e51bf4052efb1a90a93512 --- /dev/null +++ b/packages/devui-vue/devui/cascader/components/cascader-list/use-class.ts @@ -0,0 +1,11 @@ +/** + * 定义组件class + */ + import { computed, ComputedRef } from 'vue'; + + export const getRootClass = (): ComputedRef => { + return computed(() => ({ + 'devui-cascader-ul': true, + })) + } + \ No newline at end of file diff --git a/packages/devui-vue/devui/cascader/hooks/use-cascader-class.ts b/packages/devui-vue/devui/cascader/hooks/use-cascader-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..706eca5edd019b251188470e8bf288d7e421d75f --- /dev/null +++ b/packages/devui-vue/devui/cascader/hooks/use-cascader-class.ts @@ -0,0 +1,16 @@ +/** + * 定义组件class + */ +import { computed, ComputedRef, Ref } from 'vue'; +import { CascaderProps } from '../src/cascader-types' +const TRIGGER_Map = { + hover: 'hover', + click: 'click', +} +export const getRootClass = (props: CascaderProps, menuShow: Ref ): ComputedRef => { + return computed(() => ({ + 'devui-cascader devui-dropdown devui-dropdown-animation': true, + 'devui-dropdown__open': menuShow.value, + 'devui-cascader__disbaled': props.disabled, + })) +} diff --git a/packages/devui-vue/devui/cascader/hooks/use-cascader-options.ts b/packages/devui-vue/devui/cascader/hooks/use-cascader-options.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7a298708b09cd7276035cd0bcd79b08a568608d --- /dev/null +++ b/packages/devui-vue/devui/cascader/hooks/use-cascader-options.ts @@ -0,0 +1,30 @@ +/** + * 处理传入options数据 + */ +import { reactive } from 'vue'; +import { CascaderItem, OptionsCallback } from '../src/cascader-types' +let cascaderOptions +export const optionsHandles = (options?: CascaderItem[]): OptionsCallback => { + if (options) { + cascaderOptions = reactive<[CascaderItem[]]>([ options ]) + } + /** + * hover时修改展示项 + * @param optionItem - 项 + * @param ulIndex - 当前选中的第几级 + * + */ + const changeCascaderIndexs = (optionItem: CascaderItem, ulIndex: number) => { + if (!cascaderOptions) return + if (optionItem?.children?.length > 0) { + cascaderOptions[ulIndex + 1] = optionItem.children + } else { + // 选择的项没有子项时清除多余的ul + cascaderOptions.splice(ulIndex + 1, cascaderOptions.length - 1 - ulIndex) + } + } + return { + cascaderOptions, + changeCascaderIndexs + } +} diff --git a/packages/devui-vue/devui/cascader/hooks/use-cascader-popup.ts b/packages/devui-vue/devui/cascader/hooks/use-cascader-popup.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e8f4bdff2ec8a5c7823c79af0fe426084888bc1 --- /dev/null +++ b/packages/devui-vue/devui/cascader/hooks/use-cascader-popup.ts @@ -0,0 +1,22 @@ +/** + * 控制窗口打开收起 + */ +import { ref, watch } from 'vue'; +import { PopupTypes } from '../src/cascader-types' + +export const popupHandles = (): PopupTypes => { + const menuShow = ref(false) + const menuOpenClass = ref('') + const openPopup = () => { + menuShow.value = !menuShow.value + } + watch(menuShow, (status) => { + menuOpenClass.value = status ? 'devui-drop-menu-wrapper' : '' + }) + + return { + menuShow, + menuOpenClass, + openPopup, + } +} diff --git a/packages/devui-vue/devui/cascader/index.ts b/packages/devui-vue/devui/cascader/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0bb14975fbe22227e75154f17a366370611cd4ec --- /dev/null +++ b/packages/devui-vue/devui/cascader/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Cascader from './src/cascader' + +Cascader.install = function(app: App): void { + app.component(Cascader.name, Cascader) +} + +export { Cascader } + +export default { + title: 'Cascader 级联菜单', + category: '数据录入', + status: '10%', + install(app: App): void { + app.use(Cascader as any) + } +} diff --git a/packages/devui-vue/devui/cascader/src/cascader-types.ts b/packages/devui-vue/devui/cascader/src/cascader-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..13abc1af5a1e869e2b9ec394dba7cbef6aa2263f --- /dev/null +++ b/packages/devui-vue/devui/cascader/src/cascader-types.ts @@ -0,0 +1,70 @@ +import type { PropType, ExtractPropTypes, Ref } from 'vue' +import { UnwrapNestedRefs } from '@vue/reactivity' + +type TriggerTypes = 'hover'|'click' + +export interface CascaderItem { + label: string + value: number | string + isLeaf?: boolean + children?: CascaderItem[] + disabled?: boolean + icon?: string + // 用户可以传入自定义属性,并在dropDownItemTemplate中使用 + [prop: string]: any +} + +export const cascaderProps = { + /** + * 可选,指定展开次级菜单方式 + * @description 可选择的值 'hover', 'click' + * @type {('hover'|'click')} + * @default 'hover' + */ + trigger: { + type: String as PropType, + default: 'hover' + }, + /** + * 必选,级联器的菜单信息 + * @type {CascaderItem[]} + * @default [] + */ + options: { + type: Array as PropType, + default: [], + required: true + }, + /** + * 可选,级联器是否禁用 + * @type {boolean} + * @default false + */ + disabled: { + type: Boolean, + default: false + }, + /** + * 可选,没有选择时的输入框展示信息 + * @type {string} + * @default ''' + */ + placeholder: { + type: String, + default: '' + } + +} as const + +export type CascaderProps = ExtractPropTypes + +export interface PopupTypes { + menuShow: Ref + menuOpenClass: Ref + openPopup: (e?: MouseEvent) => void +} + +export interface OptionsCallback { + cascaderOptions: never | UnwrapNestedRefs<[CascaderItem[]]> + changeCascaderIndexs: (optionItem: CascaderItem, ulIndex: number) => void +} \ No newline at end of file diff --git a/packages/devui-vue/devui/cascader/src/cascader.scss b/packages/devui-vue/devui/cascader/src/cascader.scss new file mode 100644 index 0000000000000000000000000000000000000000..cb49189eb72148a52d72dc3eaf1005a43c6a7817 --- /dev/null +++ b/packages/devui-vue/devui/cascader/src/cascader.scss @@ -0,0 +1,71 @@ +@import '../../style/mixins/size'; +@import '../../style/mixins/flex'; +@import '../../style/theme/color'; + +.devui-cascader { + @include flex(flex-start); + + position: relative; + + >div:nth-child(1) { + width: 100%; + } + + &__icon { + position: absolute; + right: 5px; + top: 0; + height: 100%; + @include flex; + @include flex-direction; + + .icon { + margin: 0; + } + } + + input { + width: 100%; + padding-right: 16px; + } + + .devui-drop-menu-wrapper { + display: block; + margin: 4px 0; + font-size: 0; + white-space: nowrap; + padding: 0; + } +} + +.devui-drop-icon-animation { + transition: transform 0.2s linear; +} + +.devui-drop-menu-animation { + transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out; + // opacity: 0; + // position: absolute; + // float: left; + z-index: 1000; + // transform: scaleY(0.7) translateY(-5px); + margin-top: 1px; + + .devui-dropdown-menu { + width: auto; + padding-bottom: 0; + @include flex('flex-start'); + } +} + +.devui-dropdown__open { + .devui-cascader__icon { + transform: rotate(180deg); + } + + .devui-drop-menu-animation { + transform-origin: 0 0%; + transform: scaleY(0.9999) translateY(0); + opacity: 1; + } +} diff --git a/packages/devui-vue/devui/cascader/src/cascader.tsx b/packages/devui-vue/devui/cascader/src/cascader.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d0565e61ce12839982a0d1a88ec046e2c3617b28 --- /dev/null +++ b/packages/devui-vue/devui/cascader/src/cascader.tsx @@ -0,0 +1,51 @@ +import './cascader.scss' + +import { defineComponent, ref, reactive } from 'vue' +import { cascaderProps, CascaderProps } from './cascader-types' +import { getRootClass } from '../hooks/use-cascader-class' +import { popupHandles } from '../hooks/use-cascader-popup' +import DCascaderList from '../components/cascader-list' +import { optionsHandles } from '../hooks/use-cascader-options' + + +export default defineComponent({ + name: 'DCascader', + props: cascaderProps, + setup(props: CascaderProps, ctx) { + const origin = ref(null) + const position = reactive({ + originX: 'left', + originY: 'bottom', + overlayX: 'left', + overlayY: 'top' + } as const) + // popup弹出层 + const { menuShow, menuOpenClass, openPopup } = popupHandles() + // 配置class + const rootClasses = getRootClass(props, menuShow) + // 级联菜单操作,变换ul、li等 + const { cascaderOptions } = optionsHandles(props.options) + return () => ( + <> +
        + +
        + +
        +
        + +
        +
        + {cascaderOptions.map((item, index) => { + return + })} +
        +
        +
        + + ) + }, +}) diff --git a/packages/devui-vue/devui/checkbox/__tests__/checkbox-group.spec.ts b/packages/devui-vue/devui/checkbox/__tests__/checkbox-group.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..1573bef0df195d5d4ee68825322ffcbd62967539 --- /dev/null +++ b/packages/devui-vue/devui/checkbox/__tests__/checkbox-group.spec.ts @@ -0,0 +1,201 @@ +import { mount } from '@vue/test-utils'; +import { reactive, ref, nextTick } from 'vue'; +import DCheckboxGroup from '../src/checkbox-group'; +import DCheckbox from '../src/checkbox'; + +describe('d-checkbox-group', () => { + it('checkbox-group render work', async () => { + const list = reactive(['b']); + const wrapper = mount({ + components: { + DCheckboxGroup, + DCheckbox + }, + template: ` + + + + + `, + setup () { + return { + list + }; + } + }); + const [box1, box2] = wrapper.findAll('.devui-checkbox'); + + expect(wrapper.classes()).toContain('devui-checkbox-group'); + expect(box1.classes()).toContain('unchecked'); + expect(box2.classes()).toContain('active'); + + Object.assign(list, ['a']); + await nextTick(); + expect(box1.classes()).toContain('active'); + expect(box2.classes()).toContain('unchecked'); + }); + + it('checkbox-group disabled work', async () => { + const list = ref(['b']); + const disabled = ref(true); + const onChange = jest.fn(); + const wrapper = mount({ + components: { + DCheckboxGroup, + DCheckbox + }, + template: ` + + 1 + 2 + + `, + setup () { + return { + list, + disabled, + onChange + }; + } + }); + const label1 = wrapper.find('label'); + + await label1.trigger('click'); + expect(list.value).toStrictEqual(['b']); + expect(onChange).toBeCalledTimes(0); + expect(wrapper.findAll('.devui-checkbox').every(el => el.classes().includes('disabled'))).toBe(true); + + disabled.value = false; + await nextTick(); + await label1.trigger('click'); + expect(list.value).toStrictEqual(['b', 'a']); + expect(onChange).toBeCalledTimes(1); + expect(wrapper.findAll('.devui-checkbox').some(el => el.classes().includes('disabled'))).toBe(false); + }); + + it('checkbox-group direction work', async () => { + const direction = ref('column'); + const list = ref(['b']); + const wrapper = mount({ + components: { + DCheckboxGroup, + DCheckbox + }, + template: ` + + 1 + 2 + + `, + setup () { + return { + list, + direction + }; + } + }); + + expect(wrapper.findAll('.devui-checkbox-column-margin').length).toBe(2); + expect(wrapper.find('.devui-checkbox-list-inline').exists()).toBe(false); + + direction.value = 'row'; + await nextTick(); + expect(wrapper.find('.devui-checkbox-list-inline').exists()).toBe(true); + }); + + it('checkbox-group itemWidth work', () => { + const itemWidth = ref(100); + const list = ref(['b']); + const wrapper = mount({ + components: { + DCheckboxGroup, + DCheckbox + }, + template: ` + + 1 + 2 + + `, + setup () { + return { + list, + itemWidth + }; + } + }); + + expect(wrapper.findAll('.devui-checkbox-wrap').length).toBe(2); + }); + + it('checkbox-group options work', () => { + const list = ref(['b']); + const wrapper = mount({ + components: { + DCheckboxGroup + }, + template: ` + + + `, + setup () { + const options = [ + { + value: 'a' + }, { + value: 'b' + } + ]; + return { + list, + options + }; + } + }); + + const boxList = wrapper.findAll('.devui-checkbox'); + + expect(boxList.length).toBe(2); + expect(boxList[0].classes()).toContain('unchecked'); + expect(boxList[1].classes()).toContain('active'); + }); + + it('checkbox-group beforeChange work', async () => { + const list = ref(['b']); + const beforeChange = jest.fn(() => false); + const onChange = jest.fn(); + const wrapper = mount({ + components: { + DCheckboxGroup, + DCheckbox + }, + template: ` + + 1 + 2 + + `, + setup () { + return { + list, + beforeChange, + onChange + }; + } + }); + + const box1 = wrapper.find('label'); + await box1.trigger('click'); + + expect(beforeChange).toHaveBeenCalledTimes(1); + expect(onChange).toBeCalledTimes(0); + expect(list.value).toStrictEqual(['b']); + + beforeChange.mockReturnValue(true); + await box1.trigger('click'); + + expect(beforeChange).toHaveBeenCalledTimes(2); + expect(onChange).toBeCalledTimes(1); + expect(list.value).toStrictEqual(['b', 'a']); + }); +}); diff --git a/packages/devui-vue/devui/checkbox/__tests__/checkbox.spec.ts b/packages/devui-vue/devui/checkbox/__tests__/checkbox.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..999edf453aa33b6d5d8ebe9da68d172f9bd27a4e --- /dev/null +++ b/packages/devui-vue/devui/checkbox/__tests__/checkbox.spec.ts @@ -0,0 +1,146 @@ +import { mount } from '@vue/test-utils'; +import { ref, nextTick } from 'vue'; +import DCheckbox from '../src/checkbox'; + +describe('checkbox', () => { + it('checkbox render work', async () => { + const checked = ref(true); + const wrapper = mount({ + components: { DCheckbox }, + template: `1024`, + setup () { + return { + checked + }; + } + }); + const container = wrapper.find('.devui-checkbox'); + + expect(wrapper.text()).toEqual('1024'); + expect(container.exists()).toBeTruthy(); + expect(container.classes()).toContain('active'); + + checked.value = false; + await nextTick(); + + expect(container.classes()).not.toContain('active'); + expect(container.classes()).toContain('unchecked'); + }); + + it('checkbox title work', async () => { + const wrapper = mount(DCheckbox, { + props: { + value: 'a', + label: '1314' + } + }); + + expect(wrapper.text()).toEqual('1314'); + const label = wrapper.find('label'); + expect(label.attributes('title')).toEqual('1314'); + + await wrapper.setProps({ + title: '520', + label: '1314' + }); + expect(label.attributes('title')).toEqual('520'); + + await wrapper.setProps({ + isShowTitle: false + }); + expect(label.attributes('title')).toEqual(''); + }); + + it('checkbox showAnimation work', async () => { + const wrapper = mount(DCheckbox, { + props: { + value: 'a' + } + }); + + expect(wrapper.findAll('.devui-no-animation').length).toBe(0); + + await wrapper.setProps({ + showAnimation: false + }); + expect(wrapper.findAll('.devui-no-animation').length).toBe(2); + }); + + it('checkbox disabled work', async () => { + const onChange = jest.fn(); + const wrapper = mount(DCheckbox, { + props: { + value: 'a', + disabled: true, + onChange + } + }); + const label = wrapper.find('label'); + + await label.trigger('click'); + expect(wrapper.find('.devui-checkbox').classes()).toContain('disabled'); + expect(onChange).toBeCalledTimes(0); + + await wrapper.setProps({ + disabled: false + }); + await label.trigger('click'); + expect(wrapper.find('.devui-checkbox').classes()).not.toContain('disabled'); + expect(onChange).toBeCalledTimes(1); + }); + + it('checkbox halfchecked work', async () => { + const wrapper = mount(DCheckbox, { + props: { + value: '555', + halfchecked: false + } + }); + + const container = wrapper.find('.devui-checkbox'); + expect(container.classes()).not.toContain('halfchecked'); + expect(container.find('.devui-checkbox-default-background').exists()).toBe(true); + + await wrapper.setProps({ + halfchecked: true + }); + expect(container.classes()).toContain('halfchecked'); + expect(container.find('.devui-checkbox-default-background').exists()).toBe(false) + }); + + it('checkbox beforeChange work', async () => { + const beforeChange = jest.fn(() => false); + const onChange = jest.fn(); + const checked = ref(false); + const wrapper = mount({ + components: { DCheckbox }, + template: ` + + 666 + `, + setup () { + return { + beforeChange, + onChange, + checked + }; + } + }); + + const label = wrapper.find('label'); + await label.trigger('click'); + expect(beforeChange).toBeCalledTimes(1); + expect(onChange).toBeCalledTimes(0); + expect(checked.value).toBe(false); + + beforeChange.mockReturnValue(true); + await label.trigger('click'); + expect(beforeChange).toBeCalledTimes(2); + expect(onChange).toBeCalledTimes(1); + expect(checked.value).toBe(true); + }); +}); diff --git a/packages/devui-vue/devui/checkbox/index.ts b/packages/devui-vue/devui/checkbox/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc25995f5b7c82105f4e2c97c3b06d46bbc3522c --- /dev/null +++ b/packages/devui-vue/devui/checkbox/index.ts @@ -0,0 +1,23 @@ +import type { App } from 'vue' +import Checkbox from './src/checkbox' +import CheckboxGroup from './src/checkbox-group' + +Checkbox.install = function (app: App) { + app.component(Checkbox.name, Checkbox) +} + +CheckboxGroup.install = function (app: App) { + app.component(CheckboxGroup.name, CheckboxGroup) +} + +export { Checkbox } + +export default { + title: 'Checkbox 复选框', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(Checkbox as any); + app.use(CheckboxGroup as any); + } +} diff --git a/packages/devui-vue/devui/checkbox/src/checkbox-group.scss b/packages/devui-vue/devui/checkbox/src/checkbox-group.scss new file mode 100644 index 0000000000000000000000000000000000000000..796b99ddbdf177021ed91c2799801e1696c74d07 --- /dev/null +++ b/packages/devui-vue/devui/checkbox/src/checkbox-group.scss @@ -0,0 +1,21 @@ +:host { + display: block; +} + +.devui-checkbox-list-inline { + min-height: 28px; + line-height: 28px; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + margin: -8px 0 0 0; + + & div:not(:last-child) { + margin-right: 20px; + } + + & > * { + margin-top: 8px; + } +} diff --git a/packages/devui-vue/devui/checkbox/src/checkbox-group.tsx b/packages/devui-vue/devui/checkbox/src/checkbox-group.tsx new file mode 100644 index 0000000000000000000000000000000000000000..58551aeaf5e0e35301b7e2ba03ea9952c97137da --- /dev/null +++ b/packages/devui-vue/devui/checkbox/src/checkbox-group.tsx @@ -0,0 +1,100 @@ +import { defineComponent, ExtractPropTypes, provide, toRef } from 'vue' +import { checkboxGroupProps, checkboxGroupInjectionKey } from './use-checkbox' +import DCheckbox from './checkbox' +import './checkbox-group.scss' + +export default defineComponent({ + name: 'DCheckboxGroup', + props: checkboxGroupProps, + emits: ['change', 'update:modelValue'], + setup(props: ExtractPropTypes, ctx) { + const valList = toRef(props, 'modelValue') + + const defaultOpt = { + checked: false, + isShowTitle: true, + halfchecked: false, + showAnimation: true, + disabled: false, + } + const toggleGroupVal = (val: string) => { + let index = -1 + if (typeof valList.value[0] === 'string') { + index = valList.value.findIndex((item) => item === val) + } else if (typeof valList.value[0] === 'object') { + index = valList.value.findIndex((item) => item.value === val) + } + + if (index === -1) { + if (typeof props.options[0] === 'object') { + const newOne = props.options.find((item) => item.value === val) + const res = [...valList.value, newOne] + ctx.emit('update:modelValue', res) + ctx.emit('change', res) + return + } + const res = [...valList.value, val] + ctx.emit('update:modelValue', res) + ctx.emit('change', res) + return + } + valList.value.splice(index, 1) + ctx.emit('update:modelValue', valList.value) + ctx.emit('change', valList.value) + } + const isItemChecked = (itemVal: string) => { + if (typeof valList.value[0] === 'string') { + return valList.value.includes(itemVal) + } else if (typeof valList.value[0] === 'object') { + return valList.value.some((item) => item.value === itemVal) + } + } + + provide(checkboxGroupInjectionKey, { + disabled: toRef(props, 'disabled'), + isShowTitle: toRef(props, 'isShowTitle'), + color: toRef(props, 'color'), + showAnimation: toRef(props, 'showAnimation'), + beforeChange: props.beforeChange, + isItemChecked, + toggleGroupVal, + itemWidth: toRef(props, 'itemWidth'), + direction: toRef(props, 'direction'), + }) + + return { + defaultOpt, + } + }, + render() { + const { direction, $slots, defaultOpt, options } = this + let children = $slots.default?.() + + if (options?.length > 0) { + children = options.map((opt) => { + let mergedOpt = null + if (typeof opt === 'string') { + mergedOpt = Object.assign({}, defaultOpt, { + label: opt, + value: opt, + }) + } else if (typeof opt === 'object') { + mergedOpt = Object.assign({}, defaultOpt, { + ...opt, + label: opt.name, + }) + } + + return + }) + } + + return ( +
        +
        + {children} +
        +
        + ) + }, +}) diff --git a/packages/devui-vue/devui/checkbox/src/checkbox.scss b/packages/devui-vue/devui/checkbox/src/checkbox.scss new file mode 100644 index 0000000000000000000000000000000000000000..f976cd216a1f1a98f2cd111d910bbf112f6b65b5 --- /dev/null +++ b/packages/devui-vue/devui/checkbox/src/checkbox.scss @@ -0,0 +1,228 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/corner'; + +.devui-checkbox { + position: relative; + display: flex; + display: -ms-flexbox; + align-items: center; + -ms-flex-align: center; + height: 100%; + margin: 0; + + .devui-checkbox-tick { + position: absolute; + + .devui-tick { + fill: $devui-light-text; + stroke-dashoffset: 50; + opacity: 0; + transform: scale(0); + transform-origin: 50% 50%; + transition: stroke-dashoffset 0.2s ease-in-out, opacity 0.2s ease-in-out, transform 0.2s ease-in-out; + } + } + + &.active:not(.halfchecked) .devui-tick { + opacity: 1; + stroke-dashoffset: 0; + transform: scale(1); + transition: stroke-dashoffset 0.3s cubic-bezier(0.755, 0.05, 0.855, 0.06), opacity 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06); + } + + &.active, + &.halfchecked { + &:not(.disabled) .devui-checkbox-material:not(.custom-color) { + border-color: $devui-brand; + } + } + + &.active:not(.disabled) { + .devui-checkbox-material { + background-size: 100% 100%; + transition: background-size 0.2s ease-in-out, border-color 0.2s ease-in-out; + } + } + + &.unchecked:not(.disabled) { + .devui-checkbox-material:not(.custom-color) { + background-size: 0% 0%; + transition: background-size 0.2s ease-in-out, border-color 0.2s ease-in-out; + + &:hover { + border-color: $devui-icon-fill-active; + } + } + } + + &.unchecked:not(.disabled) { + .devui-checkbox-material.custom-color { + background-size: 0% 0%; + transition: background-size 0.2s ease-in-out, border-color 0.2s ease-in-out; + } + } + + &.halfchecked { + .devui-checkbox-material:not(.custom-color) { + background-color: $devui-brand; + + & > .devui-checkbox-halfchecked-bg { + opacity: 1; + transform: scale(0.4288); + transition: transform 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06); + background-color: $devui-light-text; + } + } + } + + &.halfchecked { + .devui-checkbox-material.custom-color { + & > .devui-checkbox-halfchecked-bg { + opacity: 1; + transform: scale(0.4288); + transition: transform 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06); + background-color: $devui-light-text; + } + } + } + + .devui-checkbox-material { + text-align: initial; + height: 14px; + width: 14px; + position: relative; + user-select: none; + border: 1px solid $devui-line; + border-radius: $devui-border-radius; + background: linear-gradient($devui-brand, $devui-brand) no-repeat center/0%; + margin-right: 8px; + vertical-align: text-bottom; + + &.devui-checkbox-default-background { + background-color: $devui-base-bg; + } + + &.devui-checkbox-no-label { + margin-right: 0; + } + + & > .devui-checkbox-halfchecked-bg { + display: inline-block; + position: absolute; + content: ''; + background-color: $devui-light-text; + top: 0; + left: 0; + height: 100%; + width: 100%; + transform: scale(1); + opacity: 0; + } + + & > svg { + width: 14px; + height: 14px; + } + } + + &:not(.disabled).halfchecked { + .devui-checkbox-material:not(.custom-color) { + &:focus, + &:active, + &:hover { + background-color: $devui-icon-fill-active; + } + + // 激活状态深色 + &:active, + &:focus, + &:hover:active, + &:hover:focus { + background-color: $devui-brand-active-focus; + } + } + } + + &-input { + opacity: 0; + position: absolute; + margin: 0; + z-index: -1; + width: 0; + height: 0; + overflow: hidden; + left: 0; + pointer-events: none; + } + + & label { + position: relative; + font-weight: normal; + height: 16px; + line-height: 16px; + cursor: pointer; + color: $devui-text; + margin: 0; + display: block; + + & > span { + display: inline-block; + box-sizing: content-box; + vertical-align: top; + } + } + + // 禁用状态透明色 + &.disabled { + label { + cursor: not-allowed; + color: $devui-disabled-text; + } + + .devui-checkbox-material { + border-color: $devui-icon-fill-active-disabled; + background-color: $devui-icon-fill-active-disabled; + } + + &.unchecked { + .devui-checkbox-material { + border-color: $devui-disabled-line; + background-color: $devui-disabled-bg; + } + } + + &.halfchecked { + .devui-checkbox-material { + background-color: $devui-disabled-bg; + + .devui-checkbox-halfchecked-bg { + transform: scale(0.4288); + background-color: $devui-disabled-text; + opacity: 1; + } + } + } + + &.active { + svg polygon { + fill: $devui-light-text; + } + } + } +} + +.devui-no-animation { + transition: none !important; +} + +.devui-checkbox-column-margin { + height: 28px; + line-height: 28px; +} + +.devui-checkbox-wrap .devui-checkbox label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/packages/devui-vue/devui/checkbox/src/checkbox.tsx b/packages/devui-vue/devui/checkbox/src/checkbox.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d4bf54e8bdf7d00ecf5ba39fcf56d0dd36bcb5c0 --- /dev/null +++ b/packages/devui-vue/devui/checkbox/src/checkbox.tsx @@ -0,0 +1,173 @@ +import { defineComponent, inject, computed } from 'vue' +import './checkbox.scss' +import { + checkboxGroupInjectionKey, + checkboxProps, + CheckboxProps, +} from './use-checkbox' + +export default defineComponent({ + name: 'DCheckbox', + props: checkboxProps, + emits: ['change', 'update:checked', 'update:modelValue'], + setup(props: CheckboxProps, ctx) { + const checkboxGroupConf = inject(checkboxGroupInjectionKey, null) + + const isChecked = computed(() => props.checked || props.modelValue) + const mergedDisabled = computed(() => { + return checkboxGroupConf?.disabled.value || props.disabled + }) + const mergedChecked = computed(() => { + return checkboxGroupConf?.isItemChecked?.(props.value) ?? isChecked.value + }) + const mergedIsShowTitle = computed(() => { + return checkboxGroupConf?.isShowTitle.value ?? props.isShowTitle + }) + const mergedShowAnimation = computed(() => { + return checkboxGroupConf?.showAnimation.value ?? props.showAnimation + }) + const mergedColor = computed(() => { + return checkboxGroupConf?.color.value ?? props.color + }) + const itemWidth = checkboxGroupConf?.itemWidth.value + const direction = checkboxGroupConf?.direction.value + + const canChange = (isChecked: boolean, val: string) => { + if (mergedDisabled.value) { + return Promise.resolve(false) + } + + const beforeChange = props.beforeChange ?? checkboxGroupConf?.beforeChange + if (beforeChange) { + const res = beforeChange(isChecked, val) + if (typeof res === 'boolean') { + return Promise.resolve(res) + } + return res + } + return Promise.resolve(true) + } + const toggle = () => { + const current = !isChecked.value + checkboxGroupConf?.toggleGroupVal(props.value) + ctx.emit('update:checked', current) + ctx.emit('update:modelValue', current) + ctx.emit('change', current) + } + const handleClick = () => { + canChange(!isChecked.value, props.label).then((res) => res && toggle()) + } + + return { + itemWidth, + direction, + mergedColor, + mergedDisabled, + mergedIsShowTitle, + mergedChecked, + mergedShowAnimation, + handleClick, + } + }, + render() { + const { + itemWidth, + direction, + mergedChecked, + mergedDisabled, + mergedIsShowTitle, + mergedShowAnimation, + halfchecked, + title, + label, + handleClick, + name, + value, + mergedColor, + $slots, + } = this + + const wrapperCls = { + 'devui-checkbox-column-margin': direction === 'column', + 'devui-checkbox-wrap': typeof itemWidth !== 'undefined', + } + const wrapperStyle = itemWidth ? [`width: ${itemWidth}px`] : [] + const checkboxCls = { + 'devui-checkbox': true, + active: mergedChecked, + halfchecked, + disabled: mergedDisabled, + unchecked: !mergedChecked, + } + const labelTitle = mergedIsShowTitle ? title || label : '' + const bgImgStyle = + (mergedColor && halfchecked) || mergedColor + ? `linear-gradient(${mergedColor}, ${mergedColor})` + : '' + const spanStyle = [ + `border-color:${ + (mergedChecked || halfchecked) && mergedColor ? mergedColor : '' + }`, + `background-image:${bgImgStyle}`, + `background-color:${mergedColor && halfchecked ? mergedColor : ''}`, + ] + const spanCls = { + 'devui-checkbox-material': true, + 'custom-color': mergedColor, + 'devui-checkbox-no-label': !label && !$slots.default, + 'devui-no-animation': !mergedShowAnimation, + 'devui-checkbox-default-background': !halfchecked, + } + const polygonCls = { + 'devui-tick': true, + 'devui-no-animation': !mergedShowAnimation, + } + const stopPropagation = ($event: Event) => $event.stopPropagation() + + const inputProps = { + indeterminate: halfchecked, + } + + return ( +
        +
        + +
        +
        + ) + }, +}) diff --git a/packages/devui-vue/devui/checkbox/src/use-checkbox.ts b/packages/devui-vue/devui/checkbox/src/use-checkbox.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a77a78fcad4560a2128829f3591b4fc8437ab18 --- /dev/null +++ b/packages/devui-vue/devui/checkbox/src/use-checkbox.ts @@ -0,0 +1,123 @@ +import { PropType, InjectionKey, Ref, ExtractPropTypes } from 'vue' + +type Direction = 'row' | 'column' + +const commonProps = { + name: { + type: String, + default: undefined, + }, + halfchecked: { + type: Boolean, + default: false, + }, + isShowTitle: { + type: Boolean, + default: true, + }, + title: { + type: String, + }, + color: { + type: String, + default: undefined, + }, + showAnimation: { + type: Boolean, + default: true, + }, + disabled: { + type: Boolean, + default: false, + }, + beforeChange: { + type: Function as PropType< + (isChecked: boolean, v: string) => boolean | Promise + >, + default: undefined, + }, +} as const + +export const checkboxProps = { + ...commonProps, + halfchecked: { + type: Boolean, + default: false, + }, + checked: { + type: Boolean, + default: false, + }, + value: { + type: String, + }, + label: { + type: String, + default: undefined, + }, + title: { + type: String, + default: undefined, + }, + 'onUpdate:checked': { + type: Function as PropType<(v: boolean) => void>, + default: undefined, + }, + onChange: { + type: Function as PropType<(v: boolean) => void>, + default: undefined, + }, + modelValue: { + type: Boolean, + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: boolean) => void>, + }, +} as const + +export type CheckboxProps = ExtractPropTypes + +export const checkboxGroupProps = { + ...commonProps, + modelValue: { + type: Array as PropType, + required: true, + }, + direction: { + type: String as PropType, + default: 'column', + }, + itemWidth: { + type: Number, + default: undefined, + }, + options: { + type: Array as PropType<({ value: string; } & Partial)[]>, + default: () => [], + }, + onChange: { + type: Function as PropType<(v: string[]) => void>, + default: undefined, + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: string[]) => void>, + default: undefined, + }, +} as const + +interface checkboxGroupInjection { + disabled: Ref + isShowTitle: Ref + color: Ref + showAnimation: Ref + beforeChange: + | undefined + | ((isChecked: boolean, v: string) => boolean | Promise) + toggleGroupVal: (v: string) => void + isItemChecked: (v: string) => boolean + itemWidth: Ref + direction: Ref +} + +export const checkboxGroupInjectionKey: InjectionKey = + Symbol('d-checkbox-group') diff --git a/packages/devui-vue/devui/date-picker/README.md b/packages/devui-vue/devui/date-picker/README.md new file mode 100644 index 0000000000000000000000000000000000000000..06d4c75be04c9e1b5dd3165fe75c727b45cc7bef --- /dev/null +++ b/packages/devui-vue/devui/date-picker/README.md @@ -0,0 +1,293 @@ +# DatePicker设计思路与实现 + +# 1. 需求梳理 + +## 1.1 主要结构 + +直观上分析,组件主要包括两部分: + +- 日期面板 + - 日期显示面板 + - 跳转到`今天`按钮 +- 顶部操作栏 + +## 1.2 交互分析 + +交互上分析,大致包括: + +- 日期面板操作 + - 单日选择 + - 区域选择 + - 开始日期(select start) + - 区间日期(start + hover) + - 结束日期(select end) + - 跳转到`今天` +- 顶栏操作 + - 显示当前日期 + - 年/月翻页功能 + +## 1.3 事件响应 + +消息传递(事件接口)上分析,应该具备以下几种能力: + +- 日期面板 + - `onSelected` 单板日期值被选中 + - `onSelectStart` 区域日期开始选择 + - `onSelecting` 区域中间值发生变化 + - `onSelectEnd` 区域日期值选择结束 + - `onToday` 跳转当天 + - `onChange` 日期值输出变化 + - `onReset` 需要重置状态 +- 顶部操作 + - `onNextYear` 跳到下一年 + - `onNextMonth` 跳到下一月 + - `onPreviousYear` 跳上一年 + - `onPreviousMonth` 跳上一月 + +## 1.4 状态管理 + +- 日期面板 + - 当月/非当月日期的显示和响应 + - 限制区域外日期的显示和响应 +- 顶部操作 + - 区域双板翻页的互作用 + - 区域限制的显示和响应 + +## 1.5 样式实现 + +- 使用`flex`布局 + + +# 2. 实现思路 + +整体上,`容器组件 + 子组件`的设计思路,将视觉、交互按组件拆分,化整为零,简化问题。 + +## 2.1 子组件拆解 + +根据`1.1`的结构,将`DatePicker`拆解为4个子组件: + +- `calendar` + - `panel` + - `today` +- `toolbar` + +其中`panel`和`today`都是孙级子组件。考虑到代码的可维护性,所有组件在文件存储路径上平级。 + +## 2.2 子组件开发 + +每个子孙组件都是纯展示组件,无内部状态;`DatePicker`作为容器组件,统一管理状态和属性派发。 + +每个子组件,按`1.3`创建事件接口;容器组件订阅这些接口消息,实现子组件与容器组件间通信。 + +### 2.2.1 单项数据流的函数式组件 + +函数式组件,是最佳的单向数据流模式,没有之一。来看一下`today`组件代码: + +```tsx +type TProps = { + onSelected?: (date: Date) => void + disabled?: boolean +} + +export default (props: TProps) => { + const { onSelected = () => 0, disabled = false } = props + return ( +
        + +
        + ) +} +``` + +该组件当中,没有任何的内置状态管理,所有属性都来自`props`,也就是父组件的传递值。 + +- `disabled`属性,考虑到在配置日期区域限制后,`today`有可能不在区域内,此时`today`按钮应当不可用,通过该属性控制; +- `onSelected`事件,用于容器组件订阅`button`的点击事件,来实现约定的`onToday`事件接口。 + +### 2.2.2 在VUE3中使用TSX函数式组件 + +由于`VSCode`对`t.ds`的良好支持——即便是受益于`React`,以及由此带来的开发侧良好体验,`DatePicker`的子孙组件(单向数据流组件)的开发全部使用`纯函数+TSX`。 + +实现详情和`webpack`支持,详见我的另外两篇文章: + +[《DevUI中VUE的TSX函数式组件实践》](https://juejin.cn/post/6999260884631552037) + +[《再聊Vue的TSX函数式组件》](https://juejin.cn/post/7000688749017317407) + +## 2.3 组件样式 + +- 所有布局使用`flex` +- `scss` + 全局样式复用。 + + +# 3 日历面板组件 `panel` + +## 3.1 具体需求: + +- 3.1.1 统一使用7x6的面板,共42天。(虽然有些月份35天面板即可完整显示,但会导致高度不一致) +- 3.1.2 面板补齐 + - 3.1.2.1 一周以周日作为起点(国际默认) + - 3.1.2.2 当月1日非周日的话,向前补齐上月尾巴到周日。 + - 3.1.2.3 使用下月日期向后补齐42天。 +- 3.1.3 非当月日期 + - 3.1.3.1 上月、下月用于补齐面板的日期格虚化显示 + - 3.1.3.2 单板选择后,面板跳转到对应月 + - 3.1.3.3 双板选择后 + - 3.1.3.3.1 双面板按日期大小排序,左板为较早时间 + - 3.1.3.3.2 双板分别跳转到对应月 + - 3.1.3.3.3 当选择区域没有跨月,显示于用户操作面板,另一面板保持。 +- 3.1.4 非限制区域内日期 + - 3.1.4.1 虚化显示 + - 3.1.4.2 鼠标悬停时cursor更改为禁用 +- 3.1.5 交互 + - 3.1.5.1 单板日期选择,触发`onSelected`,通知更新`dateStart`,然后触发`onChange` + - 3.1.5.2 单板`today`点击,触发`onToday`,通知更新`dateStart` + - 3.1.5.3 双板第一次点击,触发`onSelectStart`,通知更新区间日期开始时间`dateStart` + - 3.1.5.4 双板第一次点击后,面板内触发`onSelecting`,通知更新鼠标位置所在日期`dateHover` + - 3.1.5.5 双板第二次点击,触发`onSelectEnd`,通知更新区间日期结束时间`dateEnd`,然后触发`onChange` + - 3.1.5.6 如果`dateStart`和`dateEnd`都已在`props`中定义,则触发`onReset`,通知父组件重置状态。 + - 3.1.5.7 限制区域外日期格禁止交互(不绑定交互事件方法) + + +## 3.2 工具准备 + +由于需要大量的日期类型操作和比较,为了方便开发,所以需要先准备一些工具。 + +### 3.2.1 获取月份42天面板(3.1.2) + +```ts +const getMonthDays = (year: number, month: number) => { + // 当月第一天 + const first = new Date(year, month - 1, 1) + // 当月最后一天 + const last = new Date(year, month, 0) + // 输出结构 + const dates: TDateCell[] = [] + + // 第一天的星期几,0~6,0为周日 + let day = first.getDay() + // 向左补齐星期日期 + while (day > 0) { + day -= 1 + dates.push({ date: new Date(year, month - 1, -day), current: -1 }) + } + // 填充当月日期 + day = last.getDate() - first.getDate() + for (let i = 0; i <= day; i++) { + const date = new Date(first) + date.setDate(i + 1) + dates.push({ date, current: 0 }) + } + + // 向右补齐星期 + day = last.getDay() + let tail: Date = last + for (let i = day; i < 6; i++) { + tail = new Date(year, month, i - day + 1) + dates.push({ date: tail, current: 1 }) + } + // 按42天补齐日期 + // 这里不统一补齐方式,为35天动态面板预留。 + if(dates.length < 42) { + day = tail.getDate() + for (let i = 1; i <= 7; i++) { + tail = new Date(year, month, day + i) + dates.push({ date: tail, current: 1 }) + } + } + return dates +} +``` + +这里的一个技巧,是获取月末日期。 + +因为月份涉及`大小月`、`闰年`等变量因素,月末可能是`28/29/30/31`共4种情况,如果直接计算(尤其是闰年的计算)会比较麻烦。这里使用`取下个月第一天的前一天`的方式,来获取当月月末日期: + +```ts +const last = new Date(2000, 2, 0) // 获取2000年2月最后一天 +// -> Tue Feb 29 2000 00:00:00 GMT+0800 (中国标准时间) +``` + +这里`Date`的第3个参数为0,相当于: + +```ts +let last = new Date(2000, 2, 1) // 获取2000年3月1日 +last = last.setDate(-1) // last设置为3月1日前一天,即2月最后一天,具体日期Date会自己算。 +``` + +同样的方法我们也可以获取到年度的最后一天: + +```ts +const last = new Date(2000, 12, 0) // 获取2000年12月最后一天,也就是年度最后一天。 +// -> Sun Dec 31 2000 00:00:00 GMT+0800 (中国标准时间) +``` + +计算一年天数的时候,有可能用到。 + +**注意月份取值是索引值** + +### 3.2.2 日期比较和区间判断(3.1.5.7) + +```ts +/** 一天毫秒数 */ +const ONE_DAY = 1000 * 60 * 60 * 24 + +/** 按年、月、日三种颗粒度计算一个整数值 */ +export const dateCounter = (date: Date, type: 'y' | 'm' | 'd') => { + switch(type) { + case 'y': return date.getFullYear() + case 'm': return date.getFullYear() * 12 + date.getMonth() + } + return date.getTime() / ONE_DAY >> 0 +} + +/** 按年、月、日三种颗粒比较两个日期 */ +export const compareDateSort = (d1: Date, d2: Date, type: 'y' | 'm' | 'd') => { + const t1 = dateCounter(d1, type), t2 = dateCounter(d2, type) + return t1 < t2 ? -1 : t1 > t2 ? 1 : 0 +} + +/** + * d 是否在 [left, right] 区间 + * @param date 日期 + * @param left 最小日期 + * @param right 最大日期 + * @returns boolean + */ +export const betweenDate = (date: Date, left: any, right: any): boolean => { + if(left instanceof Date && compareDateSort(left, date, 'd') > 0) { + return false + } + if(right instanceof Date && compareDateSort(date, right, 'd') > 0) { + return false + } + return true +} +``` + +### 3.2.3 日期转换(3.1.5.7) + +```ts +/** 字符串转日期 */ +export const parseDate = (str?: string) : Date | null => { + if(!str || typeof str !== 'string') { + return null + } + + const [dateStr = '', timeStr = ''] = str.split(/([ ]|T)+/) + if(!dateStr) { + return null + } + const [y, m, d] = dateStr.split(/[^\d]+/) + const year = _parseInt(y), month = _parseInt(m), date = _parseInt(d) || 1 + if(!year || !month) { + return null + } + const time = parseTime(timeStr) + return new Date(year, month - 1, date, ...time) +} +``` \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/calendar/index.scss b/packages/devui-vue/devui/date-picker/components/calendar/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..72fe3cf172c218dce785940809b68ca9be68a449 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/calendar/index.scss @@ -0,0 +1,8 @@ +.devui-calendar-container { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + user-select: none; + position: relative; +} diff --git a/packages/devui-vue/devui/date-picker/components/calendar/index.tsx b/packages/devui-vue/devui/date-picker/components/calendar/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2834b42ab8de6c8e8fd1e749de20a5b3a962c38b --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/calendar/index.tsx @@ -0,0 +1,36 @@ +import { TProps } from '../types' +import CalendarDatePanel from '../panel' +import TimePicker from '../timepicker' + +import './index.scss' + +const Calendar = (props: TProps) => { + const { showTime = false } = props + let { current } = props + if (!(current instanceof Date)) { + current = new Date + } + if (props.type === 'range') { + let { next } = props + if (!(next instanceof Date)) { + next = new Date(current.getFullYear(), current.getMonth() + 1, 1) + } + return ( +
        + + { showTime ? : null } + + { showTime ? : null } +
        + ) + } else { + return ( +
        + + { showTime ? : null } +
        + ) + } +} + +export default Calendar \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/helper.ts b/packages/devui-vue/devui/date-picker/components/helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..805d977b50cf556a030f9e51fa2e37b756de3963 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/helper.ts @@ -0,0 +1,79 @@ +import { invokeCallback, subDateDay, betweenDate } from './utils' +import { TDateCell, TDatePanelDataProps, TDatePanelProps } from './types' + +export const getDateKey = (date: Date): string => { + return date.toDateString() +} + +export const cellClassName = (props: TDatePanelDataProps, day: TDateCell, base = 'cell'): string => { + + if(!betweenDate(day.date, props.dateMin, props.dateMax)) { + return `${base} disabled` + } else if(day.current !== 0) { + return `${base} not-current` + } + + const key = getDateKey(day.date) + if (props.type === 'range') { + if (props.dateStart) { + if (getDateKey(props.dateStart) === key) { + return `${base} selected` + } + if (props.dateEnd && getDateKey(props.dateEnd) === key) { + return `${base} selected` + } + const innerEnd = props.dateEnd || props.dateHover + if (innerEnd) { + const range = innerEnd > props.dateStart ? [props.dateStart, innerEnd] : [innerEnd, props.dateStart] + if (day.date > range[0] && day.date < range[1]) { + return `${base} innerday` + } + } + } + return base + } else { + return props.dateStart && getDateKey(props.dateStart) === key ? `${base} selected` : base + } +} + +export const trigEvent = (props: TDatePanelProps, day: TDateCell): void => { + if(!betweenDate(day.date, props.dateMin, props.dateMax)) { + return + } + + if (props.type === 'range') { + if (!props.dateStart) { + invokeCallback(props.onSelectStart, day.date) + } else if (!props.dateEnd) { + if(subDateDay(props.dateStart, day.date) !== 0) { + invokeCallback(props.onSelectEnd, day.date) + typeof props.onChange === 'function' && props.onChange(props.type, props) + } + } else { + invokeCallback(props.onReset, day.date) + } + } else { + invokeCallback(props.onSelected, day.date) + typeof props.onChange === 'function' && props.onChange(props.type, props) + } +} + +export const handleDateEnter = (props: TDatePanelProps, day: TDateCell): void => { + if(day.current !== 0) { + return + } + const { dateMin, dateMax } = props + if(dateMin && subDateDay(day.date, dateMin) < 0) { + return + } + if(dateMax && subDateDay(dateMax, day.date) < 0) { + return + } + if (props.type === 'range') { + const key = getDateKey(day.date) + if (!props.dateStart || getDateKey(props.dateStart) === key || props.dateEnd) { + return + } + invokeCallback(props.onSelecting, day.date) + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/panel/index.scss b/packages/devui-vue/devui/date-picker/components/panel/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..9fb2adaea7a4cb6fec4a8d7a3e2a749d65cda733 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/panel/index.scss @@ -0,0 +1,103 @@ +@import '../../../style/devui.scss'; + +$panel-width: 230px; +$panel-height: 210px; +$panel-padding: 5px; +$panel-row-height: 24px; +$panel-cell-bg: #ffffff; +$panel-cell-color: #000000; +$panel-cell-active-bg: #0066cc; +$panel-cell-active-color: #f1f1f1; +$panel-cell-active-hover-bg: #0088dd; +$panel-cell-active-hover-color: #ffffff; + +.devui-calendar-panel { + width: $panel-width; + padding: $panel-padding; + box-sizing: border-box; + overflow: hidden; + + .row { + display: flex; + flex-direction: row; + justify-content: space-between; + height: $panel-row-height; + + .cell { + width: 100%; + text-align: center; + flex-grow: 1; + flex-shrink: 1; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + border-radius: $devui-border-radius; + background-color: $panel-cell-bg; + color: $panel-cell-color; + + &:hover { + background-color: $devui-disabled-bg; + } + + &.selected { + background-color: $panel-cell-active-bg; + color: $panel-cell-active-color; + + &:hover { + background-color: $panel-cell-active-hover-bg; + color: $panel-cell-active-hover-color; + } + } + + &.innerday { + background-color: $devui-disabled-bg; + } + + &.disabled, + &.not-current { + color: $devui-disabled-text; + } + + &.disabled { + cursor: not-allowed; + } + } + } + + .head { + cursor: default; + padding: 0; + margin: 0; + } + + .body { + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + cursor: pointer; + list-style: none; + } + + .today-container { + padding: 8px 8px; + display: flex; + flex-direction: row; + justify-content: flex-end; + + &.disabled { + .today-button { + border: 1px solid #cccccc; + cursor: not-allowed; + } + } + + .today-button { + border: 1px solid #0066cc; + border-radius: 3px; + padding: 2px 20px; + font-size: 12px; + } + } +} diff --git a/packages/devui-vue/devui/date-picker/components/panel/index.tsx b/packages/devui-vue/devui/date-picker/components/panel/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..71526888a66bbf866e3006990317a96a2020a9ed --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/panel/index.tsx @@ -0,0 +1,53 @@ +import { TDatePanelProps } from '../types' +import { getMonthWeeklyDays, WEEK_DAYS, betweenDate } from '../utils' +import { handleDateEnter, cellClassName, trigEvent } from '../helper' +import Toolbar from '../toolbar' +import TodayDefault from '../today-default' +import './index.scss' + +const CalendarDatePanel = (props: TDatePanelProps) => { + const today = new Date() + return ( +
        + +
          { + WEEK_DAYS.map(day =>
        1. {day}
        2. ) + }
        +
          { + getMonthWeeklyDays(props.current).map(row =>
        • { + row.map(day => { + return ( + trigEvent(props, day)} + onMouseenter={() => handleDateEnter(props, day)} + >{day.date.getDate()} + ) + }) + }
        • ) + }
        + {props.type !== 'range' ? ( + { + typeof props.onToday === 'function' && props.onToday(today, 0) + }} + /> + ) : null} +
        + ) +} + +export default CalendarDatePanel \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/popup/index.scss b/packages/devui-vue/devui/date-picker/components/popup/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..d9208c50646644ddf80b52eef45fa9df09284277 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/popup/index.scss @@ -0,0 +1,14 @@ +.devui-datepicker-popup { + position: fixed; + left: 0; + top: 0; + width: 0; + height: 0; + background-color: rgba(0, 0, 0, 0.2); + z-index: 99; + overflow: visible; + + .popup-tracing { + position: absolute; + } +} diff --git a/packages/devui-vue/devui/date-picker/components/popup/index.tsx b/packages/devui-vue/devui/date-picker/components/popup/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f241927b34a43764e07ffe34803e639e634c4857 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/popup/index.tsx @@ -0,0 +1,109 @@ +import { defineComponent, reactive, renderSlot, ref, useSlots, onMounted, onUnmounted, onBeforeUpdate } from 'vue' +import { EventManager, isIn, traceNode, invokeFunction } from '../../utils' +import { + handlePositionFactory, + formatValue, + formatPlaceholder, + getAttachInputDom, +} from '../../helper' + +import './index.scss' + +type TState = { + x?: string + y?: string + attachInputDom?: string + show: boolean + st: boolean +} + +export default defineComponent({ + name: 'DDatePickerPopup', + props: { + attach: { type: String }, + onBinding: { type: Function }, + onClosed: { type: Function }, + onOpen: { type: Function }, + show: { type: Boolean }, + }, + setup(props) { + + const container = ref() + const evtman = new EventManager() + const state = reactive({ + x: '0', + y: '0', + st: true, + show: !!props.show, + }) + + let el: Element | null = null + + // 弹出层跟踪 + const handlePosition = handlePositionFactory(state, props, container) + + onBeforeUpdate(() => { + state.show = !!props.show + }) + + onMounted(() => { + // 获取绑定节点(默认input) + el = getAttachInputDom(props) + // 绑定节点不存在,作为普通组件展示。 + if (!el) { + state.st = true + state.show = true + return + } else { + state.show = false + state.st = false + } + + invokeFunction(props.onBinding) + + // 绑定节点click事件处理弹出层显示 + evtman.append(el, 'click', () => { + if(!state.show) { + state.show = true + invokeFunction(props.onOpen) + } + }) + // document层处理`点击其他区域隐藏` + evtman.append(document, 'click', (e: MouseEvent) => { + if (!state.show || e.target === el || isIn(e.target as Node, container.value)) { + return + } + state.show = false + invokeFunction(props.onClosed) + // reset() + }) + // 对绑定节点做scroll跟踪,并绑定跟踪事件 + traceNode(el).forEach(node => { + evtman.append(node, 'scroll', handlePosition) + }) + }) + + onUnmounted(() => { + evtman.dispose() + }) + + return () => { + const defaultSlot = renderSlot(useSlots(), 'default') + if (state.st) { + return defaultSlot + } + handlePosition() + return ( +
        + +
        + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/timepicker/index.scss b/packages/devui-vue/devui/date-picker/components/timepicker/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..139b9aaaa27d6fa03304af43b56307ddd428eba8 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/timepicker/index.scss @@ -0,0 +1,69 @@ +@import '../../../style/devui.scss'; +@import '../panel/index.scss'; + +$calendar-timepicker-width: 100px; +$head-height: 32px; + +.devui-calendar-timepicker { + width: $calendar-timepicker-width; + height: $panel-height; + overflow: hidden; + position: relative; + + .head { + height: $head-height; + line-height: $head-height; + background-color: #f1f1f1; + text-align: center; + display: flex; + justify-content: center; + // position: absolute; + // width: 100%; + // top: 50%; + // margin-top: -($head-height / 2); + + // z-index: 20; + + // .chars { + // width: 38%; + // display: flex; + // justify-content: space-between; + + // span { + // color: #000; + // // font-size: 16px; + // // margin-top: -2px + // } + // } + } + + .select { + display: flex; + flex-direction: row; + justify-content: space-around; + height: $panel-height - $head-height; + // height: $panel-height; + .column { + cursor: default; + overflow: auto; + flex-grow: 1; + + span { + display: block; + font-size: 11px; + width: 24px; + height: 24px; + line-height: 24px; + text-align: center; + overflow: hidden; + border-radius: 100%; + background-color: #f6f6f6; + + &.selected { + background-color: #00aaff; + color: #ffffff; + } + } + } + } +} diff --git a/packages/devui-vue/devui/date-picker/components/timepicker/index.tsx b/packages/devui-vue/devui/date-picker/components/timepicker/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..df874f8722b7cd3aab97d05af21e93f090414960 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/timepicker/index.tsx @@ -0,0 +1,59 @@ +import { defineComponent, onMounted, ref, reactive } from 'vue' +import VerticalSliderFunction from '../vertical-slider' + +import './index.scss' + +const TimePicker = defineComponent({ + props: { + time: { type: Date } + }, + setup(props) { + + const { time = new Date() } = props || {} + const state = reactive({ + hour: time.getHours(), + minute: time.getMinutes(), + second: time.getSeconds() + }) + + const hours = Array(24).fill(0).map((_, i) => `${i}`.padStart(2, '0')) + const minutes = Array(60).fill(0).map((_, i) => `${i}`.padStart(2, '0')) + + return () => { + return ( +
        +
        +
        + {/* {`:`} + {`:`} */} + + {state.hour.toString().padStart(2, '0')}: + {state.minute.toString().padStart(2, '0')}: + {state.second.toString().padStart(2, '0')} + +
        +
        +
        + state.hour = idx} + /> + state.minute = idx} + /> + state.second = idx} + /> +
        +
        + ) + } + } +}) + +export default TimePicker \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/today-default/index.tsx b/packages/devui-vue/devui/date-picker/components/today-default/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9ed09cbf7bfe60ed4fd7f2fbf9ae7a53afdeefb4 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/today-default/index.tsx @@ -0,0 +1,19 @@ +type TProps = { + onSelected?: (date: Date) => void + disabled?: boolean +} + +const TodayDefault = (props: TProps) => { + const { onSelected = () => 0, disabled = false } = props + return ( +
        + +
        + ) +} + +export default TodayDefault \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/toolbar/index.scss b/packages/devui-vue/devui/date-picker/components/toolbar/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..d73f4afc503a6b0d568452bb30e28d1322d1b681 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/toolbar/index.scss @@ -0,0 +1,45 @@ +@import '../../../style/devui.scss'; + +$toolbar-height: 32px; +$cell-size: 28px; + +.devui-calendar-toolbar { + height: $toolbar-height; + font-weight: $font-title-weight; + display: flex; + justify-content: space-between; + align-items: center; + user-select: none; + + a { + width: $cell-size; + height: $cell-size; + line-height: $cell-size; + color: $text-color; + display: block; + text-align: center; + flex-shrink: 1; + flex-grow: 0; + cursor: pointer; + text-decoration: none; + + &:hover { + color: $text-color; + text-decoration: none; + } + + &.disabled { + color: $devui-disabled-text; + cursor: not-allowed; + + &:hover { + color: $devui-disabled-text; + } + } + + &.title { + flex-grow: 1; + flex-shrink: 1; + } + } +} diff --git a/packages/devui-vue/devui/date-picker/components/toolbar/index.tsx b/packages/devui-vue/devui/date-picker/components/toolbar/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..802ba1672b213cdb26a7f13a46bd01b00c2094c1 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/toolbar/index.tsx @@ -0,0 +1,76 @@ +import { compareDate, invokeCallback, subDateMonth } from '../utils' +import { Year, Month } from './svg-icon' +import { TCalendarToolbarItemProps, TDateToolbarProps } from '../types' +import './index.scss' + +const Item = (props: TCalendarToolbarItemProps) => { + const { + button: Btn, + disabled = false, + rotate = 0, + date, + pos, + cb, + } = props + const color = disabled ? '#cfd0d3' : '#585d6b' + const className = `${disabled ? 'disabled' : ''}` + const handleClick = disabled ? undefined : () => invokeCallback(props.cb, date, pos) + return ( + + + + ) +} + +export const Title = (props: { date: Date; }) => { + const { date } = props + return ( + { + `${date.getFullYear()}年${(date.getMonth() + 1 + '').padStart(2, '0')}月` + } + ) +} + +const CalendarToolbar = (props: TDateToolbarProps) => { + const { + type, current, compare, pos, + dateMax, dateMin, + onPreviousYear, + onPreviousMonth, + onNextMonth, + onNextYear, + } = props + + const dis = [false, false, false, false] + + if (type === 'range') { + if (pos === 1) { + dis[0] = !compareDate(compare, current, 'year', 1) + dis[1] = !compareDate(compare, current, 'month', 1) + dis[2] = !compareDate(current, dateMax, 'month', 0) + dis[3] = !compareDate(current, dateMax, 'year', 0) + } else { + dis[0] = !compareDate(dateMin, current, 'year', 0) + dis[1] = !compareDate(dateMin, current, 'month', 0) + dis[2] = !compareDate(current, compare, 'month', 1) + dis[3] = !compareDate(current, compare, 'year', 1) + } + } else { + dis[0] = !compareDate(dateMin, current, 'year', 0) + dis[1] = !compareDate(dateMin, current, 'month', 0) + dis[2] = !compareDate(current, dateMax, 'month', 0) + dis[3] = !compareDate(current, dateMax, 'year', 0) + } + + return ( +
        + + + + <Item disabled={dis[2]} date={current} pos={pos} button={Month} rotate={90} cb={onNextMonth} /> + <Item disabled={dis[3]} date={current} pos={pos} button={Year} rotate={180} cb={onNextYear} /> + </div> + ) +} + +export default CalendarToolbar \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/toolbar/svg-icon.tsx b/packages/devui-vue/devui/date-picker/components/toolbar/svg-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..01d9a31a3e853397497af16d85d073773a3128d4 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/toolbar/svg-icon.tsx @@ -0,0 +1,23 @@ +import { TIconSvgProps } from '../types' + +export const Year = (props: TIconSvgProps) => { + const { color = '#585d6b', rotate = 0 } = props + return ( + <svg style={{ transform: `rotate(${rotate}deg)` }} width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <g fill={color} transform="translate(-1.000000, -1.000000)"> + <path d="M11,1.83333333 L11,10.1666667 L7,7.38833333 L7,10.1666667 L1,6 L7,1.83333333 L7,4.61033333 L11,1.83333333 Z" /> + </g> + </svg> + ) +} + +export const Month = (props: TIconSvgProps) => { + const { color = '#585d6b', rotate = 0 } = props + return ( + <svg style={{ transform: `rotate(${rotate}deg)` }} width="6px" height="10px" viewBox="0 0 6 10" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <g fill={color} transform="translate(-3.000000, -1.000000)"> + <polygon points="6 3 10.1666667 9 1.83333333 9" /> + </g> + </svg> + ) +} \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/types.ts b/packages/devui-vue/devui/date-picker/components/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..d11595ee1943cd19a29f241a552e009653e6a3e5 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/types.ts @@ -0,0 +1,70 @@ +export type TDateCell = { date: Date; current: -1 | 0 | 1; } +export type TDatePanelMode = 'month' | 'year' +export type TDatePanelType = 'select' | 'range' +export type TEventCallback = (date: Date, position?: number) => void + +export type TDateConfig = { + type?: TDatePanelType + mode?: TDatePanelMode + current: Date + showTime: boolean + dateMin?: Date + dateMax?: Date +} + +export type TDateSelectingBase = { + dateStart?: Date + dateEnd?: Date + dateHover?: Date +} + +export type TDateToolbarEventProps = { + onPreviousYear?: TEventCallback + onPreviousMonth?: TEventCallback + onNextMonth?: TEventCallback + onNextYear?: TEventCallback +} + +export type TDateToolbarDataProps = TDateConfig & { + pos?: number + compare?: Date +} + +export type TDateToolbarProps = TDateToolbarDataProps & TDateToolbarEventProps + +export type TDatePanelEventProps = TDateToolbarEventProps & { + onSelected?: TEventCallback + onReset?: TEventCallback + onSelectStart?: TEventCallback + onSelectEnd?: TEventCallback + onSelecting?: TEventCallback + onToday?: TEventCallback + onChange?: (type: TDatePanelType, config: TDateSelectingBase) => void +} + +export type TDatePanelDataProps = TDateToolbarDataProps & TDateSelectingBase + +export type TDatePanelProps = { showToday?: boolean; } & TDatePanelDataProps & TDatePanelEventProps + + +export type TProps = ({ + type: 'select' +} | { + type: 'range' + next: Date +}) & TDateConfig & TDateSelectingBase & TDatePanelEventProps + +export type TIconSvgProps = { + color?: string + rotate?: number +} +export type TIconSvg = (props: TIconSvgProps) => any + +export type TCalendarToolbarItemProps = { + disabled?: boolean + rotate?: number + cb?: (...args: any[]) => void + pos: number + date: Date + button: TIconSvg +} \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/utils.ts b/packages/devui-vue/devui/date-picker/components/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..23150961ab6f902b807f804df1a5bbd91147257b --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/utils.ts @@ -0,0 +1,186 @@ +import { TDateCell } from './types' + +const getHumanDate = (d: Date) => { + const year = d.getFullYear() + const month = d.getMonth() + 1 + const date = d.getDate() + const day = d.getDay() + const hour = d.getHours() + const minute = d.getMinutes() + const second = d.getSeconds() + const ms = d.getMilliseconds() + + return { + year, y: year, month, M: month, date, d: date, day, + hour, H: hour, h: hour, + minute, m: minute, + second, s: second, + ms, + } +} + +const getMonthDays = (year: number, month: number) => { + const first = new Date(year, month - 1, 1) + const last = new Date(year, month, 0) + const dates: TDateCell[] = [] + + let day = first.getDay() + while (day > 0) { + day -= 1 + dates.push({ date: new Date(year, month - 1, -day), current: -1 }) + } + + day = last.getDate() - first.getDate() + for (let i = 0; i <= day; i++) { + const date = new Date(first) + date.setDate(i + 1) + dates.push({ date, current: 0 }) + } + + day = last.getDay() + let tail: Date = last + for (let i = day; i < 6; i++) { + tail = new Date(year, month, i - day + 1) + dates.push({ date: tail, current: 1 }) + } + if(dates.length < 42) { + day = tail.getDate() + for (let i = 1; i <= 7; i++) { + tail = new Date(year, month, day + i) + dates.push({ date: tail, current: 1 }) + } + } + return dates +} + +export const getMonthWeeklyDays = (date: any = new Date()) => { + if (!(date instanceof Date)) { + date = new Date() + } + const { year, month } = getHumanDate(date) + const days = getMonthDays(year, month) + const dayRows: TDateCell[][] = [] + while (days.length > 0) { + dayRows.push(days.splice(0, 7)) + } + return dayRows +} + +export const WEEK_DAYS = ['日', '一', '二', '三', '四', '五', '六'] + +export const invokeCallback = (cb: any, ...args: any[]) => { + typeof cb === 'function' && cb(...args) +} + +/** + * a - b 的月数 + */ +export const subDateMonth = (a: Date, b: Date) => { + const am = a.getFullYear() * 12 + a.getMonth() + const bm = b.getFullYear() * 12 + b.getMonth() + return am - bm +} + +const ONE_DAY = 1000 * 60 * 60 * 24 + +/** + * a - b 的天数 + * @param a + * @param b + * @returns + */ +export const subDateDay = (a: Date, b: Date) => { + const ad = new Date(a.getFullYear(), a.getMonth(), a.getDate()).getTime() + const bd = new Date(b.getFullYear(), b.getMonth(), b.getDate()).getTime() + return (ad - bd) / ONE_DAY +} + +/** +* 比较日期单位 +* @param small 相对早的日期 +* @param big 相对晚的日期 +* @param mode 比较单位 +* @param min 不能小于这个值 +* @returns +*/ +export const compareDate = (small: Date | undefined, big: Date | undefined, mode: 'year' | 'month', min: number) => { + if (!small || !big) { + return true + } + if (mode === 'year') { + return big.getFullYear() - small.getFullYear() > min + } else { + return subDateMonth(big, small) > min + } +} + +export const parseDate = (str?: string) : Date | null => { + if(!str || typeof str !== 'string') { + return null + } + + const [dateStr = '', timeStr = ''] = str.split(/([ ]|T)+/) + if(!dateStr) { + return null + } + const [y, m, d] = dateStr.split(/[^\d]+/) + const year = _parseInt(y), month = _parseInt(m), date = _parseInt(d) || 1 + if(!year || !month) { + return null + } + const time = parseTime(timeStr) + return new Date(year, month - 1, date, ...time) +} + +const _parseInt = (str: any, dftVal?: number) => { + if(!str || typeof str !== 'string') { + return dftVal + } + const n = parseInt(str) + if(isNaN(n)) { + return dftVal + } + return n +} + +export const parseTime = (str?: string) : [number, number, number, number] => { + const [h, m, s, ms] = str.split(/[\:\.]+/) + return [_parseInt(h, 0), _parseInt(m, 0), _parseInt(s, 0), _parseInt(ms, 0)] +} + +type TDateCounterType = 'd' | 'm' | 'y' + +export const compareDateSort = (d1: Date, d2: Date, type: TDateCounterType = 'd') => { + const t1 = dateCounter(d1, type), t2 = dateCounter(d2, type) + return t1 < t2 ? -1 : t1 > t2 ? 1 : 0 +} + +export const dateCounter = (date: Date, type: TDateCounterType) => { + switch(type) { + case 'y': return date.getFullYear() + case 'm': return date.getFullYear() * 12 + date.getMonth() + } + return date.getTime() / ONE_DAY >> 0 +} +export const borderDateFactory = (factor: (d1: Date, d2: Date) => Date) => (...ds: Date[]) => { + return ds.length < 2 ? ds[0] || new Date() : ds.reduce((r, v) => factor(r, v)) +} +export const getMinDate = borderDateFactory((d1: Date, d2: Date) => compareDateSort(d1, d2) < 0 ? d1 : d2) +export const getMaxDate = borderDateFactory((d1: Date, d2: Date) => compareDateSort(d1, d2) < 0 ? d2 : d1) + +/** + * d 是否在 [left, right] 区间 + * @param date 日期 + * @param left 最小日期 + * @param right 最大日期 + * @returns boolean + */ +export const betweenDate = (date: Date, left: any, right: any): boolean => { + if(left instanceof Date && compareDateSort(left, date, 'd') > 0) { + return false + } + if(right instanceof Date && compareDateSort(date, right, 'd') > 0) { + return false + } + return true +} \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/components/vertical-slider/index.scss b/packages/devui-vue/devui/date-picker/components/vertical-slider/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..8e2160d290fe997a19a13e2b7162b28e66ae16e9 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/vertical-slider/index.scss @@ -0,0 +1,45 @@ +.devui-vertical-slider { + display: flex; + flex-direction: column; + min-width: 24px; + text-align: center; + position: relative; + overflow: hidden; + flex-grow: 1; + + .movable-bar { + position: relative; + overflow: visible; + + .slider-item { + display: block; + flex-grow: 0; + flex-shrink: 0; + box-sizing: border-box; + + // &.selected { + // background-color: #06c; + // color: #fff; + // } + } + } + + .forcus { + position: absolute; + box-sizing: border-box; + width: 100%; + height: 50%; + top: 25%; + } + + .slider-mask { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + background-color: rgba(0, 0, 0, 0); + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), transparent, rgba(0, 0, 0, 0.3)); + z-index: 99; + } +} diff --git a/packages/devui-vue/devui/date-picker/components/vertical-slider/index.tsx b/packages/devui-vue/devui/date-picker/components/vertical-slider/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..07f0265daaf2461e59afabae6730e5b86c625465 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/components/vertical-slider/index.tsx @@ -0,0 +1,120 @@ +import { defineComponent, reactive, onMounted, ref } from 'vue' + +import './index.scss' + +const VerticalSlider = defineComponent({ + props: { + size: { type: Number, default: 26 }, + items: { type: Array }, + selectedIndex: { type: Number }, + className: { type: String }, + itemClassNormal: { type: String }, + itemClassSelected: { type: String }, + onChange: { type: Function } + }, + setup(props) { + + const { + items = [0,1,2,3,4,5,6,7,8,9], + selectedIndex = 0, + size = 26, + className = '', + itemClassNormal = '', + itemClassSelected = 'selected', + onChange, + } = props || {} + + let max_y = 0, min_y = 0 + const container = ref<Element>() + const movbar = ref<Element>() + + let pos_start: [number, number] | null = null + let pos_cache: [number, number] | null = null + + const state = reactive<{ + selectedIndex: number + barOpacity: number + x: number + y: number + transition: string + }>({ + selectedIndex, + barOpacity: 0, + x: 0, y: 0, + transition: 'none', + }) + + const handleMouseDown = (e: MouseEvent) => { + e.stopPropagation() + e.preventDefault() + pos_start = [e.clientX, e.clientY] + state.transition = 'none' + } + + const handleMouseMove = (e: MouseEvent) => { + e.stopPropagation() + e.preventDefault() + if(!pos_start || !pos_cache) { + return + } + state.x = pos_cache[0] + e.clientX - pos_start[0] + state.y = Math.min(max_y, Math.max(min_y, pos_cache[1] + e.clientY - pos_start[1])) + state.selectedIndex = (max_y - state.y + size / 2) / size >> 0 + } + const handleMouseUp = (e: MouseEvent) => { + e.stopPropagation() + e.preventDefault() + pos_start = null + state.y = max_y - state.selectedIndex * size; + state.transition = 'transform 0.1s' + pos_cache[0] = state.x + pos_cache[1] = state.y + if(typeof onChange === 'function') { + const idx = state.selectedIndex + const val = items[idx] + onChange(val, idx) + } + } + + onMounted(() => { + const { height: ch } = container.value.getBoundingClientRect() + const { height: mh } = movbar.value.getBoundingClientRect() + max_y = (ch - size) / 2 + min_y = (ch + size) / 2 - mh + pos_cache = [0, max_y - state.selectedIndex * size] + state.x = pos_cache[0] + state.y = pos_cache[1] + state.barOpacity = 1 + state.transition = 'transform 0.1s' + // console.log(ch, mh) + }) + + return () => { + return ( + <div ref={container} class={`devui-vertical-slider ${className}`}> + <div ref={movbar} class="movable-bar" style={{ + opacity: state.barOpacity, + transform: `translateY(${state.y}px)`, + transition: state.transition, + }}> + { + items.map((c, i) => { + const className = i === state.selectedIndex ? itemClassSelected : itemClassNormal + return <span class={`slider-item ${className}`} style={{ height: `${size}px`, lineHeight: `${size}px` }}>{c}</span> + }) + } + </div> + <div + class="slider-mask" + onMousedown={handleMouseDown} + onMousemove={handleMouseMove} + onMouseup={handleMouseUp} + onMouseout={handleMouseUp} + ></div> + </div> + ) + } + } +}) + +export default VerticalSlider \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/date-picker.scss b/packages/devui-vue/devui/date-picker/date-picker.scss new file mode 100644 index 0000000000000000000000000000000000000000..60bc524970502d3595c09f32db96c452194d5e00 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/date-picker.scss @@ -0,0 +1,54 @@ +@import '../style/devui.scss'; + +$cell-font-size: 13px; +$border-width: 1px; +$border-style: solid; +$border-color: #dddddd; +$input-border-color: #0066cc; + +.devui-datepicker-container { + .input-container { + border: 1px solid $input-border-color; + border-radius: $devui-border-radius; + display: flex; + flex-direction: row; + width: 200px; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + position: relative; + } + + .datepicker-input { + position: relative; + width: 100%; + + input { + border: 0 solid #000000; + outline: none; + margin-right: 20px; + } + } + + .datepicker-input-icon { + position: absolute; + z-index: 9; + right: 6px; + } + + .devui-datepicker-panel { + border: 1px solid #000000; + margin: 0; + padding: 0; + display: inline-block; + border-width: $border-width; + border-style: $border-style; + border-color: $border-color; + border-radius: $devui-border-radius-card; + box-shadow: $devui-shadow-length-base $devui-shadow; + background-color: $devui-base-bg; + font-size: $cell-font-size; + position: absolute; + z-index: 99; + } +} diff --git a/packages/devui-vue/devui/date-picker/date-picker.tsx b/packages/devui-vue/devui/date-picker/date-picker.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fd11fe99da357dbd2e3c224c318cb2a1de159782 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/date-picker.tsx @@ -0,0 +1,158 @@ +import { onUnmounted, UnwrapRef , defineComponent, reactive, onMounted, ref } from 'vue' +import { invokeFunction, isIn } from './utils' +import { compareDateSort , parseDate } from './components/utils' +import { Input } from '../input' +import { Icon } from '../icon' + +import { + TState, + handleCalendarSwitchState, + formatValue, + formatPlaceholder, +} from './helper' + +import Calendar from './components/calendar' + +import './date-picker.scss' + +const formatRange = (state: UnwrapRef<TState>) => { + const [start, end] = [state.start, state.end].sort((a, b) => a.getTime() - b.getTime()) + + state.start = start + state.end = end + + if (compareDateSort(start, end, 'm') !== 0) { + state.current = start + state.next = end + } else { + if (compareDateSort(start, state.current) < 0) { + state.current = start + } + if (compareDateSort(state.next, end) < 0) { + state.next = end + } + } +} + +export default defineComponent({ + name: 'DDatepicker', + props: { + selectedDateChange: { type: Function }, + autoClose: { type: Boolean, default: false }, + range: { type: Boolean, default: false }, + showTime: { type: Boolean, default: false }, + format: { type: String, default: 'y/MM/dd' }, + rangeSpliter: { type: String, default: '-' }, + attachInputDom: { type: String }, + dateMin: { type: String }, + dateMax: { type: String }, + }, + setup(props, ctx) { + + const panel = ref<Node>(null) + const input = ref<Node>(null) + + const current = parseDate(props.dateMin) || new Date() + const next = new Date(current.getFullYear(), current.getMonth() + 1, 1) + + + const state = reactive<TState>({ + show: false, + value: '', + placeholder: formatPlaceholder(props), + current, + next, + }) + + state.value = formatValue(state, props) + state.placeholder = formatPlaceholder(props) + + const documentClick = (e: MouseEvent) => { + e.stopPropagation() + + if( + isIn(e.target as Node, panel.value) + || isIn(e.target as Node, input.value) + ) { + return + } + state.show = false + } + + onMounted(() => { + document.addEventListener('click', documentClick) + }) + + onUnmounted(() => { + document.removeEventListener('click', documentClick) + }) + + return () => { + return ( + <div class="devui-datepicker-container"> + <div class="input-container" ref={input}> + <Input + ref={input} + class="datepicker-input" + value={state.value} + placeholder={state.placeholder} + onFocus={() => state.show = true } + /> + <Icon size="small" name="calendar" class="datepicker-input-icon" /> + </div> + <div class="devui-datepicker-panel" ref={panel}> + {state.show ? <Calendar + type={props.range ? 'range' : 'select'} + showTime={props.showTime} + current={state.current} + next={state.next} + dateMin={parseDate(props.dateMin)} + dateMax={parseDate(props.dateMax)} + dateStart={state.start} + dateEnd={state.end} + dateHover={state.hover} + onReset={(date: Date) => { + state.end = state.hover = undefined + state.start = date + }} + onChange={(type, config) => { + state.value = formatValue(state, props) + state.placeholder = formatPlaceholder(props) + invokeFunction(props.selectedDateChange, state.value) + if (props.autoClose) { + state.show = false + } + }} + onToday={(date: Date) => { + state.current = date + state.start = date + state.value = formatValue(state, props) + state.placeholder = formatPlaceholder(props) + invokeFunction(props.selectedDateChange, state.value) + if (props.autoClose) { + state.show = false + } + }} + onSelected={(date: Date) => { + state.start = date + if (compareDateSort(state.current, date) !== 0) { + state.current = date + } + }} + onSelectStart={(date: Date) => state.start = date} + onSelectEnd={(date: Date) => { + state.end = date + formatRange(state) + }} + onSelecting={(date: Date) => state.hover = date} + onPreviousYear={(date: Date, pos: number) => handleCalendarSwitchState(state, 0, pos, date)} + onPreviousMonth={(date: Date, pos: number) => handleCalendarSwitchState(state, 1, pos, date)} + onNextMonth={(date: Date, pos: number) => handleCalendarSwitchState(state, 2, pos, date)} + onNextYear={(date: Date, pos: number) => handleCalendarSwitchState(state, 3, pos, date)} + /> : null} + </div> + </div> + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/helper.ts b/packages/devui-vue/devui/date-picker/helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..47baf8fa50987f6a45d3bea189d9c0db96deaeba --- /dev/null +++ b/packages/devui-vue/devui/date-picker/helper.ts @@ -0,0 +1,156 @@ +import type { Ref } from 'vue' +import { formatDate, formatRange } from './utils' + +export type TState = { + range?: boolean + current?: Date + next?: Date + start?: Date + end?: Date + hover?: Date + show?: boolean + input?: string + value?: string + placeholder?: string +} + +/** + * Calendar 面板年月切换逻辑 + * @param state + * @param index + * @param pos + * @param date + */ +export const handleCalendarSwitchState = (state: TState, index: number, pos: number, date: Date) => { + switch (index) { + case 0: // previous year + const preYear = new Date(date) + preYear.setFullYear(preYear.getFullYear() - 1) + pos === 0 ? (state.current = preYear) : (state.next = preYear) + break + case 1: // previous month + const preMonth = new Date(date) + preMonth.setMonth(preMonth.getMonth() - 1) + pos === 0 ? (state.current = preMonth) : (state.next = preMonth) + break + case 2: // next month + const nextMonth = new Date(date) + nextMonth.setMonth(nextMonth.getMonth() + 1) + pos === 0 ? (state.current = nextMonth) : (state.next = nextMonth) + break + case 3: // next year + const nextYear = new Date(date) + nextYear.setFullYear(nextYear.getFullYear() + 1) + pos === 0 ? (state.current = nextYear) : (state.next = nextYear) + break + } +} + +/** + * 格式化输入日期字符串 + * @param state + * @param props + * @returns + */ +export const formatValue = (state: TState, props: any) => { + const { format = 'y/MM/dd', range, rangeSpliter = '-' } = props || {} + if (range) { + if (!state.start) { + return '' + } else if(!state.end) { + return formatDate(format, state.start) + } + if(state.end < state.start) { + const end = state.end + state.end = state.start + state.start = end + } + return formatRange(format, + state.start, + state.end, + rangeSpliter + ) + } else { + if (!state.start) { + return '' + } + return formatDate(format, state.start) + } +} + +/** + * 格式化placeholder显示 + * @param props + * @returns + */ +export const formatPlaceholder = (props: any) => { + if (!props) return '' + const format = props.format || `y/MM/dd` + const sp = props.rangeSpliter || '-' + return props.range ? `${format} ${sp} ${format}` : format +} + +/** + * 输出日期选择结果 + * @param id + * @param output + */ +export const handleValue = (id: string | undefined, output: string) => { + if (id && typeof id === 'string') { + const el = document.querySelector(id) + if (el instanceof HTMLInputElement) { + el.value = output + } + } +} + +/** + * 获取绑定节点 + * @returns + */ +export const getAttachInputDom = (props: any) => { + const { attach, attachInputDom = attach } = props || {} + if (!attachInputDom || typeof attachInputDom !== 'string') { + return null + } + const el = document.querySelector(attachInputDom) + if (!el) { + return null + } + return el +} + +/** + * 绑定弹出层场景,计算弹出层位置。 + * @param state + * @param props + * @param container + * @returns + */ +export const handlePositionFactory = (state: { + x?: string + y?: string + attachInputDom?: string + show?: boolean + st?: boolean +}, props: any, container: Ref<Element>) => () => { + if (!state.show) { + state.x = `-100%` + state.y = `-100%` + return + } + const el = getAttachInputDom(props) + if (!el) { + state.st = true + return + } + const { left, top, width, height } = el.getBoundingClientRect() + const { width: _width, height: _height } = container.value.getBoundingClientRect() + const bottom = window.innerHeight - top - height + state.x = `${left}px` + if (bottom > top) { + state.y = `${top + height}px` + } else { + state.y = `${top - _height}px` + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/index.ts b/packages/devui-vue/devui/date-picker/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..26274dc708352d1aaedc1a7494f8eb8d982d6703 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/index.ts @@ -0,0 +1,19 @@ +import { App } from 'vue' +import DatePicker from './date-picker' +import StickSlider from './stick-slider' + +DatePicker.install = function(app: App) { + app.component(DatePicker.name, DatePicker) + app.component(StickSlider.name, StickSlider) +} + +export { DatePicker, StickSlider } + +export default { + title: 'DatePicker 日期选择器', + category: '数据录入', + status: '50%', + install(app: App): void { + app.use(DatePicker) + } +} diff --git a/packages/devui-vue/devui/date-picker/stick-slider/index.scss b/packages/devui-vue/devui/date-picker/stick-slider/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..46436f2fcd563c269f1001f3c4947253ba2d2116 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/stick-slider/index.scss @@ -0,0 +1,47 @@ +.devui-stick-slider { + border: 1px solid #000000; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + border-radius: 100%; + position: relative; + width: 36px; + height: 36px; + + .main-button { + width: 36px; + height: 36px; + cursor: pointer; + user-select: none; + background-color: red; + border-radius: 100%; + position: relative; + z-index: 10; + } + + .sub-buttons { + border: 1px solid #0000ff; + width: 240px; + height: 240px; + position: absolute; + display: flex; + flex-direction: row; + flex-wrap: wrap; + + .button { + width: 48px; + height: 48px; + line-height: 48px; + text-align: center; + background-color: #ffaa00; + position: relative; + margin: 5px; + cursor: pointer; + + &.selected { + background-color: #ff3300; + } + } + } +} diff --git a/packages/devui-vue/devui/date-picker/stick-slider/index.tsx b/packages/devui-vue/devui/date-picker/stick-slider/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d51ef64d84ea6e4c0bd6780f039cddd2da8cc951 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/stick-slider/index.tsx @@ -0,0 +1,58 @@ +import { defineComponent, reactive } from 'vue' + +import './index.scss' + +const StickSlider = defineComponent({ + name: 'DStickSlider', + props: {}, + setup(props) { + + const state = reactive({ + showButtons: false, + selectedIndex: 0, + }) + + const reset = () => { + state.showButtons = false + } + + const handleMainButtonMouseDown = (e: MouseEvent) => { + e.stopPropagation() + state.showButtons = true + } + const handleMainButtonMouseUp = (e: MouseEvent) => { + e.stopPropagation() + reset() + } + + return () => { + return ( + <div + class="devui-stick-slider" + onMousedown={handleMainButtonMouseDown} + onMouseup={handleMainButtonMouseUp} + onMouseleave={handleMainButtonMouseUp} + > + <div + class="sub-buttons" + style={{ display: state.showButtons ? '' : 'none' }} + > + { + Array(16).fill(null).map((_, i) => { + return (<div + class={`button ${i === state.selectedIndex ? 'selected' : ''}`} + onMouseenter={() => state.selectedIndex = i} + >{i}</div>) + }) + } + </div> + <div class="main-button"></div> + </div> + ) + } + } +}) + + + +export default StickSlider \ No newline at end of file diff --git a/packages/devui-vue/devui/date-picker/utils.ts b/packages/devui-vue/devui/date-picker/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..9400fc5fe80ef2105e650b874769cee434fb9148 --- /dev/null +++ b/packages/devui-vue/devui/date-picker/utils.ts @@ -0,0 +1,110 @@ +const getDateTime = (d: Date) => { + const year = d.getFullYear() + const month = d.getMonth() + 1 + const date = d.getDate() + const day = d.getDay() + const hour = d.getHours() + const minute = d.getMinutes() + const second = d.getSeconds() + const ms = d.getMilliseconds() + return [year, month, date, day, hour, minute, second, ms] +} + +const fixStart = (n: number, m: string, max = 2, ch = '0') => { + return (n + '').padStart(Math.min(m.length, max), ch) +} + +/** + * - y: year yy 取后2位,其他情况取4位 + * - M: month 最多取2位补0 + * @param fmt + * @param d + */ +export const formatDate = (fmt: string, d: Date) => { + const usage = getDateTime(d) + let res = fmt + res = res.replace(/y+/g, m => { + const year = usage[0] + '' + if (m.length === 2) { + return year.substring(2) + } + return year + }) + res = res.replace(/M+/g, m => fixStart(usage[1], m)) + res = res.replace(/d+/g, m => fixStart(usage[2], m)) + res = res.replace(/h+/g, m => fixStart(usage[4], m)) + res = res.replace(/m+/g, m => fixStart(usage[5], m)) + res = res.replace(/s+/g, m => fixStart(usage[6], m)) + return res +} + +export const formatRange = (fmt: string, a: Date, b: Date, conn = '-') => { + const ab = [a, b] + if(a.getTime() > b.getTime()) { + ab.reverse() + } + return `${formatDate(fmt, ab[0])} ${conn} ${formatDate(fmt, ab[1])}` +} + +/** + * 判断节点a是否在节点b中 + * @param a + * @param b + * @returns + */ +export const isIn = (a: Node | null, b: any) => { + if (!b) { + return false + } + while (a) { + if (a === b) { + return true + } + a = a.parentNode + } + return false +} + +type EventItem = { el: Node | Window; cb: (...args: any[]) => any; name: string; capture: boolean; } +export class EventManager { + private readonly items: EventItem[] + constructor() { + this.items = [] + } + + append(el: Node | Window, name: string, cb: (...args: any[]) => any, capture = false) { + el.addEventListener(name, cb, capture) + this.items.push({ el, name, cb, capture }) + } + + dispose() { + this.items.splice(0, this.items.length).forEach(({ el, name, cb, capture }) => { + el.removeEventListener(name, cb, capture) + }) + } +} + +export const traceNode = (el: Node) => { + const els: Node[] = [], name = 'scroll' + while (el.parentNode) { + els.push(el.parentNode) + el = el.parentNode + } + return els +} + +/** + * 函数安全调用 + */ +export const invokeFunction = (fn: any, ...args: any[]) => { + if (typeof fn === 'function') { + fn(...args) + } +} + +export const getMinDate = (a?: Date, b?: Date) => { + if(a && b) { + return a > b ? b : a + } + return a || b || undefined +} \ No newline at end of file diff --git a/packages/devui-vue/devui/dragdrop/__tests__/dragdrop.spec.ts b/packages/devui-vue/devui/dragdrop/__tests__/dragdrop.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..83981b23ee863aa104b0aed97cadfa21a4e99533 --- /dev/null +++ b/packages/devui-vue/devui/dragdrop/__tests__/dragdrop.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { DragdropDirective } from '../index'; + +describe('dragdrop test', () => { + it('dragdrop init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/dragdrop/index.ts b/packages/devui-vue/devui/dragdrop/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ab571518cb6e0f43c4eb096d632cc91a9b6c1b4 --- /dev/null +++ b/packages/devui-vue/devui/dragdrop/index.ts @@ -0,0 +1,15 @@ +import type { App } from 'vue' +import DraggableDirective from './src/draggable.directive' +import DroppableDirective from './src/droppable.directive' + +export { DraggableDirective, DroppableDirective } + +export default { + title: 'Dragdrop 拖拽', + category: '通用', + status: '10%', + install(app: App): void { + app.directive('DDraggable', DraggableDirective) + app.directive('DDroppable', DroppableDirective) + } +} diff --git a/packages/devui-vue/devui/dragdrop/src/draggable.directive.ts b/packages/devui-vue/devui/dragdrop/src/draggable.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..c53e3342c1f70652f065ff235c678f4ab69d9122 --- /dev/null +++ b/packages/devui-vue/devui/dragdrop/src/draggable.directive.ts @@ -0,0 +1,11 @@ +export default { + mounted(el: HTMLElement): void { + el.setAttribute('draggable', 'true') + el.style.cursor = 'grab' + + // dragstart/drag/dragend + el.addEventListener('dragstart', (event: DragEvent) => { + event.dataTransfer.setData('originId', el.id) + }) + }, +} diff --git a/packages/devui-vue/devui/dragdrop/src/droppable.directive.ts b/packages/devui-vue/devui/dragdrop/src/droppable.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..d60618868e0b5dddab2599dc2f35d92b36aee14c --- /dev/null +++ b/packages/devui-vue/devui/dragdrop/src/droppable.directive.ts @@ -0,0 +1,15 @@ +export default { + mounted(el: HTMLElement): void { + // dragenter/dragover/dragend/drop + el.addEventListener('dragover', (event: DragEvent) => { + event.preventDefault() + }) + + el.addEventListener('drop', (event: DragEvent) => { + const originId = event.dataTransfer.getData('originId') + const originNodeCopy = document.getElementById(originId).cloneNode(true) + const targetNode: any = event.target + targetNode.append(originNodeCopy) + }) + }, +} diff --git a/packages/devui-vue/devui/drawer/index.ts b/packages/devui-vue/devui/drawer/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..342b0f9339b9c656d2172ba98d83a917b371bd4c --- /dev/null +++ b/packages/devui-vue/devui/drawer/index.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue' +import Drawer from './src/drawer' + +Drawer.install = function(app: App): void { + app.component(Drawer.name, Drawer) +} + +export { Drawer } + +export default { + title: 'Drawer 抽屉板', + category: '反馈', + status: '30%', + install(app: App): void { + + app.use(Drawer as any) + } +} diff --git a/packages/devui-vue/devui/drawer/src/components/drawer-body.scss b/packages/devui-vue/devui/drawer/src/components/drawer-body.scss new file mode 100644 index 0000000000000000000000000000000000000000..707fae38018469c198fbfa5a3d57320700f01b3d --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/components/drawer-body.scss @@ -0,0 +1,43 @@ +@import '../../../style/devui.scss'; + +.devui-drawer { + position: fixed; + top: 0; + left: 0; + height: 100vh; +} + +.devui-overlay-wrapper { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: 0; + bottom: 0; + width: 100vw; +} + +.devui-overlay-backdrop { + position: absolute; + top: 0; + left: 0; + background: $devui-shadow; + width: 100vw; + height: 100vh; +} + +.devui-drawer-nav { + position: absolute; + top: 0; + bottom: 0; + border-radius: $devui-border-radius; + background: $devui-base-bg; +} + +.devui-drawer-content { + border-radius: $devui-border-radius; + overflow: auto; + box-shadow: $devui-shadow-length-fullscreen-overlay $devui-shadow; + padding: 20px; + height: 100vh; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/drawer/src/components/drawer-body.tsx b/packages/devui-vue/devui/drawer/src/components/drawer-body.tsx new file mode 100644 index 0000000000000000000000000000000000000000..00d64fee17f480050ef4229820b6373fe31ecdac --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/components/drawer-body.tsx @@ -0,0 +1,53 @@ +import { defineComponent, inject, computed, toRefs, onUnmounted } from 'vue' + +import './drawer-body.scss' + +export default defineComponent({ + name: 'DrawerBody', + setup(props, { slots }) { + const isFullScreen: any = inject('isFullScreen') + const closeDrawer: any = inject('closeDrawer') + const zindex: number = inject('zindex') + const isCover: boolean = inject('isCover') + const position: any = inject('position') + const width: any = inject('width') + const visible: boolean = inject('visible') + + const navRight = computed(() => position.value === 'right' ? { 'right': 0 } : { 'left': 0 }) + const navWidth = computed(() => isFullScreen.value ? '100vw' : width.value) + + let clickContent = (e) => { + e.stopPropagation() + } + + return { + closeDrawer, + zindex, + slots, + isCover, + navRight, + navWidth, + visible, + clickContent, + } + }, + + render() { + const { zindex, closeDrawer, slots, isCover, navRight, navWidth, visible } = this + + if (!visible) return null + + return ( + <div class="devui-drawer" style={{ zIndex: zindex }} onClick={closeDrawer} > + {isCover ? <div class="devui-overlay-backdrop" /> : null} + <div class="devui-overlay-wrapper"> + <div class="devui-drawer-nav" style={{ 'width': navWidth, ...navRight }}> + <div class="devui-drawer-content" onClick={this.clickContent}> + {slots.default ? slots.default() : null} + </div> + </div> + </div> + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/drawer/src/components/drawer-container.tsx b/packages/devui-vue/devui/drawer/src/components/drawer-container.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c45f3b25456a9197aa6164b1a6d5735d60cdc3cc --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/components/drawer-container.tsx @@ -0,0 +1,14 @@ +import { defineComponent, inject } from 'vue' + +export default defineComponent({ + name: 'DrawerContainer', + setup() { + const visible = inject('visible') + return { visible } + }, + render() { + const { visible } = this + if (!visible) return null + return <div>内容区域</div> + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/drawer/src/components/drawer-header.scss b/packages/devui-vue/devui/drawer/src/components/drawer-header.scss new file mode 100644 index 0000000000000000000000000000000000000000..ee1776a5d0c509c4c34ffa85622c855f77adb1c8 --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/components/drawer-header.scss @@ -0,0 +1,11 @@ +@import '../drawer.scss'; + +.devui-drawer-header { + display: flex; + flex-direction: row; + justify-content: flex-end; + + & .devui-drawer-header-item + .devui-drawer-header-item { + padding-left: 12px; + } +} diff --git a/packages/devui-vue/devui/drawer/src/components/drawer-header.tsx b/packages/devui-vue/devui/drawer/src/components/drawer-header.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8db4bec7e95cf1c1dc50db7b833526fa26dbe1e1 --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/components/drawer-header.tsx @@ -0,0 +1,46 @@ +import { defineComponent, ref, inject, computed, onUnmounted } from 'vue' + +import './drawer-header.scss' + +export default defineComponent({ + name: 'DrawerHeader', // 头部 + emits: ['toggleFullScreen', 'close'], + setup(props, ctx) { + const isFullScreen = ref(false) + + const visible: boolean = inject('visible') + + const fullScreenClassName = computed(() => isFullScreen.value ? 'icon icon-minimize' : 'icon icon-maxmize') + + const handleFullScreen = (e) => { + e.stopPropagation() + isFullScreen.value = !isFullScreen.value + ctx.emit('toggleFullScreen') + } + + const handleDrawerClose = () => { + ctx.emit('close') + } + + return { fullScreenClassName, visible, handleFullScreen, handleDrawerClose, } + }, + render() { + const { handleFullScreen, handleDrawerClose, visible, fullScreenClassName } = this + + if (!visible) return null + + return ( + <div class="devui-drawer-header"> + <div class="devui-drawer-header-item"> + <span class="devui-drawer-header-item icon icon-more-operate" /> + </div> + <div class="devui-drawer-header-item" onClick={handleFullScreen}> + <span class={fullScreenClassName}/> + </div> + <div class="devui-drawer-header-item" onClick={handleDrawerClose}> + <span class="icon icon-close" /> + </div> + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/drawer/src/drawer-types.ts b/packages/devui-vue/devui/drawer/src/drawer-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..9cdc51e6ef1c27fb98b5b2bfb5880f838e20ff44 --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/drawer-types.ts @@ -0,0 +1,30 @@ +import type { ExtractPropTypes, PropType } from 'vue' + +export const drawerProps = { + width: { + type: String, + default: '300px', + }, + visible: { + type: Boolean, + default: false, + }, + zIndex: { + type: Number, + default: 1000, + }, + isCover: { + type: Boolean, + default: true, + }, + escKeyCloseable: { + type: Boolean, + default: true, + }, + position: { + type: String as PropType<'left' | 'right'>, + default: 'left', + }, +} as const + +export type DrawerProps = ExtractPropTypes<typeof drawerProps> diff --git a/packages/devui-vue/devui/drawer/src/drawer.scss b/packages/devui-vue/devui/drawer/src/drawer.scss new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/drawer.scss @@ -0,0 +1 @@ + diff --git a/packages/devui-vue/devui/drawer/src/drawer.tsx b/packages/devui-vue/devui/drawer/src/drawer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3b2be3ff4b2d239fc84d274d84e8293d861f2fdf --- /dev/null +++ b/packages/devui-vue/devui/drawer/src/drawer.tsx @@ -0,0 +1,78 @@ +import { defineComponent, ref, toRefs, watch, onUnmounted, Teleport, provide } from 'vue' +import { drawerProps, DrawerProps } from './drawer-types' + +import DrawerHeader from './components/drawer-header' +import DrawerContainer from './components/drawer-container' +import DrawerBody from './components/drawer-body' + +export default defineComponent({ + name: 'DDrawer', + props: drawerProps, + emits: ['close', 'update:visible', 'afterOpened'], + setup(props: DrawerProps, { emit, slots }) { + const { width, visible, zIndex, isCover, escKeyCloseable, position } = toRefs(props) // 宽度 + let isFullScreen = ref(false) + + const fullScreenEvent = () => { + isFullScreen.value = !isFullScreen.value + } + + const closeDrawer = () => { + emit('update:visible', false) + emit('close') + } + + const escCloseDrawer = (e) => { + if (e.code === 'Escape') { + closeDrawer() + } + } + + watch(visible, (val) => { + if (val) { + emit('afterOpened') + isFullScreen.value = false + } + if (escKeyCloseable && val) { + document.addEventListener('keyup', escCloseDrawer) + } else { + document.removeEventListener('keyup', escCloseDrawer) + } + }) + + provide('closeDrawer', closeDrawer) + provide('zindex', zIndex) + provide('isCover', isCover) + provide('position', position) + provide('width', width) + provide('visible', visible) + provide('isFullScreen', isFullScreen) + + onUnmounted(() => { + document.removeEventListener('keyup', escCloseDrawer) + }) + + return { + isFullScreen, + visible, + slots, + fullScreenEvent, + closeDrawer, + } + }, + render() { + const fullScreenEvent: any = this.fullScreenEvent + const closeDrawer: any = this.closeDrawer + + if (!this.visible) return null + + return ( + <Teleport to="body"> + <DrawerBody> + <DrawerHeader onToggleFullScreen={fullScreenEvent} onClose={closeDrawer} /> + {this.slots.default ? this.slots.default() : <DrawerContainer />} + </DrawerBody> + </Teleport> + ) + } +}) diff --git a/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts b/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f842c738ef8fc3f81d2d1d81221799ba39477c55 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Dropdown } from '../index'; + +describe('dropdown test', () => { + it('dropdown init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/dropdown/index.ts b/packages/devui-vue/devui/dropdown/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3bf24e74ca37403a1eae2eed6a957f4aa85ff86 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/index.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue' + +import Dropdown from './src/dropdown' + +Dropdown.install = function (app: App): void { + app.component(Dropdown.name, Dropdown) +} + +export { Dropdown } + +export default { + title: 'Dropdown 下拉菜单', + category: '导航', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Dropdown as any) + } +} diff --git a/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts b/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..38d67100b7cbb1d68560049d486f54682e7195e0 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts @@ -0,0 +1,7 @@ +export const dDropdownDirective = { + +}; + +export const dDropdownMenuDirective = { + +}; diff --git a/packages/devui-vue/devui/dropdown/src/dropdown-types.ts b/packages/devui-vue/devui/dropdown/src/dropdown-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed072b108d800599d72ae479b878976cb3bf5667 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown-types.ts @@ -0,0 +1,45 @@ +import type { PropType, ExtractPropTypes, ComponentPublicInstance } from 'vue' + +export type TriggerType = 'click' | 'hover' | 'manually'; +export type CloseScopeArea = 'all' | 'blank' | 'none'; + + +export const dropdownProps = { + origin: { + type: Object as PropType<Element | ComponentPublicInstance>, + required: true + }, + + isOpen: { + type: Boolean, + default: false + }, + + disabled: { + type: Boolean, + default: false + }, + + trigger: { + type: String as PropType<TriggerType>, + default: 'click' + }, + + closeScope: { + type: String as PropType<CloseScopeArea>, + default: 'all' + }, + + closeOnMouseLeaveMenu: { + type: Boolean, + default: true + }, + + showAnimation: { + type: Boolean, + default: true + } + +} as const + +export type DropdownProps = ExtractPropTypes<typeof dropdownProps> diff --git a/packages/devui-vue/devui/dropdown/src/dropdown.scss b/packages/devui-vue/devui/dropdown/src/dropdown.scss new file mode 100644 index 0000000000000000000000000000000000000000..faa3cd509d4e43f03542277485d261c16bc0d357 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown.scss @@ -0,0 +1,61 @@ +@import '../../styles-var/devui-var'; + +.devui-dropdown span { + &.icon-chevron-down, + &.icon-select-arrow { + display: inline-block; + vertical-align: text-top; + } +} + +.devui-dropdown-animation span { + &.icon-chevron-down, + &.icon-select-arrow { + transition: transform $devui-animation-duration-slow $devui-animation-ease-in-out-smooth; + } +} + +.devui-dropdown.open span { + &.icon-chevron-down, + &.icon-select-arrow { + transform: rotate(180deg); + } +} + + + +.devui-dropdown-fade { + @mixin d-dropdown-fade-animation { + animation-name: d-dropdown-fade; + animation-duration: 0.3s; + } + @keyframes d-dropdown-fade { + 0% { + opacity: 0; + transform: scaleY(0.9999) scaleY(0); + } + + 100% { + opacity: 1; + transform: scaleY(0.8) scaleY(4px); + } + } + + &-enter { + opacity: 0; + } + + &-enter-active { + @include d-dropdown-fade-animation; + } + + &-leave { + opacity: 1; + } + + &-leave-active { + @include d-dropdown-fade-animation; + + animation-direction: reverse; + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/dropdown/src/dropdown.tsx b/packages/devui-vue/devui/dropdown/src/dropdown.tsx new file mode 100644 index 0000000000000000000000000000000000000000..589d8c6359e64abf5b6a559acdcb86ca48fa7594 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown.tsx @@ -0,0 +1,66 @@ +import { defineComponent, watch, ref, toRefs, Transition, computed } from 'vue' +import { dropdownProps, DropdownProps } from './dropdown-types' +import { useDropdown } from './use-dropdown'; + +import { FlexibleOverlay } from '../../overlay'; + +import './dropdown.scss' + +export default defineComponent({ + name: 'DDropdown', + props: dropdownProps, + emits: [], + setup(props: DropdownProps, ctx) { + const { + isOpen, + origin, + trigger, + closeScope, + closeOnMouseLeaveMenu, + } = toRefs(props); + + const visible = ref<boolean>(false); + watch(isOpen, (value) => { + visible.value = value; + }, { immediate: true }); + + const position = { + originX: 'left', + originY: 'bottom', + overlayX: 'left', + overlayY: 'top' + } as const; + + const { dropdownEl } = useDropdown({ + visible, + origin, + trigger, + closeScope, + closeOnMouseLeaveMenu, + }); + + const animatedVisible = computed(() => { + return props.showAnimation ? visible.value : true; + }); + + return () => { + // let vnodes = ctx.slots.default?.() ?? []; + return ( + <> + <FlexibleOverlay + origin={props.origin} + v-model:visible={visible.value} + position={position} + hasBackdrop={false} + > + <Transition name="devui-dropdown-fade"> + <div v-show={animatedVisible.value} ref={dropdownEl} style="width:100vw"> + {ctx.slots.default?.()} + </div> + </Transition> + </FlexibleOverlay> + </> + ) + }; + } +}) diff --git a/packages/devui-vue/devui/dropdown/src/use-dropdown.ts b/packages/devui-vue/devui/dropdown/src/use-dropdown.ts new file mode 100644 index 0000000000000000000000000000000000000000..596a4579311c3265eb8154b0137446fdc986929a --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/use-dropdown.ts @@ -0,0 +1,120 @@ +import { Ref, ref, watch } from 'vue'; +import { getElement } from '../../shared/util/dom'; +import { CloseScopeArea, TriggerType } from './dropdown-types'; + +function subscribeEvent<E = Event>(dom: Element | Document, type: string, callback: (event: E) => void) { + dom?.addEventListener(type, callback as any); + return () => { + dom?.removeEventListener(type, callback as any); + } +} + +type ReadonlyRef<T> = Readonly<Ref<T>>; + +interface UseDropdownProps { + visible: Ref<boolean> + trigger: ReadonlyRef<TriggerType> + origin: ReadonlyRef<any> + closeScope: ReadonlyRef<CloseScopeArea> + closeOnMouseLeaveMenu: ReadonlyRef<boolean> +} + +interface UseDropdownResult { + dropdownEl: Ref<HTMLElement> +} + +export const useDropdown = ({ + visible, + trigger, + origin, + closeScope, + closeOnMouseLeaveMenu +}: UseDropdownProps): UseDropdownResult => { + const dropdownElRef = ref<HTMLElement>(); + + const closeByScope = () => { + if (closeScope.value === 'none') { + return; + } + visible.value = false; + } + watch( + [trigger, origin, dropdownElRef], + ([trigger, origin, dropdownEl], ov, onInvalidate) => { + const originEl = getElement(origin); + if (!originEl || !dropdownEl) { + return; + } + const subscriptions = [ + subscribeEvent(dropdownEl, 'click', () => { + if (closeScope.value === 'all') { + visible.value = false; + } + }), + ]; + + if (trigger === 'click') { + // 点击触发 + subscriptions.push( + subscribeEvent(originEl, 'click', () => visible.value = !visible.value), + subscribeEvent(document, 'click', (e) => { + if (!visible.value) { + return; + } + const target = e.target as HTMLElement; + const isContain = originEl.contains(target) || dropdownEl.contains(target); + if (isContain) { + return; + } + closeByScope(); + }), + subscribeEvent(dropdownEl, 'mouseleave', () => { + // 判断鼠标是否已经进入 origin + if (closeOnMouseLeaveMenu.value) { + visible.value = false; + } + }) + ); + } else if (trigger === 'hover') { + // 鼠标悬浮触发 + let overlayEnter = false; + let originEnter = false; + const handleLeave = async (elementType: 'origin' | 'dropdown') => { + // 由于关联元素和 dropdown 元素间有间距, + // 悬浮时在两者之间移动可能会导致多次关闭打开, + // 所以需要给关闭触发节流。 + await new Promise((resolve) => setTimeout(resolve, 50)); + if ((elementType === 'origin' && overlayEnter) || (elementType === 'dropdown' && originEnter)) { + return; + } + closeByScope(); + }; + subscriptions.push( + subscribeEvent(originEl, 'mouseenter', () => { + originEnter = true; + visible.value = true; + }), + subscribeEvent(originEl, 'mouseleave', () => { + originEnter = false; + // 判断鼠标是否已经进入 overlay + if (!closeOnMouseLeaveMenu.value) { + handleLeave('origin'); + } + }), + subscribeEvent(dropdownEl, 'mouseenter', () => { + overlayEnter = true; + visible.value = true; + }), + subscribeEvent(dropdownEl, 'mouseleave', () => { + overlayEnter = false; + // 判断鼠标是否已经进入 origin + handleLeave('dropdown'); + }) + ); + } + onInvalidate(() => subscriptions.forEach(v => v())); + } + ); + + return { dropdownEl: dropdownElRef }; +} diff --git a/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts b/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa694a308b703f06ced6875e435057fdc97350f4 --- /dev/null +++ b/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { EditableSelect } from '../index'; + +describe('editable-select test', () => { + it('editable-select init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/editable-select/index.ts b/packages/devui-vue/devui/editable-select/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..411728313716c4f53e85b39ecb87f7dc765ab8bf --- /dev/null +++ b/packages/devui-vue/devui/editable-select/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import EditableSelect from './src/editable-select' + +EditableSelect.install = function(app: App): void { + app.component(EditableSelect.name, EditableSelect) +} + +export { EditableSelect } + +export default { + title: 'EditableSelect 可输入下拉选择框', + category: '数据录入', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(EditableSelect as any) + } +} diff --git a/packages/devui-vue/devui/editable-select/src/editable-select-types.ts b/packages/devui-vue/devui/editable-select/src/editable-select-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..4da866665772dc30d0ab009d275ba650367315d8 --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/editable-select-types.ts @@ -0,0 +1,49 @@ +import type { PropType, ExtractPropTypes } from 'vue' +export interface OptionItem { + name: string + [key: string]: any +} +export type Options = Array<string | OptionItem> +export const editableSelectProps = { + /* test: { + type: Object as PropType<{ xxx: xxx }> + } */ + modelValue: { + type: [String, Number] as PropType<string | number> + }, + options: { + type: Array as PropType<Options>, + default: () => [] + }, + width: { + type: Number + }, + maxHeight: { + type: Number + }, + disabled: { + type: Boolean, + default: false + }, + disabledKey: { + type: String, + }, + remote: { + type: Boolean, + default: false + }, + loading: { + type: Boolean + }, + remoteMethod: { + type: Function as PropType<(inputValue: string) => Array<Options>> + }, + filterMethod: { + type: Function as PropType<(inputValue: string) => Array<Options>> + }, + searchFn: { + type: Function as PropType<(term: string) => Array<Options>>, + } +} as const + +export type EditableSelectProps = ExtractPropTypes<typeof editableSelectProps> diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.scss b/packages/devui-vue/devui/editable-select/src/editable-select.scss new file mode 100644 index 0000000000000000000000000000000000000000..78714927a24c4c9db4db8cc193bcd93b0118baae --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/editable-select.scss @@ -0,0 +1,126 @@ +@import '../../style/theme/color'; +@import '../../style/core/animation'; + +.devui-form-group { + input::-ms-clear { + display: none; + } + + ul.devui-list-unstyled { + margin: 0; + overflow-y: auto; + padding: 0; + } + + .devui-dropdown-bg { + background: $devui-list-item-hover-bg; + } + + .devui-popup-tips { + color: $devui-text-weak; + padding: 4px 12px; + } + + .devui-form-control { + outline: none; + padding-right: 24px; + } +} + +.devui-select-open { + .devui-select-chevron-icon { + transform: rotate(180deg); + + svg path { + fill: $devui-text-weak; + } + } +} + +.devui-form-control-feedback { + .devui-select-chevron-icon { + display: inline-flex; + vertical-align: middle; + transition: transform $devui-animation-duration-slow $devui-animation-ease-in-out-smooth; + } +} + +.devui-has-feedback > .devui-form-control-feedback { + line-height: 26px; +} + +.devui-dropdown-bg.devui-dropdown-bg { + background-color: inherit; +} +// 下拉部分 +.devui-editable-select { + .devui-dropdown-menu { + width: 100%; + display: block; + } + + .devui-dropdown-item { + cursor: pointer; + display: block; + width: 100%; + padding: 8px 12px; + clear: both; + border: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + line-height: 14px; + } + + .devui-dropdown-menu { + .devui-dropdown-item:not(.disabled) { + &.selected { + color: $devui-list-item-active-text; + background-color: $devui-list-item-active-bg; + } + } + } + + .devui-no-result-template, + .devui-is-searching-template { + display: block; + width: 100%; + padding: 8px 12px; + clear: both; + border: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: not-allowed; + background-color: $devui-disabled-bg; + color: $devui-disabled-text; + line-height: 14px; + + &:hover, + &:active, + &:hover:active { + background-color: $devui-unavailable; + } + } + // 选项disabled + .devui-dropdown-item.disabled, + .devui-dropdown-item.disabled:hover { + cursor: not-allowed; + color: $devui-disabled-text; + } + + ul.devui-list-unstyled { + margin: 0; + overflow-y: auto; + padding: 0; + } + + .devui-dropdown-bg { + background: $devui-list-item-hover-bg; + } + + .devui-popup-tips { + color: $devui-text-weak; + padding: 4px 12px; + } +} diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.tsx b/packages/devui-vue/devui/editable-select/src/editable-select.tsx new file mode 100644 index 0000000000000000000000000000000000000000..671e6eb9d8f50f288a301937926bc30d9728323b --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/editable-select.tsx @@ -0,0 +1,170 @@ +import { defineComponent, ref, renderSlot, computed, Transition } from "vue" +import { + OptionItem, + editableSelectProps, + EditableSelectProps, +} from "./editable-select-types" +import "./editable-select.scss" +import { Icon } from "../../icon" +import ClickOutside from "../../shared/devui-directive/clickoutside" +import { className } from "./utils" +import { debounce } from "lodash" +export default defineComponent({ + name: "DEditableSelect", + directives: { ClickOutside }, + props: editableSelectProps, + emits: ["update:modelValue"], + setup(props: EditableSelectProps, ctx) { + const inputCls = className( + "devui-form-control devui-dropdown-origin devui-dropdown-origin-open", + { + disabled: props.disabled, + } + ) + + const getLiCls = (item) => { + const { disabledKey } = props + return className("devui-dropdown-item", { + disabled: disabledKey ? !!item[disabledKey] : false, + }) + } + + const visible = ref(false) + const inputValue = ref("") + const query = ref(props.modelValue) + + const wait = computed(() => (props.remote ? 300 : 0)) + + const emptyText = computed(() => { + const options = filteredOptions.value + if (!props.remote && inputValue.value && options.length === 0) { + return "没有相关记录" + } + if (options.length === 0) { + return "没有数据" + } + return null + }) + const normalizeOptions = computed(() => { + let options: OptionItem + const { disabledKey } = props + disabledKey ? disabledKey : "disabled" + return props.options.map((item) => { + if (typeof item !== "object") { + options = { + name: item, + } + return options + } + return item + }) + }) + + const filteredOptions = computed(() => { + const isValidOption = (o: OptionItem): boolean => { + const query = inputValue.value + const containsQueryString = query ? o.name.includes(query) : true + return containsQueryString + } + return normalizeOptions.value + .map((item) => { + if (props.remote || isValidOption(item)) { + return item + } + return null + }) + .filter((item) => item !== null) + }) + + const handleClose = () => { + visible.value = false + } + const toggleMenu = () => { + if (!props.disabled) { + visible.value = !visible.value + } + } + const onInputChange = () => { + if (props.filterMethod) { + props.filterMethod(inputValue.value) + } else if (props.remote) { + props.remoteMethod(inputValue.value) + } + } + + const debouncedOnInputChange = debounce(onInputChange, wait.value) + + const handleInput = (event) => { + const value = event.target.value + inputValue.value = value + query.value = value + if (props.remote) { + debouncedOnInputChange() + } else { + onInputChange() + } + } + const selectOptionClick = (e, item) => { + const { disabledKey } = props + if (disabledKey && item[disabledKey]) { + e.stopPropagation() + } else { + query.value = item.name + ctx.emit("update:modelValue", item.name) + } + } + return () => { + return ( + <div + class="devui-form-group devui-has-feedback devui-select-open" + v-click-outside={handleClose} + onClick={toggleMenu} + > + <input + class={inputCls} + type="text" + onInput={handleInput} + value={query.value} + /> + <span class="devui-form-control-feedback"> + <span class="devui-select-chevron-icon"> + <Icon name="select-arrow" /> + </span> + </span> + <div class="devui-editable-select"> + <Transition name="fade"> + <div class="devui-dropdown-menu" v-show={visible.value}> + <ul + class="devui-list-unstyled scroll-height" + style={{ + maxHeight: props.maxHeight + "px", + }} + > + {filteredOptions.value.map((item) => { + return ( + <li + class={getLiCls(item)} + onClick={($evnet) => selectOptionClick($evnet, item)} + key={item.name} + > + {ctx.slots.default + ? renderSlot(ctx.slots, "default", { item }) + : item.name} + </li> + ) + })} + <li + class="devui-no-result-template" + v-show={filteredOptions.value.length === 0} + > + <div class="devui-no-data-tip">{emptyText.value}</div> + </li> + </ul> + </div> + </Transition> + </div> + </div> + ) + } + }, +}) diff --git a/packages/devui-vue/devui/editable-select/src/utils/index.ts b/packages/devui-vue/devui/editable-select/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..91a72c870fca41d1e554c765ddd5e1613c077eb8 --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/utils/index.ts @@ -0,0 +1,31 @@ +import { VNode } from 'vue'; + +/** + * 动态获取class字符串 + * @param classStr 是一个字符串,固定的class名 + * @param classOpt 是一个对象,key表示class名,value为布尔值,true则添加,否则不添加 + * @returns 最终的class字符串 + */ +export function className( + classStr: string, + classOpt?: { [key: string]: boolean; } +): string { + let classname = classStr; + if (typeof classOpt === 'object') { + Object.keys(classOpt).forEach((key) => { + classOpt[key] && (classname += ` ${key}`); + }); + } + + return classname; +} +/** + * + * @param condition 渲染条件 + * @param node1 待渲染的组件 + * @param node2 + * @returns 最终被渲染的组件 + */ +export function renderCondition(condition: unknown, node1: VNode, node2?: VNode): VNode { + return !!condition ? node1 : node2; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/form/index.ts b/packages/devui-vue/devui/form/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba7b235ffa70a54c5fd22ef3acc49c3e1763ad64 --- /dev/null +++ b/packages/devui-vue/devui/form/index.ts @@ -0,0 +1,43 @@ +import type { App } from 'vue' +import Form from './src/form' +import FormLabel from './src/form-label/form-label'; +import FormItem from './src/form-item/form-item'; +import FormControl from './src/form-control/form-control'; +import FormOperation from './src/form-operation/form-operation'; +import dValidateRules from './src/directive/d-validate-rules'; + +Form.install = function(app: App) { + app.component(Form.name, Form); + app.directive('d-validate-rules', dValidateRules); +} + +FormLabel.install = function(app: App) { + app.component(FormLabel.name, FormLabel) +} + +FormItem.install = function(app: App) { + app.component(FormItem.name, FormItem) +} + +FormControl.install = function(app: App) { + app.component(FormControl.name, FormControl) +} + +FormOperation.install = function(app: App) { + app.component(FormOperation.name, FormOperation) +} + +export { Form, FormLabel, FormItem, FormControl, FormOperation } + +export default { + title: 'Form 表单', + category: '数据录入', + status: '70%', + install(app: App): void { + app.use(Form as any); + app.use(FormLabel as any); + app.use(FormItem as any); + app.use(FormControl as any); + app.use(FormOperation as any); + } +} diff --git a/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts b/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts new file mode 100644 index 0000000000000000000000000000000000000000..658bd0c344c962f1f9d821fe2fbbc423e8d6ec1a --- /dev/null +++ b/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts @@ -0,0 +1,366 @@ +import AsyncValidator, { RuleItem } from 'async-validator'; +import { VNode, DirectiveBinding } from 'vue'; +import { debounce } from 'lodash-es'; +import { EventBus, isObject, hasKey } from '../util'; +import './style.scss'; + +interface ValidateFnParam { + validator: AsyncValidator + modelValue: Record<string, unknown> + el: HTMLElement + tipEl: HTMLElement + isFormTag: boolean + message: string + messageShowType: MessageShowType +} + +interface CustomValidatorRuleObject { + message: string + validator: (rule, value) => boolean + asyncValidator: (rule, value) => Promise<boolean> +} + +interface DirectiveValidateRuleOptions { + updateOn?: UpdateOn + errorStrategy?: ErrorStrategy + asyncDebounceTime?: number +} + +interface DirectiveBindingValue { + rules: Partial<DirectiveCustomRuleItem>[] + options: DirectiveValidateRuleOptions + messageShowType: MessageShowType + errorStrategy: ErrorStrategy +} + +interface DirectiveCustomRuleItem extends RuleItem { + validators: CustomValidatorRuleObject[] + asyncValidators: CustomValidatorRuleObject[] +} + +type MessageShowType = 'popover' | 'text' | 'none' | 'toast'; +type UpdateOn = 'input' | 'focus' | 'change' | 'blur' | 'submit'; +type ErrorStrategy = 'dirty' | 'pristine'; + +enum ErrorStrategyEnum { + dirty = 'dirty', + pristine = 'pristine' +} + +enum UpdateOnEnum { + input = 'input', + focus = 'focus', + change = 'change', + blur = 'blur', + submit = 'submit', +} + +enum MessageShowTypeEnum { + popover = 'popover', + text = 'text', + none = 'none', + toast = 'toast' +} + +// 获取async-validator可用的规则名 +function getAvaliableRuleObj(ruleName: string, value: any) { + if(!ruleName) { + console.error("[v-d-validate] validator's key is invalid"); + return null; + } + switch(ruleName) { + case 'maxlength': + return { + type: 'string', + max: value, + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(val.length > value) { + reject('最大长度为' + value); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'minlength': + return { + type: 'string', + min: value, + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(val.length < value) { + reject('最小长度为' + value); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'min': + return { + type: 'number', + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(val < value) { + reject('最小值为' + value); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'max': + return { + type: 'number', + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(val > value) { + reject('最大值为' + value); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'required': + return { + reqiured: true, + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(!val) { + reject('必填项'); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'requiredTrue': + return { + asyncValidator: (rule, val) => { + return new Promise((resolve, reject) => { + if(!val) { + reject('必须为true值'); + }else { + resolve('校验通过'); + } + }) + } + }; + case 'email': + return { + type: 'email', + message: '邮箱格式不正确' + }; + case 'pattern': + return { + type: 'regexp', + pattern: value, + message: '只能包含数字与大小写字符', + validator: (rule, val) => value.test(val), + }; + case 'whitespace': + return { + message: '输入不能全部为空格或空字符', + validator: (rule, val) => !!val.trim() + }; + default: + return { + [ruleName]: value, + }; + } +} + +function getKeyValueOfObjectList(obj): {key: string; value: any;}[] { + const kvArr = []; + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + kvArr.push({ + key, + value: obj[key] + }) + } + } + return kvArr; +} + +function handleErrorStrategy(el: HTMLElement): void { + const classList: Array<string> = [...el.classList]; + classList.push('d-validate-rules-error-pristine'); + el.setAttribute('class', classList.join(' ')); +} + +function handleErrorStrategyPass(el: HTMLElement): void { + const classList: Array<string> = [...el.classList]; + const index = classList.indexOf('d-validate-rules-error-pristine'); + index !== -1 && classList.splice(index, 1); + el.setAttribute('class', classList.join(' ')); +} + +function handleValidateError({el, tipEl, message, isFormTag, messageShowType}: Partial<ValidateFnParam>): void { + // 如果该指令用在form标签上,这里做特殊处理 + if(isFormTag && messageShowType === MessageShowTypeEnum.toast) { + // todo:待替换为toast + alert(message); + return; + } + + tipEl.innerText = '' + message; + tipEl.style.display = 'inline-flex'; + tipEl.setAttribute('class', 'd-validate-tip'); + handleErrorStrategy(el); +} + +function handleValidatePass(el: HTMLElement, tipEl: HTMLElement): void { + tipEl.style.display = 'none'; + handleErrorStrategyPass(el); +} + +// 获取表单name +function getFormName(binding: DirectiveBinding): string { + const _refs = binding.instance.$refs; + const key = Object.keys(_refs)[0]; + return _refs[key]['name']; +} + +// 校验处理函数 +function validateFn({validator, modelValue, el, tipEl, isFormTag, messageShowType}: Partial<ValidateFnParam>) { + validator.validate({modelName: modelValue}).then(() => { + handleValidatePass(el, tipEl); + }).catch((err) => { + const { errors } = err; + if(!errors || errors.length === 0) return; + let msg = ''; + + // todo: 待支持国际化 + if(typeof errors[0].message === 'object') { + msg = errors[0].message.default; + }else { + msg = errors[0].message; + } + + handleValidateError({el, tipEl, message: msg, isFormTag, messageShowType}); + }) +} + +export default { + mounted(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void { + const isFormTag = el.tagName === 'FORM'; + + const hasOptions = isObject(binding.value) && hasKey(binding.value, 'options'); + + // 获取指令绑定的值 + const { + rules: bindingRules, + options = {}, + messageShowType = MessageShowTypeEnum.popover + }: DirectiveBindingValue = binding.value; + let { errorStrategy }: DirectiveBindingValue = binding.value; + + // errorStrategy可配置在options对象中 + const { + updateOn = UpdateOnEnum.change, + errorStrategy: ErrorStrategy = ErrorStrategyEnum.dirty, + asyncDebounceTime = 300 + }: DirectiveValidateRuleOptions = options; + + if(!errorStrategy) { + errorStrategy = ErrorStrategy; + } + + // 判断是否有options,有就取binding.value对象中的rules对象,再判断有没有rules对象,没有就取binding.value + let customRule: Partial<DirectiveCustomRuleItem> | DirectiveBindingValue = {}; + if(hasOptions) { + customRule = bindingRules ?? binding.value + }else { + customRule = binding.value as DirectiveBindingValue + } + + const isCustomValidator = customRule && isObject(customRule) && (hasKey(customRule, 'validators') || hasKey(customRule, 'asyncValidators')); + + const rules = Array.isArray(customRule) ? customRule : [customRule]; + const tipEl = document.createElement('span'); + + // messageShowType控制是否显示文字提示 + if(messageShowType !== MessageShowTypeEnum.none) { + el.parentNode.append(tipEl); + } + + const descriptor = { + modelName: [] + }; + + rules.forEach((rule) => { + const kvObjList = !Array.isArray(rule) && getKeyValueOfObjectList(rule); + let ruleObj: Partial<CustomValidatorRuleObject> = {}; + let avaliableRuleObj = {}; + kvObjList.forEach(item => { + avaliableRuleObj = getAvaliableRuleObj(item.key, item.value); + ruleObj = {...ruleObj, ...avaliableRuleObj}; + }); + descriptor.modelName.push(ruleObj); + }); + + // 使用自定义的验证器 + if(isCustomValidator) { + // descriptor.modelName = []; + const {validators, asyncValidators} = customRule as DirectiveCustomRuleItem; + + // 校验器 + validators && validators.forEach(item => { + const ruleObj: Partial<CustomValidatorRuleObject> = { + message: item?.message || '', + validator: (rule, value) => item.validator(rule, value), + } + descriptor.modelName.push(ruleObj); + }); + + // 异步校验器 + asyncValidators && asyncValidators.forEach(item => { + const ruleObj: Partial<CustomValidatorRuleObject> = { + message: item?.message || '', + asyncValidator: (rule, value) => { + return new Promise(debounce((resolve, reject) => { + const res = item.asyncValidator(rule, value); + if(res) { + resolve(''); + }else { + reject(rule.message); + } + }, asyncDebounceTime)) + }, + } + descriptor.modelName.push(ruleObj); + }); + } + + // 校验器对象 + const validator = new AsyncValidator(descriptor); + + const htmlEventValidateHandler = (e) => { + const modelValue = e.target.value; + validateFn({validator, modelValue, el, tipEl, isFormTag: false, messageShowType}); + } + + // 监听事件验证 + vnode.children[0].el.addEventListener(updateOn, htmlEventValidateHandler); + + // 设置errorStrategy + if(errorStrategy === ErrorStrategyEnum.pristine) { + handleErrorStrategy(el); + // pristine为初始化验证,初始化时需改变下原始值才能出发验证 + vnode.children[0].props.value = '' + vnode.children[0].props.value; + } + + const formName = getFormName(binding); + // 处理表单提交验证 + formName && EventBus.on(`formSubmit:${formName}`, () => { + const modelValue = isFormTag ? '' : vnode.children[0].el.value; + + // 进行提交验证 + validateFn({validator, modelValue, el, tipEl, isFormTag, messageShowType}); + }); + + } +} diff --git a/packages/devui-vue/devui/form/src/directive/style.scss b/packages/devui-vue/devui/form/src/directive/style.scss new file mode 100644 index 0000000000000000000000000000000000000000..56345b9d66fca17a2d3e17934fd1bf5023e44937 --- /dev/null +++ b/packages/devui-vue/devui/form/src/directive/style.scss @@ -0,0 +1,24 @@ + +.d-validate-rules-error-pristine { + // background-color: #ffeeed; + input { + background-color: #ffeeed; + border: 1px solid #f66f6a; + + &:focus { + border: 1px solid #f66f6a !important; + } + + &:hover { + border: 1px solid #f66f6a !important; + } + } +} + +.d-validate-tip { + display: flex; + justify-content: center; + align-items: center; + font-size: 12px; + color: #f66f6a; +} diff --git a/packages/devui-vue/devui/form/src/form-control/form-control.scss b/packages/devui-vue/devui/form/src/form-control/form-control.scss new file mode 100644 index 0000000000000000000000000000000000000000..993bae7c6654f75d29a904b6da6a99ffa5a4eaac --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-control/form-control.scss @@ -0,0 +1,101 @@ +.form-control { + position: relative; + + .star { + color: red; + } + + .devui-form-control-container { + position: relative; + + .feedback-status { + position: absolute; + top: 50%; + right: 0; + z-index: 1; + width: 32px; + height: 16px; + margin-top: -7px; + line-height: 16px; + text-align: center; + visibility: visible; + pointer-events: none; + } + + .devui-radio { + &:not(:last-child) { + margin-bottom: 20px; + } + } + } + + .devui-form-control-container-horizontal { + display: flex; + + .devui-radio { + &:not(:last-child) { + margin-bottom: 0; + margin-right: 20px; + } + } + + .devui-checkbox-group > div:first-child { + display: flex; + align-items: center; + } + + .devui-checkbox-column-margin { + &:not(:last-child) { + margin-right: 20px; + } + } + + input, + .devui-tags-host { + width: 200px; + } + + .d-validate-tip { + margin: 0 10px; + } + } + + .has-feedback { + display: flex; + align-items: center; + + input { + padding-right: 28px; + } + } + + .feedback-error { + border: 1px solid #f66f6a; + border-radius: 2px; + + input { + background-color: #ffeeed; + border-color: transparent; + + &:hover { + border-color: transparent !important; + } + + &:focus { + border-color: transparent !important; + } + } + + .devui-select-arrow { + right: 24px !important; + } + } + + .devui-form-control-extra-info { + font-size: 12px; + color: #8a8e99; + min-height: 20px; + line-height: 1.5; + text-align: justify; + } +} diff --git a/packages/devui-vue/devui/form/src/form-control/form-control.tsx b/packages/devui-vue/devui/form/src/form-control/form-control.tsx new file mode 100644 index 0000000000000000000000000000000000000000..181509190d2fbe207180c93e93584449475898a0 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-control/form-control.tsx @@ -0,0 +1,47 @@ +import { defineComponent, inject, ref, computed, reactive } from 'vue'; +import {IForm, formControlProps, formInjectionKey} from '../form-types'; +import Icon from '../../../icon/src/icon'; +import './form-control.scss'; + +export default defineComponent({ + name: 'DFormControl', + props: formControlProps, + setup(props, ctx) { + const formControl = ref(); + const dForm = reactive(inject(formInjectionKey, {} as IForm)); + const labelData = reactive(dForm.labelData); + const isHorizontal = labelData.layout === 'horizontal'; + + const iconData = computed(() => { + switch(props.feedbackStatus) { + case 'pending': + return {name: 'priority', color: '#e9edfa'}; + case 'success': + return {name: 'right-o', color: 'rgb(61, 204, 166)'}; + case 'error': + return {name: 'error-o', color: 'rgb(249, 95, 91)'}; + default: + return {name: '', color: ''}; + } + }) + + return () => { + const { + feedbackStatus, + extraInfo, + } = props; + return <div class="form-control" ref={formControl}> + <div class={`devui-form-control-container${isHorizontal ? ' devui-form-control-container-horizontal' : ''}${feedbackStatus ? ' has-feedback' : ''}${feedbackStatus === 'error' ? ' feedback-error' : ''}`}> + {ctx.slots.default?.()} + { + (feedbackStatus || ctx.slots.suffixTemplate?.()) && + <span class="feedback-status"> + {ctx.slots.suffixTemplate?.() ? ctx.slots.suffixTemplate?.() : <Icon name={iconData.value.name} color={iconData.value.color}></Icon>} + </span> + } + </div> + {extraInfo && <div class="devui-form-control-extra-info">{extraInfo}</div>} + </div> + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/form/src/form-item/form-item.scss b/packages/devui-vue/devui/form/src/form-item/form-item.scss new file mode 100644 index 0000000000000000000000000000000000000000..41c1a739690d7b84acb7107524392f956b7c97d8 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-item/form-item.scss @@ -0,0 +1,36 @@ +.form-item { + display: flex; + // align-items: center; + margin-bottom: 20px; +} + +.form-item-vertical { + flex-direction: column; +} + +.form-item-columns { + flex-direction: column; + display: inline-block !important; +} +// .u-1-3 { +// width: 33.3%; +// } +.column-item { + margin-bottom: 20px; +} + +.column-item .form-control { + width: 60% !important; +} + +.d-validate-tip { + display: flex; + justify-content: center; + align-items: center; + font-size: 12px; + color: #f66f6a; +} + +.d-validate-tip-horizontal { + margin-left: 10px; +} diff --git a/packages/devui-vue/devui/form/src/form-item/form-item.tsx b/packages/devui-vue/devui/form/src/form-item/form-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..28fddf78acc25c94574c9240bbbac972f07e2e91 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-item/form-item.tsx @@ -0,0 +1,106 @@ +import { defineComponent, reactive, inject, onMounted, onBeforeUnmount, provide, ref} from 'vue'; +import AsyncValidator, { Rules } from 'async-validator'; +import mitt from 'mitt'; +import { dFormEvents, dFormItemEvents, IForm, formItemProps, formInjectionKey, formItemInjectionKey } from '../form-types'; +import './form-item.scss'; + + +export default defineComponent({ + name: 'DFormItem', + props: formItemProps, + setup(props, ctx) { + const formItemMitt = mitt(); + const dForm = reactive(inject(formInjectionKey, {} as IForm)); + const formData = reactive(dForm.formData); + const columnsClass = ref(dForm.columnsClass); + const initFormItemData = formData[props.prop]; + const labelData = reactive(dForm.labelData); + const rules = reactive(dForm.rules); + + const resetField = () => { + formData[props.prop] = initFormItemData; + } + + const formItem = reactive({ + dHasFeedback: props.dHasFeedback, + prop: props.prop, + formItemMitt, + resetField + }) + provide(formItemInjectionKey, formItem); + + const isHorizontal = labelData.layout === 'horizontal'; + const isVertical = labelData.layout === 'vertical'; + const isColumns = labelData.layout === 'columns'; + + const showMessage = ref(false); + const tipMessage = ref(''); + + const validate = (trigger: string) => { + // console.log('trigger', trigger); + + const ruleKey = props.prop; + const ruleItem = rules[ruleKey]; + const descriptor: Rules = {}; + descriptor[ruleKey] = ruleItem; + + const validator = new AsyncValidator(descriptor); + + validator.validate({[ruleKey]: formData[ruleKey]}).then(() => { + showMessage.value = false; + tipMessage.value = ''; + }).catch(({ errors }) => { + // console.log('validator errors', errors); + showMessage.value = true; + tipMessage.value = errors[0].message; + }); + } + const validateEvents = []; + + const addValidateEvents = () => { + if(rules && rules[props.prop]) { + const ruleItem = rules[props.prop]; + let eventName = ruleItem['trigger']; + + if(Array.isArray(ruleItem)) { + ruleItem.forEach((item) => { + eventName = item['trigger']; + const cb = () => validate(eventName); + validateEvents.push({eventName: cb}); + formItem.formItemMitt.on(dFormItemEvents[eventName], cb); + }); + }else { + const cb = () => validate(eventName); + validateEvents.push({eventName: cb}); + ruleItem && formItem.formItemMitt.on(dFormItemEvents[eventName], cb); + } + } + } + + const removeValidateEvents = () => { + if(rules && rules[props.prop] && validateEvents.length > 0) { + validateEvents.forEach(item => { + formItem.formItemMitt.off(item.eventName, item.cb); + }); + } + } + + onMounted(() => { + dForm.formMitt.emit(dFormEvents.addField, formItem); + addValidateEvents(); + }); + + onBeforeUnmount(() => { + dForm.formMitt.emit(dFormEvents.removeField, formItem); + removeValidateEvents(); + }); + return () => { + return ( + <div class={`form-item${isHorizontal ? '' : (isVertical ? ' form-item-vertical' : ' form-item-columns')}${isColumns ? ' column-item ' + columnsClass.value : ''}`}> + {ctx.slots.default?.()} + <div class={`d-validate-tip${isHorizontal ? ' d-validate-tip-horizontal' : ''}`}>{showMessage.value && tipMessage.value}</div> + </div> + ) + } + }, +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/form/src/form-label/form-label.scss b/packages/devui-vue/devui/form/src/form-label/form-label.scss new file mode 100644 index 0000000000000000000000000000000000000000..d761f33beb49af6eb153d323f614f5271770ad34 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-label/form-label.scss @@ -0,0 +1,54 @@ +.form-label { + // flex: 1 1 auto; + -moz-box-flex: 1; + text-align: left; + padding-bottom: 8px; + justify-content: flex-start; + align-self: flex-start; + margin-right: 16px; + + .devui-required { + display: inline-flex; + align-items: center; + + &::before { + content: '*'; + color: red; + display: inline-block; + margin-right: 8px; + margin-left: -12px; + } + } +} + +.form-label_sm { + width: 80px; + min-width: 80px; +} + +.form-label_sd { + width: 100px; + min-width: 100px; +} + +.form-label_lg { + width: 150px; + min-width: 150px; +} + +.form-label_center { + text-align: center; +} + +.form-label_end { + text-align: end; +} + +.form-label-help { + border-radius: 50%; + display: inline-flex; + justify-content: center; + align-items: center; + position: relative; + margin-left: 10px; +} diff --git a/packages/devui-vue/devui/form/src/form-label/form-label.tsx b/packages/devui-vue/devui/form/src/form-label/form-label.tsx new file mode 100644 index 0000000000000000000000000000000000000000..51715fdc9a9deed48cc44db5ee9a9d07a9bc77f6 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-label/form-label.tsx @@ -0,0 +1,44 @@ +import { defineComponent, inject, reactive, computed } from 'vue'; +import { IForm, formLabelProps, FormLabelProps, formInjectionKey } from '../form-types'; +import Icon from '../../../icon/src/icon'; +import Popover from '../../../popover/src/popover'; +import './form-label.scss'; + +export default defineComponent({ + name: 'DFormLabel', + props: formLabelProps, + setup(props: FormLabelProps, ctx) { + const dForm = reactive(inject(formInjectionKey, {} as IForm)); + const labelData = reactive(dForm.labelData); + + const isHorizontal = computed(() => labelData.layout === 'horizontal').value; + const isLg = computed(() => labelData.labelSize === 'lg').value; + const isSm = computed(() => labelData.labelSize === 'sm').value; + const isCenter = computed(() => labelData.labelAlign === 'center').value; + const isEnd = computed(() => labelData.labelAlign === 'end').value; + + const wrapperCls = `form-label${isHorizontal ? (isSm ? ' form-label_sm' : (isLg ? ' form-label_lg' : ' form-label_sd')) : ''}${isCenter ? ' form-label_center' : (isEnd ? ' form-label_end' : '')}`; + const className = `${props.required ? ' devui-required' : ''}`; + const style = {display: isHorizontal ? 'inline' : 'inline-block'}; + + return () => { + return <span class={wrapperCls} style={style}> + <span class={className} > + {ctx.slots.default?.()} + { + props.hasHelp && props.helpTips && ( + <Popover content={props.helpTips} showAnimation={false} position={'top'} trigger={'hover'} v-slots={{ + reference: () => ( + <span class="form-label-help"> + <Icon name="helping" color="#252b3a"></Icon> + </span> + ) + }}> + </Popover> + ) + } + </span> + </span> + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/form/src/form-operation/form-operation.scss b/packages/devui-vue/devui/form/src/form-operation/form-operation.scss new file mode 100644 index 0000000000000000000000000000000000000000..3e4154caac02e9483e8f765baac5d4bf9c43f8ad --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-operation/form-operation.scss @@ -0,0 +1,5 @@ +.form-operation { + .star { + color: red; + } +} diff --git a/devui/alert/alert.tsx b/packages/devui-vue/devui/form/src/form-operation/form-operation.tsx similarity index 35% rename from devui/alert/alert.tsx rename to packages/devui-vue/devui/form/src/form-operation/form-operation.tsx index 1f8eb86119f51fcbd4877c2982835780bea79c58..5a589a9a634606e593d22013a6785677f031f320 100644 --- a/devui/alert/alert.tsx +++ b/packages/devui-vue/devui/form/src/form-operation/form-operation.tsx @@ -1,12 +1,16 @@ -import { defineComponent } from 'vue' +import { defineComponent } from 'vue'; +import './form-operation.scss'; export default defineComponent({ - name: 'd-alert', + name: 'DFormOperation', props: { + }, setup(props, ctx) { return () => { - return <div>devui-alert</div> + return <div class="form-operation"> + {ctx.slots.default?.()} + </div> } } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/form/src/form-types.ts b/packages/devui-vue/devui/form/src/form-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..662bfab3009698d01c20e0b42a3146a056eb41fc --- /dev/null +++ b/packages/devui-vue/devui/form/src/form-types.ts @@ -0,0 +1,161 @@ +import { Emitter } from 'mitt' +import type { PropType, ExtractPropTypes, InjectionKey, Ref } from 'vue' + +export const formProps = { + formData: { + type: Object, + default: {} + }, + layout: { + type: String as PropType<'horizontal' | 'vertical' | 'columns'>, + default: 'horizontal', + }, + labelSize: { + type: String as PropType<'sm' | '' | 'lg'>, + default: '', + }, + labelAlign: { + type: String as PropType<'start' | 'center' | 'end'>, + default: 'start', + }, + rules: { + type: Object, + default: {}, + }, + columnsClass: { + type: String as PropType<'u-1-3'>, + default: '', + }, + name: { + type: String, + default: '', + }, +} as const + +export const formItemProps = { + dHasFeedback: { + type: Boolean, + default: false + }, + prop: { + type: String, + default: '' + } +} as const + +export const formLabelProps = { + required: { + type: Boolean, + default: false + }, + hasHelp: { + type: Boolean, + default: false + }, + helpTips: { + type: String, + default: '' + } +} as const + +export const formControlProps = { + feedbackStatus: { + type: String as PropType<'success' | 'error' | 'pending' | ''>, + default: '' + }, + extraInfo: { + type: String, + default: '' + } +} as const + +export const dFormEvents = { + addField: 'd.form.addField', + removeField: 'd.form.removeField', +} as const + +type LabelData = { + layout: string + labelSize: string + labelAlign: string +} + +export const formInjectionKey: InjectionKey<IForm> = Symbol('dForm'); +export const formItemInjectionKey: InjectionKey<IFormItem> = Symbol('dFormItem'); + +export const dFormItemEvents = { + blur: 'd.form.blur', + change: 'd.form.change', + input: 'd.form.input', +} as const + + +export interface IForm { + formData: any + labelData: IFormLabel + formMitt: Emitter<any> + rules: any + columnsClass: string +} + +export interface IFormLabel { + layout: string + labelSize: string + labelAlign: string +} + +export interface IFormItem { + dHasFeedback: boolean + prop: string + formItemMitt: Emitter<any> + resetField(): void +} + +export interface IFormControl { + feedbackStatus: string + extraInfo: string + formItemMitt: Emitter<any> + resetField(): void +} + +export type FormProps = ExtractPropTypes<typeof formProps> +export type FormItemProps = ExtractPropTypes<typeof formItemProps> +export type FormLabelProps = ExtractPropTypes<typeof formLabelProps> +export type FormControlProps = ExtractPropTypes<typeof formControlProps> + + +export interface IValidators { + required: boolean + minlength: number + maxlength: number + min: number + max: number + requiredTrue: boolean + email: boolean + pattern: RegExp + whiteSpace: boolean +} + +const Validators: IValidators = { + required: false, + minlength: 0, + maxlength: 0, + min: 0, + max: 0, + requiredTrue: false, + email: false, + pattern: undefined, + whiteSpace: false +} + +export const dDefaultValidators = { + 'required': Validators.required, // 配置不能为空限制,rule中使用:{ required: true } + 'minlength': Validators.minlength, // 配置最小长度限制,rule中使用:{ minlength: 5 } + 'maxlength': Validators.maxlength, // 配置最大长度限制,rule中使用:{ maxlength: 128 } + 'min': Validators.min, // 配置最小值限制,rule中使用:{ min: 0 } + 'max': Validators.max, // 配置最大值限制,rule中使用:{ max: 100 } + 'requiredTrue': Validators.requiredTrue, // 配置需要为true,rule中使用:{ requiredTrue: true } + 'email': Validators.email, // 配置邮箱校验,rule中使用:{ email: true } + 'pattern': Validators.pattern, // 配置正则校验,rule中使用:{ pattern: RegExp } + 'whitespace': Validators.whiteSpace, // 配置输入不能全为空格限制,rule中使用:{ whitespace: true } +}; diff --git a/packages/devui-vue/devui/form/src/form.scss b/packages/devui-vue/devui/form/src/form.scss new file mode 100644 index 0000000000000000000000000000000000000000..f2170c54cc9fd44cb2b29adc8e2436f7ee5539ef --- /dev/null +++ b/packages/devui-vue/devui/form/src/form.scss @@ -0,0 +1,3 @@ +.d-form { + position: relative; +} diff --git a/packages/devui-vue/devui/form/src/form.tsx b/packages/devui-vue/devui/form/src/form.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e8fbe99dba86e7613b8ee03f4ba2d868a2ec5758 --- /dev/null +++ b/packages/devui-vue/devui/form/src/form.tsx @@ -0,0 +1,67 @@ + +import { defineComponent, provide } from 'vue' +import mitt from 'mitt' +import { formProps, FormProps, IFormItem, dFormEvents, formInjectionKey, IForm } from './form-types' +import { EventBus } from './util' +import './form.scss' + + +export default defineComponent({ + name: 'DForm', + props: formProps, + emits: ['submit'], + setup(props: FormProps, ctx) { + const formMitt = mitt(); + const fields: IFormItem[] = []; + const resetFormFields = () => { + fields.forEach((field: IFormItem) => { + field.resetField(); + }) + } + + formMitt.on(dFormEvents.addField, (field: any) => { + if(field) { + fields.push(field); + } + }) + + formMitt.on(dFormEvents.removeField, (field: any) => { + if(field.prop) { + fields.splice(fields.indexOf(field), 1); + } + }) + + provide(formInjectionKey, { + formData: props.formData, + formMitt, + labelData: { + layout: props.layout, + labelSize: props.labelSize, + labelAlign: props.labelAlign, + }, + rules: props.rules, + columnsClass: props.columnsClass + }); + + const onSubmit = (e) => { + e.preventDefault(); + ctx.emit('submit', e); + EventBus.emit(`formSubmit:${props.name}`); + } + + return { + fields, + formMitt, + onSubmit, + resetFormFields + } + }, + render() { + const {onSubmit} = this; + return ( + <form onSubmit={onSubmit} class="d-form"> + {this.$slots.default?.()} + </form> + ); + } +}) diff --git a/packages/devui-vue/devui/form/src/util/event-bus.ts b/packages/devui-vue/devui/form/src/util/event-bus.ts new file mode 100644 index 0000000000000000000000000000000000000000..3411bb73f8e37cfbd90a7f874fce1a24f652ae37 --- /dev/null +++ b/packages/devui-vue/devui/form/src/util/event-bus.ts @@ -0,0 +1,3 @@ +import mitt from 'mitt'; + +export default mitt(); \ No newline at end of file diff --git a/packages/devui-vue/devui/form/src/util/index.ts b/packages/devui-vue/devui/form/src/util/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1fac48d3f2b4efc5ba7ed8b34ba04ddb404f1a6 --- /dev/null +++ b/packages/devui-vue/devui/form/src/util/index.ts @@ -0,0 +1,12 @@ + +import eventBus from './event-bus' +export const EventBus = eventBus; + +export function isObject(obj: any): boolean { + return Object.prototype.toString.call(obj).slice(8, -1) === 'Object'; +} + +export function hasKey(obj: any, key: string | number | symbol): boolean { + if (!isObject(obj)) return false; + return Object.prototype.hasOwnProperty.call(obj, key); +} diff --git a/packages/devui-vue/devui/fullscreen/__tests__/fullscreen.spec.ts b/packages/devui-vue/devui/fullscreen/__tests__/fullscreen.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e8ed761ea3cbaa82933dbe0bd94475d3edd4056f --- /dev/null +++ b/packages/devui-vue/devui/fullscreen/__tests__/fullscreen.spec.ts @@ -0,0 +1,53 @@ +import { mount, VueWrapper } from '@vue/test-utils' +import { ref, nextTick } from 'vue' + +describe('fullscreen', () => { + let wrapper: VueWrapper<any> + + beforeEach(() => { + wrapper = mount({ + template: ` + <d-fullscreen :mode='"normal"' @fullscreenLaunch='fullscreenLaunch'> + <div fullscreen-target> + <button test fullscreen-launch>{{btnContent}}</button> + </div> + </d-fullscreen> + `, + setup() { + const btnContent = ref('FullScreen') + const fullscreenLaunch = (val) => { + if (val) { + btnContent.value = 'Exit' + } else { + btnContent.value = 'FullScreen' + } + } + return { + btnContent, + fullscreenLaunch + } + } + }) + }) + + // 样式判断 + it('judge html class correctly', async () => { + + // 初始样式 + expect(document.getElementsByTagName('html')[0].classList.value).toEqual('') + // 点击之后,增加class + await wrapper.find('[test]').trigger('click') + await nextTick() + expect(document.getElementsByTagName('html')[0].classList.value).not.toContain('devui-fullscreen') + + // 再次点击,删除class + await wrapper.find('[test]').trigger('click') + await nextTick() + expect(document.getElementsByTagName('html')[0].classList.value).toEqual('') + }) + + // 判断属性 + it('attr', () => { + expect(wrapper.attributes('mode')).toBe('normal') + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/fullscreen/index.ts b/packages/devui-vue/devui/fullscreen/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b73d21fe20c4b388fc96d47df1e85c086da1ef88 --- /dev/null +++ b/packages/devui-vue/devui/fullscreen/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Fullscreen from './src/fullscreen' + +Fullscreen.install = function(app: App): void { + app.component(Fullscreen.name, Fullscreen) +} + +export { Fullscreen } + +export default { + title: 'Fullscreen 全屏', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(Fullscreen as any) + } +} diff --git a/packages/devui-vue/devui/fullscreen/src/fullscreen-types.ts b/packages/devui-vue/devui/fullscreen/src/fullscreen-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..5428abb3889a27f5a9d3d0899f7aa6d0993c579b --- /dev/null +++ b/packages/devui-vue/devui/fullscreen/src/fullscreen-types.ts @@ -0,0 +1,19 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +type ModeType = PropType<'immersive' | 'normal'> +export const fullscreenProps = { + fullscreenLaunch: { + type: Function, + default: undefined + }, + mode: { + type: String as ModeType, + default: 'immersive' + }, + zIndex: { + type: Number, + default: 10 + } +} as const + +export type FullscreenProps = ExtractPropTypes<typeof fullscreenProps> diff --git a/packages/devui-vue/devui/fullscreen/src/fullscreen.scss b/packages/devui-vue/devui/fullscreen/src/fullscreen.scss new file mode 100644 index 0000000000000000000000000000000000000000..38689d367ee1c53be852d47acee4dbbbfec05bf9 --- /dev/null +++ b/packages/devui-vue/devui/fullscreen/src/fullscreen.scss @@ -0,0 +1,20 @@ +@import '../../style/theme/color'; + +.fullscreen { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10; + overflow: auto; + background-color: $devui-base-bg; +} + +.devui-fullscreen { + overflow: hidden; +} + +:not(:root):fullscreen::backdrop { + background: #ffffff; +} diff --git a/packages/devui-vue/devui/fullscreen/src/fullscreen.tsx b/packages/devui-vue/devui/fullscreen/src/fullscreen.tsx new file mode 100644 index 0000000000000000000000000000000000000000..99495bf5d60d31ce005dd725264aedb56d28a756 --- /dev/null +++ b/packages/devui-vue/devui/fullscreen/src/fullscreen.tsx @@ -0,0 +1,150 @@ +import './fullscreen.scss' + +import { + defineComponent, + useSlots, + renderSlot, + onMounted, + ref +} from 'vue' +import { fullscreenProps, FullscreenProps } from './fullscreen-types' + +export default defineComponent({ + name: 'DFullscreen', + props: fullscreenProps, + emits: ['fullscreenLaunch'], + setup(props: FullscreenProps, ctx) { + + let currentTarget = ref(null) + const isFullscreen = ref(false) + const slotElement = ref(null) + + const onFullScreenChange = () => { + if (currentTarget.value) { + const targetElement: HTMLElement = currentTarget + if (document.fullscreenElement) { // 进入全屏 + addFullScreenStyle() + launchNormalFullscreen(targetElement) + } else { // 退出全屏 + removeFullScreenStyle() + currentTarget = null + exitNormalFullscreen(targetElement) + } + // F11退出全屏时,需要将全屏状态传出去 + isFullscreen.value = !!(document.fullscreenElement) + ctx.emit('fullscreenLaunch', isFullscreen.value) + } + } + + // 页面全屏 + const launchNormalFullscreen = (targetElement: HTMLElement) => { + targetElement.classList.add('fullscreen') + if (props.zIndex) { + targetElement.setAttribute('style', `z-index: ${props.zIndex}`) + } + } + + // 退出正常全屏 + const exitNormalFullscreen = (targetElement: HTMLElement) => { + targetElement.classList.remove('fullscreen') + targetElement.style.zIndex = null + } + + // 事件监听 + const handleFullscreen = async () => { + // const targetElement = document.querySelector('[fullscreen-target]') + const targetElement = slotElement.value.querySelector('[fullscreen-target]') + let isFull = false + // 判断模式 + if (props.mode === 'normal') { // 浏览器全屏 + const fullscreen = targetElement.classList.contains('fullscreen') + if (!fullscreen) { // 进入全屏 + addFullScreenStyle() + launchNormalFullscreen(targetElement) + isFull = true + } else { // 退出全屏 + removeFullScreenStyle() + exitNormalFullscreen(targetElement) + isFull = false + } + } else { // 沉浸式全屏 + currentTarget = targetElement + if (document.fullscreenElement || document.msFullscreenElement || document.webkitFullscreenElement) { + isFull = await exitImmersiveFullScreen(document) + } else { + isFull = await launchImmersiveFullScreen(currentTarget) + } + } + isFullscreen.value = isFull + ctx.emit('fullscreenLaunch', isFullscreen.value) + } + + const addFullScreenStyle = (): void => { + document.getElementsByTagName('html')[0].classList.add('devui-fullscreen') + } + + const removeFullScreenStyle = (): void => { + document.getElementsByTagName('html')[0].classList.remove('devui-fullscreen') + } + + const exitImmersiveFullScreen = async (doc: any) => { + let fullscreenExit = null + if (doc.exitFullscreen) { + fullscreenExit = doc.exitFullscreen() + } else if (doc.mozCancelFullScreen) { + fullscreenExit = doc.mozCancelFullScreen() + } else if (doc.webkitCancelFullScreen) { + fullscreenExit = Promise.resolve(doc.webkitCancelFullScreen()); + } else if (doc.msExitFullscreen) { + fullscreenExit = Promise.resolve(doc.msExitFullscreen()); + } + return await fullscreenExit.then(() => !!document.fullscreenElement) + } + + const launchImmersiveFullScreen = async (docElement: any) => { + let fullscreenLaunch = null + if (docElement.requestFullscreen) { + fullscreenLaunch = docElement.requestFullscreen() + } else if (docElement.mozRequestFullScreen) { + fullscreenLaunch = docElement.mozRequestFullScreen() + } else if (docElement.webkitRequestFullScreen) { + fullscreenLaunch = Promise.resolve(docElement.webkitRequestFullScreen()) + } else if (docElement.msRequestFullscreen) { + fullscreenLaunch = Promise.resolve(docElement.msRequestFullscreen()) + } + return await fullscreenLaunch.then(() => !!document.fullscreenElement) + } + + const handleKeyDown = (event) => { + if (event.keyCode === 27) { // 按ESC键退出全屏 + if (isFullscreen.value) { + const targetElement = slotElement.value.querySelector('[fullscreen-target]') + if (props.mode === 'normal') { + removeFullScreenStyle() + exitNormalFullscreen(targetElement) + } else { + if (document.fullscreenElement) { exitImmersiveFullScreen(document) } + } + isFullscreen.value = false + ctx.emit('fullscreenLaunch', isFullscreen.value) + } + } + } + + onMounted(() => { + const btnLaunch = slotElement.value.querySelector('[fullscreen-launch]') + if (btnLaunch) { btnLaunch.addEventListener('click', handleFullscreen) } + document.addEventListener('fullscreenchange', onFullScreenChange) + document.addEventListener('MSFullscreenChange', onFullScreenChange) + document.addEventListener('webkitfullscreenchange', onFullScreenChange) + document.addEventListener('keydown', handleKeyDown) + }) + return () => { + const defaultSlot = renderSlot(useSlots(), 'default') + // if (defaultSlot.children.length === 0) throw new Error('未发现全屏元素') + return ( + <div ref={slotElement}>{defaultSlot}</div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/gantt/__tests__/gantt.spec.ts b/packages/devui-vue/devui/gantt/__tests__/gantt.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..321977ee72742e59bc55eac0369e0fb6d5c23e63 --- /dev/null +++ b/packages/devui-vue/devui/gantt/__tests__/gantt.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Gantt } from '../index'; + +describe('gantt test', () => { + it('gantt init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/gantt/index.ts b/packages/devui-vue/devui/gantt/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f79701c051486e61388229d57d20d25aa43a2b5 --- /dev/null +++ b/packages/devui-vue/devui/gantt/index.ts @@ -0,0 +1,21 @@ +import type { App } from 'vue' +import Gantt from './src/gantt' +import GanttTools from './src/gantt-tools' +import ganttMarkerDirective from './src/gantt-scale/gantt-marker-directive' + +Gantt.install = function (app: App): void { + app.component(Gantt.name, Gantt) + app.component(GanttTools.name, GanttTools) + app.directive('gantt-marker', ganttMarkerDirective) +} + +export { Gantt } + +export default { + title: 'Gantt 甘特图', + category: '数据展示', + status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Gantt as any) + }, +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-bar-parent/gantt-bar-parent.scss b/packages/devui-vue/devui/gantt/src/gantt-bar-parent/gantt-bar-parent.scss new file mode 100644 index 0000000000000000000000000000000000000000..6aaae086d6d1b641ebe1b89eebd7103a5a5a07e3 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-bar-parent/gantt-bar-parent.scss @@ -0,0 +1,73 @@ +@import '../../style/theme/color'; + +.devui-gantt-bar-parent { + width: 100%; + box-sizing: border-box; + height: 24px; + z-index: 3; + position: relative; + + .devui-gantt-bar-rail { + position: absolute; + background: #eaecf0; + height: 12px; + width: 100%; + margin-top: 4px; + } + + .devui-gantt-bar-rail::before { + width: 0; + height: 0; + border: 3px transparent solid; + border-top-color: #eaecf0; + border-left-color: #eaecf0; + position: absolute; + left: 0; + bottom: -6px; + content: ''; + } + + .devui-gantt-bar-rail::after { + width: 0; + height: 0; + border: 3px transparent solid; + border-top-color: #eaecf0; + border-right-color: #eaecf0; + position: absolute; + right: 0; + bottom: -6px; + content: ''; + } + + .devui-gantt-bar-track { + position: absolute; + background-color: #cacfd8; + height: 12px; + margin-top: 4px; + width: 0; + } + + .devui-gantt-bar-track.head::before { + width: 0; + height: 0; + border: 3px transparent solid; + border-top-color: #cacfd8; + border-left-color: #cacfd8; + position: absolute; + left: 0; + bottom: -6px; + content: ''; + } + + .devui-gantt-bar-track.tail::after { + width: 0; + height: 0; + border: 3px transparent solid; + border-top-color: #cacfd8; + border-right-color: #cacfd8; + position: absolute; + right: 0; + bottom: -6px; + content: ''; + } +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-bar-parent/index.tsx b/packages/devui-vue/devui/gantt/src/gantt-bar-parent/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c20a7cad965dfeb139ee3de410a89866cbdff53c --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-bar-parent/index.tsx @@ -0,0 +1,154 @@ +import {defineComponent , ref , toRefs } from 'vue'; +import {GanttService} from '../gantt-service' +import { Subscription } from 'rxjs'; +// import { GanttProps } from '../gantt-types' +import './gantt-bar-parent.scss'; +const ganttService = new GanttService() +export default defineComponent({ + name:'DGanttBarParent', + props:{ + // 开始时间 + startDate:{ + type:Date, + }, + // 结束时间 + endDate:{ + type:Date + }, + // 进度 + progressRate:{ + type:Number, + default:0 + }, + data:{}, + id:{ + type:String, + }, + tip:{ + type:String, + }, + ganttScaleStatusHandler:{ + type:Subscription + } + }, + setup(props){ + const {startDate,endDate,data,id,tip } = toRefs(props) + let { progressRate, ganttScaleStatusHandler } = toRefs(props) + // const ganttScaleStatusHandler:Subscription = ref<Subscription>() + const tipHovered = ref(false) + const percentage = ref(0) + let left = ref(0) + let width = ref(0) + let max = 100 + let min = 0 + let duration = ref('') + + const setValue = (value: number | null): void => { + if (progressRate !== value) { + progressRate = value; + updateTrackAndHandle(); + } + } + const ensureValueInRange = (value: number | null): number => { + let safeValue; + if (!valueMustBeValid(value)) { + safeValue = min; + } else { + safeValue = clamp(min, value as number, max); + } + return safeValue; + } + const valueMustBeValid = (value: number): boolean => { + return !isNaN(typeof value !== 'number' ? parseFloat(value) : value); + } + const clamp = (min: number, n: number, max: number) => { + return Math.max(min, Math.min(n, max)); + } + const updateTrackAndHandle = (): void => { + const value = progressRate; + const offset = valueToOffset(value); + updateStyle(offset / 100); + this.cdr.markForCheck(); + } + const valueToOffset = (value: number): number => { + return ((value - min.value) / (max.value - min.value)) * 100; + } + const updateStyle = (percentage) => { + percentage = Math.min(1, Math.max(0, percentage)); + if (this.ganttBarTrack && this.ganttBarTrack.nativeElement) { + this.ganttBarTrack.nativeElement.style.width = `${percentage * 100}%`; + } + + if (this.ganttBarProgress && this.ganttBarProgress.nativeElement) { + this.ganttBarProgress.nativeElement.style.left = `${percentage * 100}%`; + } + } + const onInit = () => { + if (progressRate === null) { + this.setValue(this.ensureValueInRange(null)); + } + + duration = ganttService.getDuration(startDate, endDate) + 'd'; + + ganttScaleStatusHandler = ganttService.ganttScaleConfigChange.subscribe((config) => { + if (config.startDate) { + left = ganttService.getDatePostionOffset(startDate); + } + if (config.unit) { + left = ganttService.getDatePostionOffset(startDate); + width = ganttService.getDurationWidth(startDate, endDate); + } + }) as Subscription; + } + + const ngOnChanges = (changes) => { + if (changes['progressRate'] && progressRate > 0) { + updateTrackAndHandle(); + } + + if (changes['startDate']) { + left = ganttService.getDatePostionOffset(startDate); + width = ganttService.getDurationWidth(startDate, endDate); + } + + if (changes['endDate']) { + width = ganttService.getDurationWidth(startDate, endDate); + } + } + + const AfterViewInit = () => { + if (progressRate && progressRate > 0) { + updateTrackAndHandle(); + } + } + + const OnDestroy= (): void => { + if (ganttScaleStatusHandler.value) { + ganttScaleStatusHandler.value.unsubscribe(); + ganttScaleStatusHandler = null; + } + } + + return { + left, + width + } + }, + render() { + const { + left, + width + } = this + const style = { + position:'', + left:left, + width:width + } + return ( + <div class="devui-gantt-bar-parent"> + <div class="devui-gantt-bar-rail"></div> + <div class="devui-gantt-bar-track"></div> + </div> + ) + }, +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/gantt/src/gantt-bar/gantt-bar.scss b/packages/devui-vue/devui/gantt/src/gantt-bar/gantt-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..2e593ef9bf3005ea9d59bda286a691834ade1ff1 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-bar/gantt-bar.scss @@ -0,0 +1,3 @@ +.gantt-bar { + position: relative; +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-bar/index.tsx b/packages/devui-vue/devui/gantt/src/gantt-bar/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8370cf8053a560f2e088c9b751458a09ae8d6fc3 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-bar/index.tsx @@ -0,0 +1,14 @@ +import {defineComponent} from 'vue' + +import './gantt-bar.scss' + + +export default defineComponent({ + name:'GantBar', + props:{}, + render(){ + return ( + <div class="gantt-bar"></div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/gantt/src/gantt-milestone/gantt-milestone.scss b/packages/devui-vue/devui/gantt/src/gantt-milestone/gantt-milestone.scss new file mode 100644 index 0000000000000000000000000000000000000000..0abd57b6c0ca72b6175bc6e086a8da449b0e0c8f --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-milestone/gantt-milestone.scss @@ -0,0 +1,17 @@ +.devui-gantt-milestone { + position: relative; + height: 24px; + line-height: 24px; + display: inline-block; + + & span { + display: inline-block; + vertical-align: middle; + } + + & .icon { + width: 20px; + height: 24px; + margin-right: 4px; + } +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-milestone/index.tsx b/packages/devui-vue/devui/gantt/src/gantt-milestone/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..38aae3c74b7cf1c4bc8b97d63cb359b217a9d32e --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-milestone/index.tsx @@ -0,0 +1,32 @@ +import { defineComponent, ref } from 'vue' +import { MilestoneIcon } from './milestone-icon' +import './gantt-milestone.scss' + +export default defineComponent({ + name: 'DGanttMilestone', + props: { + startDate: { + type: Date, + }, + title: { + type: String, + }, + id: { + type: String, + }, + }, + setup(props) { + // todo + }, + render() { + const { title } = this + return ( + <div class="devui-gantt-milestone"> + <span class="icon"> + <MilestoneIcon /> + </span> + <span>{title}</span> + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/gantt/src/gantt-milestone/milestone-icon.tsx b/packages/devui-vue/devui/gantt/src/gantt-milestone/milestone-icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b0c2b58617aaa127a557ca7c4109ce91c7cff247 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-milestone/milestone-icon.tsx @@ -0,0 +1,212 @@ +export const MilestoneIcon = () => ( + <svg + xmlns="http://www.w3.org/2000/svg" + xmlns-xlink="http://www.w3.org/1999/xlink" + width="22px" + height="24px" + viewBox="0 0 22 24" + version="1.1" + > + <defs> + <linearGradient + x1="50%" + y1="6.72700158%" + x2="50%" + y2="91.2568893%" + id="gantt-linearGradient-1" + > + <stop stop-color="#3DCCA6" offset="0%" /> + <stop stop-color="#2AA7AF" offset="100%" /> + </linearGradient> + <path + d="M14,1.15470054 L20.3923048,4.84529946 C21.6299092,5.55983064 22.3923048,6.88033872 22.3923048,8.30940108 L22.3923048,15.6905989 C22.3923048,17.1196613 21.6299092,18.4401694 20.3923048,19.1547005 L14,22.8452995 C12.7623957,23.5598306 11.2376043,23.5598306 10,22.8452995 L3.60769515,19.1547005 C2.37009085,18.4401694 1.60769515,17.1196613 1.60769515,15.6905989 L1.60769515,8.30940108 C1.60769515,6.88033872 2.37009085,5.55983064 3.60769515,4.84529946 L10,1.15470054 C11.2376043,0.440169359 12.7623957,0.440169359 14,1.15470054 Z" + id="gantt-path-2" + /> + <linearGradient + x1="50%" + y1="0%" + x2="50%" + y2="50%" + id="gantt-linearGradient-4" + > + <stop stop-color="#FFFFFF" offset="0%" /> + <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%" /> + </linearGradient> + <linearGradient + x1="50%" + y1="0%" + x2="51.6276154%" + y2="68.3310347%" + id="gantt-linearGradient-5" + > + <stop stop-color="#FFFFFF" offset="0%" /> + <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%" /> + </linearGradient> + <linearGradient + x1="50%" + y1="0%" + x2="50%" + y2="70.5804357%" + id="gantt-linearGradient-6" + > + <stop stop-color="#FFFFFF" offset="0%" /> + <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%" /> + </linearGradient> + <linearGradient + x1="50%" + y1="0%" + x2="50%" + y2="71.0876747%" + id="gantt-linearGradient-7" + > + <stop stop-color="#FFFFFF" offset="0%" /> + <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%" /> + </linearGradient> + <linearGradient + x1="50%" + y1="0%" + x2="50%" + y2="60.3844779%" + id="gantt-linearGradient-8" + > + <stop stop-color="#FFFFFF" offset="0%" /> + <stop stop-color="#FFFFFF" stop-opacity="0" offset="100%" /> + </linearGradient> + <linearGradient + x1="50%" + y1="0%" + x2="50%" + y2="100%" + id="gantt-linearGradient-9" + > + <stop stop-color="#FFFFFF" stop-opacity="0" offset="0%" /> + <stop stop-color="#FFFFFF" offset="100%" /> + </linearGradient> + <filter + x="-25.0%" + y="-75.0%" + width="150.0%" + height="250.0%" + filterUnits="objectBoundingBox" + id="gantt-filter-10" + > + <feGaussianBlur stdDeviation="1" in="SourceGraphic" /> + </filter> + <linearGradient + x1="-33.9878453%" + y1="3.1788779%" + x2="67.7654261%" + y2="81.2841156%" + id="gantt-linearGradient-11" + > + <stop stop-color="#FF790E" offset="0%" /> + <stop stop-color="#FECC55" offset="100%" /> + </linearGradient> + <linearGradient + x1="71.1217155%" + y1="42.8128234%" + x2="17.9433277%" + y2="-14.3609467%" + id="gantt-linearGradient-12" + > + <stop stop-color="#FFE88E" offset="0%" /> + <stop stop-color="#FF790E" offset="100%" /> + </linearGradient> + </defs> + <g + id="gantt-page-1" + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + > + <g id="gantt-04fix" transform="translate(-189.000000, -423.000000)"> + <g id="gantt-Group-2" transform="translate(40.000000, 417.000000)"> + <g id="gant-group-4" transform="translate(148.000000, 6.000000)"> + <mask id="gantt-mask-3" fill="white"> + <use xlink:href="#gantt-path-2" /> + </mask> + <use + id="gantt-men" + fill="url(#gantt-linearGradient-1)" + xlink:href="#gantt-path-2" + /> + <polygon + fill="url(#gantt-linearGradient-4)" + opacity="0.200000003" + mask="url(#gantt-mask-3)" + points="10 0 14 0 13 13 11 13" + /> + <polygon + fill="url(#gantt-linearGradient-5)" + opacity="0.200000003" + mask="url(#gantt-mask-3)" + transform="translate(17.500000, 11.000000) rotate(-270.000000) translate(-17.500000, -11.000000) " + points="14.5 4.5 18.5 4.5 20.5 17.5 19.5 17.5" + /> + <polygon + fill="url(#gantt-linearGradient-6)" + opacity="0.200000003" + mask="url(#gantt-mask-3)" + transform="translate(7.000000, 11.000000) scale(-1, 1) rotate(-270.000000) translate(-7.000000, -11.000000) " + points="4 4.5 8 4.5 10 17.5 9 17.5" + /> + <polygon + fill="url(#gantt-linearGradient-7)" + opacity="0.200000003" + mask="url(#gantt-mask-3)" + transform="translate(8.110913, 8.110913) rotate(-45.000000) translate(-8.110913, -8.110913) " + points="6.1109127 1.6109127 10.1109127 1.6109127 9.1109127 14.6109127 7.1109127 14.6109127" + /> + <polygon + fill="url(#gantt-linearGradient-8)" + opacity="0.200000003" + mask="url(#gantt-mask-3)" + transform="translate(15.889087, 8.110913) rotate(-315.000000) translate(-15.889087, -8.110913) " + points="13.8890873 1.6109127 17.8890873 1.6109127 16.8890873 14.6109127 14.8890873 14.6109127" + /> + <ellipse + fill="url(#gantt-linearGradient-9)" + opacity="0.5" + filter="url(#filter-10)" + mask="url(#gantt-mask-3)" + cx="12" + cy="17" + rx="6" + ry="2" + /> + <polygon + fill="url(#gantt-linearGradient-11)" + mask="url(#gantt-mask-3)" + points="12 8 18 9 15 11 18 13 11 14" + /> + <polygon + fill="url(#gantt-linearGradient-12)" + mask="url(#gantt-mask-3)" + points="10 6 14 7 13 13 9 13" + /> + <polygon + fill="#FFE3A0" + mask="url(#gantt-mask-3)" + points="10 6 11 6 9 17 8 17" + /> + <polygon + fill="#B4832C" + mask="url(#gantt-mask-3)" + points="13 13 11 14 11.1707479 13" + /> + <rect + fill="#000000" + opacity="0.100000001" + mask="url(#gantt-mask-3)" + x="7" + y="17" + width="10" + height="1" + /> + </g> + </g> + </g> + </g> + </svg> +) diff --git a/packages/devui-vue/devui/gantt/src/gantt-model.ts b/packages/devui-vue/devui/gantt/src/gantt-model.ts new file mode 100644 index 0000000000000000000000000000000000000000..91b5456bd719e0aaa6b05a966d5f284dcead9459 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-model.ts @@ -0,0 +1,61 @@ +export interface GanttScaleDateInfo { + dayOfMonthLabel: string + dayOfWeekLabel: string + monthLabel: string + yearLabel: string + date: Date + monthStart?: boolean + weekend?: boolean + today?: boolean + highlight?: boolean + highlightStart?: boolean + milestone?: string + scaleStartVisable?: boolean + index?: number +} + +export enum GanttScaleUnit { + day = 'day', + week = 'week', + month = 'month', +} +export interface GanttBarStatus { + focused: boolean + startDate: Date + endDate: Date +} + +export interface GanttScaleConfig { + startDate?: Date + endDate?: Date + unit?: GanttScaleUnit +} + +export enum GanttMarkerType { + milestone = 'milestone', + month = 'month', + week = 'week', +} + +export interface GanttMilestone { + date: Date + lable: string +} + +export interface GanttTaskInfo { + id: string + startDate: Date + endDate: Date + title?: string + progress: string + duration: string + moveOffset?: number + left?: number + width?: number +} + +export enum UnitRole { + day = 10, + week = 20, + month = 30, +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-marker-directive.ts b/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-marker-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..9156a42a6dcfda33d1016b61e7a7ed5b9f86568c --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-marker-directive.ts @@ -0,0 +1,47 @@ +import { GanttScaleUnit } from '../gantt-model' +interface BindingType { + value: { + ganttBarContainerElement: HTMLElement + ganttScaleContainerOffsetLeft: number + monthMark: boolean + weekend: boolean + today: boolean + milestone: string + unit: GanttScaleUnit + date: Date + last: boolean + } +} +const ganttMarkerDirective = { + ganttBarContainerElement: null, + monthMarkElement: null, + weekendElement: null, + todayElement: null, + milestoneElement: null, + monthMark: '', + mounted(el: HTMLElement, binding: BindingType): void { + const { ganttBarContainerElement, monthMark } = binding.value + if (ganttBarContainerElement) { + this.ganttBarContainerElement = ganttBarContainerElement + } + if (monthMark) { + this.monthMark = this.monthMark + } + }, + updated(el: HTMLElement, binding: BindingType): void { + // todo + const { monthMark, weekend, today, milestone, unit } = binding.value + if (monthMark) { + this.initMarkElement() + } + }, + initMarkElement(): void { + if (this.ganttBarContainerElement) { + if (this.monthMark && !this.monthMarkElement) { + // todo + } + } + }, +} + +export default ganttMarkerDirective diff --git a/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-scale.scss b/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-scale.scss new file mode 100644 index 0000000000000000000000000000000000000000..bbb3cc42bc5e6f5ab757065c1f499d2c3d61673d --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-scale/gantt-scale.scss @@ -0,0 +1,175 @@ +@import '../../../style/theme/color'; +@import '../../../style/theme/corner'; +@import '../../../style/core/_font'; + +.devui-gantt-scale-wrapper { + display: block; + height: 36px; + line-height: 18px; +} + +.devui-gantt-scale { + display: inline-block; + color: $devui-placeholder; // TODO: Color-Question + text-align: center; + position: absolute; + height: 36px; + font-weight: normal; + + &.day { + &:not(.milestone) { + &:hover .devui-scale-start { + display: none; + } + } + + &.milestone { + background-image: + linear-gradient( + 180deg, + rgba(254, 204, 85, 0) 0%, + rgba(62, 204, 166, 0.1) 100% + ); + } + } + + & .devui-scale-start { + width: 100%; + height: 18px; + position: absolute; + left: 1px; + white-space: nowrap; + + &.milestone { + color: $devui-success; + } + } + + & .devui-scale-unit { + height: 18px; + position: absolute; + top: 18px; + width: 100%; + + & .border-left { + height: 18px; + border-left: 1px solid $devui-list-item-selected-bg; + } + + & .scale-highlight { + position: absolute; + height: 18px; + border-radius: $devui-border-radius; + background-color: $devui-brand; + padding: 0 4px 0 4px; + + & div { + color: $devui-base-bg; + font-size: $devui-font-size; + font-weight: normal; + } + } + + .today { + background: rgba(255, 121, 14, 0.2); + border-radius: $devui-border-radius; + height: 16px; + } + } + + & .milestone-new { + display: none; + position: absolute; + width: 18px; + height: 18px; + margin-left: 16px; + border: 1px solid $devui-list-item-selected-bg; // TODO: Color-Question + cursor: pointer; + + & div { + line-height: 16px; + } + } + + &:not(.milestone) { + &:hover .milestone-new.day { + display: block; + } + } +} + +.devui-mark-line { + position: absolute; + top: 0; + bottom: 0; + width: 2px; + z-index: 1; + background: $devui-line; + opacity: 0.5; + + &.today { + opacity: 0.2; + background: #ff790e; + + &.day { + margin-left: 24px; + } + + &.week { + margin-left: 9px; + } + + &.month { + margin-left: 4px; + } + } + + &.milestone { + opacity: 0.2; + background: $devui-success; + + &.day { + margin-left: 24px; + } + + &.week { + margin-left: 9px; + } + + &.month { + margin-left: 4px; + } + } +} + +.devui-mark-stripe { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + background: + linear-gradient( + 45deg, + rgba(202, 207, 216, 0.2) 0, + rgba(202, 207, 216, 0.2) 10%, + transparent 10%, + transparent 50%, + rgba(202, 207, 216, 0.2) 50%, + rgba(202, 207, 216, 0.2) 60%, + transparent 60%, + transparent + ); + background-size: 6px 6px; + + &.day { + width: 100px; + } + + &.week { + width: 40px; + } + + &.month { + width: 20px; + } +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-scale/index.tsx b/packages/devui-vue/devui/gantt/src/gantt-scale/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..00cb52decf41882f766ad27872d46c636e9de199 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-scale/index.tsx @@ -0,0 +1,195 @@ +import { defineComponent, ref, PropType, onMounted, toRefs, watch } from 'vue' +import './gantt-scale.scss' +import { + GanttScaleUnit, + GanttMilestone, + GanttScaleDateInfo, +} from '../gantt-model' +import { useScaleData } from './use-scale-data' +import { i18nText } from '../i18n-gantt' +export default defineComponent({ + name: 'DGanttScale', + props: { + /** 视图单位 */ + unit: { + type: String, + default: GanttScaleUnit.day, + }, + height: { + type: Number, + }, + /** 开始时间 */ + startDate: { + type: Date, + }, + /** 结束时间 */ + endDate: { + type: Date, + }, + /** 甘特图时间轴容器左偏移像素 */ + ganttScaleContainerOffsetLeft: { + type: Number, + }, + /** 版本里程碑列表 */ + milestoneList: { + type: Array as PropType<GanttMilestone[]>, + }, + scrollElement: { + type: Object, + }, + ganttBarContainerElement: { + type: Object, + }, + }, + emits: ['addMilestone'], + setup(props, ctx) { + const { startDate, endDate, milestoneList, scrollElement, unit } = + toRefs(props) + const scaleData = ref<GanttScaleDateInfo[]>([]) + const viewSCaleData = ref<GanttScaleDateInfo[]>([]) + const scaleWidth = ref({ + day: 40, + week: 30, + month: 20, + }) + const highlight = ref(false) + const highlightStartText = ref('') + const highlightEndText = ref('') + const { generateScaleData } = useScaleData(milestoneList) + let viewScaleRange = [0, 0] + const addMilestone = (info: GanttScaleDateInfo) => { + ctx.emit('addMilestone', info) + } + const getViewScaleData = () => { + if (scrollElement.value) { + const containerWidth = scrollElement.value.clientWidth + const scrollLeft = scrollElement.value.scrollLeft + + const start = Math.floor(scrollLeft / scaleWidth.value[unit.value]) + const offset = Math.ceil(containerWidth / scaleWidth.value[unit.value]) + viewScaleRange = [start - 2, start + offset + 2] + viewSCaleData.value = scaleData.value.filter( + (i: GanttScaleDateInfo) => { + return i.index >= viewScaleRange[0] && i.index <= viewScaleRange[1] + } + ) + } + } + onMounted(() => { + if (startDate.value && endDate.value) { + scaleData.value = generateScaleData(startDate.value, endDate.value) + getViewScaleData() + } + }) + + watch( + () => props.scrollElement, + () => { + getViewScaleData() + ;(props.scrollElement as HTMLDivElement).addEventListener( + 'scroll', + () => { + getViewScaleData() + } + ) + } + ) + + return { + viewSCaleData, + scaleWidth, + addMilestone, + highlight, + highlightStartText, + highlightEndText, + } + }, + render() { + const { + unit, + viewSCaleData, + scaleWidth, + addMilestone, + highlight, + highlightStartText, + highlightEndText, + ganttBarContainerElement, + } = this + return ( + <div class="devui-gantt-scale-wrapper"> + {viewSCaleData.map((data, index) => ( + <div + class={`devui-gantt-scale ${unit} ${data.today} ${data.milestone}`} + style={{ + left: `${scaleWidth[unit] * data.index}px`, + width: `${scaleWidth[unit]}px`, + }} + v-gantt-marker={{ + ganttBarContainerElement, + monthMark: data.monthMark, + weekend: data.weekend, + milestone: data.milestone, + today: data.today, + date: data.date, + unit: unit, + last: index === viewSCaleData.length - 1, + }} + > + <div class={`devui-scale-start ${data.milestone}`}> + {data.milestone && unit === 'day' && <div>{data.milestone}</div>} + {(!data.milestone || unit !== 'day') && + data.scaleStartVisable && + (index === 0 || data.monthStart) + ? unit === 'month' + ? i18nText.zh.yearDisplay(data.yearLabel) + : i18nText.zh.yearAndMonthDisplay( + data.yearLabel, + data.monthLabel + ) + : ''} + </div> + <div class="devui-scale-unit"> + {highlight && data.highlightStart && ( + <div class="scale-highlight"> + <div style="float: left">{highlightStartText}</div> + <div style="float: right">{highlightEndText}</div> + <div style="clear: both"></div> + </div> + )} + {(!highlight || !data.highlightStart) && unit === 'day' && ( + <div class={`border-left ${data.today ? 'today' : ''}`}> + {data.today ? i18nText.zh.today : data.dayOfMonthLabel} + </div> + )} + {(!highlight || !data.highlightStart) && unit === 'week' && ( + <div + class={`${data.weekend || index === 0 ? 'border-left' : ''}`} + > + {index === 0 || data.weekend ? data.dayOfMonthLabel : ''} + </div> + )} + {(!highlight || !data.highlightStart) && unit === 'month' && ( + <div + class={`${ + data.monthStart || index === 0 ? 'border-left' : '' + }`} + > + {index === 0 || data.monthStart + ? i18nText.zh.monthDisplay(data.monthLabel) + : ''} + </div> + )} + </div> + <div + class={`milestone-new ${unit}`} + title="milestone" + onClick={() => addMilestone(data)} + > + <d-icon name="add" /> + </div> + </div> + ))} + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/gantt/src/gantt-scale/use-scale-data.ts b/packages/devui-vue/devui/gantt/src/gantt-scale/use-scale-data.ts new file mode 100644 index 0000000000000000000000000000000000000000..72f2f14c9f7b7da4184e0273a8d76efa43968e24 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-scale/use-scale-data.ts @@ -0,0 +1,93 @@ +import { Ref } from 'vue' +import { GanttMilestone, GanttScaleDateInfo } from '../gantt-model' +import { isSameDate } from '../utils' + +export const useScaleData = ( + milestoneList: Ref<GanttMilestone[]> +): { + generateScaleData: (startDate: Date, endDate: Date) => GanttScaleDateInfo[] +} => { + const SCALE_START_LABLE_OFFSET = 7 + + const generateDateInfo = (date: Date, index: number): GanttScaleDateInfo => { + const dateInfo: GanttScaleDateInfo = { + dayOfMonthLabel: '', + dayOfWeekLabel: '', + monthLabel: '', + yearLabel: '', + date: date, + monthStart: false, + weekend: false, + today: false, + milestone: '', + highlightStart: false, + scaleStartVisable: true, + index, + } + const dayOfMonth = date.getDate() + dateInfo.dayOfMonthLabel = dayOfMonth + '' + if (dayOfMonth === 1) { + dateInfo.monthStart = true + } + + const dayOfWeek = date.getDay() + dateInfo.dayOfWeekLabel = dayOfWeek + '' + if (dayOfWeek === 6) { + dateInfo.weekend = true + } + const month = date.getMonth() + 1 + dateInfo.monthLabel = month + '' + const year = date.getFullYear() + dateInfo.yearLabel = year + '' + if (isSameDate(date, new Date())) { + dateInfo.today = true + } + + if ( + new Date( + year, + month - 1, + dayOfMonth + SCALE_START_LABLE_OFFSET + ).getMonth() > + month - 1 + ) { + dateInfo.scaleStartVisable = false + } + if (milestoneList.value) { + milestoneList.value.forEach((milestone) => { + if (milestone.date) { + if (isSameDate(milestone.date, dateInfo.date)) { + dateInfo.milestone = milestone.lable + } + } + }) + } + + return dateInfo + } + + const getNextDay = (date: Date) => { + const nextDayDate = date.setDate(date.getDate() + 1) + return new Date(nextDayDate) + } + const generateScaleData = ( + startDate: Date, + endDate: Date + ): GanttScaleDateInfo[] => { + const scaleData = [] + let handleDate = startDate + let index = 0 + while (!isSameDate(handleDate, endDate)) { + const dateInfo = generateDateInfo(handleDate, index) + scaleData.push(dateInfo) + handleDate = getNextDay(new Date(handleDate)) + index++ + } + console.log({ scaleData }) + return scaleData + } + + return { + generateScaleData, + } +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-service.ts b/packages/devui-vue/devui/gantt/src/gantt-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..22e888132113beb67b1b6428d2fc1f9846a6af70 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-service.ts @@ -0,0 +1,110 @@ +import { fromEvent, merge, Observable, ReplaySubject, Subject } from 'rxjs'; +import { pluck } from 'rxjs/operators'; +import { GanttBarStatus, GanttScaleConfig, GanttScaleUnit } from './gantt-model'; +export class GanttService { + static DAY_DURATION = 24 * 60 * 60 * 1000; + scaleUnit = GanttScaleUnit.day; + scaleStartDate: Date; + scaleEndDate: Date; + ganttBarStatusChange = new Subject<GanttBarStatus>(); + ganttScaleConfigChange = new ReplaySubject<GanttScaleConfig>(1); + + mouseDownListener: Observable<number>; + mouseMoveListener = new Observable(); + mouseEndListener = new Observable(); + + changeGanttBarStatus(status: GanttBarStatus):void { + this.ganttBarStatusChange.next(status); + } + + registContainerEvents(scrollContainer: HTMLElement):void { + // 背景拖拽 + this.mouseDownListener = fromEvent(scrollContainer, 'mousedown').pipe(pluck<Event, number>('pageX')); + + this.mouseMoveListener = fromEvent(scrollContainer, 'mousemove').pipe(pluck<Event, number>('pageX')); + + this.mouseEndListener = merge(fromEvent(scrollContainer, 'mouseup'), fromEvent(scrollContainer, 'mouseout')).pipe( + pluck<Event, number>('pageX') + ); + } + + changeGanttScaleConfig(status: GanttScaleConfig):void { + this.ganttScaleConfigChange.next(status); + } + + setScaleConfig(config: GanttScaleConfig):void { + if (config.startDate) { + this.scaleStartDate = config.startDate; + } + if (config.endDate) { + this.scaleEndDate = config.endDate; + } + if (config.unit) { + this.scaleUnit = config.unit; + } + this.changeGanttScaleConfig(config); + } + + getScaleUnitPixel():number { + switch (this.scaleUnit) { + case GanttScaleUnit.day: + return 40; + break; + case GanttScaleUnit.week: + return 30; + break; + case GanttScaleUnit.month: + return 20; + break; + default: + break; + } + } + + getDatePostionOffset(date: Date): number { + if (date && this.scaleStartDate) { + const timeOffset = date.getTime() - this.scaleStartDate.getTime(); + const units = timeOffset / GanttService.DAY_DURATION; + return units * this.getScaleUnitPixel(); + } + } + + getDuration(startDate: Date, endDate: Date): number { + if (startDate && endDate) { + const timeOffset = endDate.getTime() - startDate.getTime(); + const duration = timeOffset / GanttService.DAY_DURATION + 1; + return Math.round(duration); + } + } + + getDurationWidth(startDate: Date, endDate: Date): number { + if (startDate && endDate) { + const duration = this.getDuration(startDate, endDate); + return duration * this.getScaleUnitPixel(); + } + } + + isSomeDate(date: Date, compareDate: Date):boolean { + if (date.getFullYear() !== compareDate.getFullYear()) { + return false; + } + + if (date.getMonth() !== compareDate.getMonth()) { + return false; + } + + if (date.getDate() !== compareDate.getDate()) { + return false; + } + return true; + } + + roundDate(date: Date):void { + if (date.getHours() >= 12) { + date.setDate(date.getDate() + 1); + date.setHours(0, 0, 0); + } else if (date.getHours() < 12) { + date.setHours(0, 0, 0); + } + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/gantt/src/gantt-tools/gantt-tools.scss b/packages/devui-vue/devui/gantt/src/gantt-tools/gantt-tools.scss new file mode 100644 index 0000000000000000000000000000000000000000..45137d7795db0dea315b6fda1c71fb61e2a2eb2d --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-tools/gantt-tools.scss @@ -0,0 +1,79 @@ +@import '../../../style/theme/color'; +@import '../../../style/theme/corner'; +@import '../../../style/core/_font'; +@import '../../../style/theme/shadow'; + +.tools-container { + position: absolute; + top: 70px; + right: 20px; + z-index: 10; + + .devui-dropdown-origin { + border: 0; + + &:hover { + color: $devui-link !important; + } + } + + .devui-btn { + height: 32px !important; + color: $devui-text !important; + padding: 0 8px !important; + min-width: 50px; + + &:hover { + color: $devui-link !important; + } + } + + .tool { + &.minus, + &.add { + .devui-btn { + min-width: 30px; + } + } + } + + .devui-select-selection { + width: 90px; + + .devui-select-input { + height: 32px; + } + } +} + +.tool { + display: inline-flex; + align-items: center; + justify-content: center; + height: 32px; + margin-left: 12px; + background-color: $devui-base-bg; + box-shadow: $devui-shadow-length-base rgba(81, 112, 255, 0.4); + cursor: pointer; + + &.disabled { + opacity: 0.5; + } + + span { + border: 0 !important; + } + + .switch-view { + padding: 0 8px; + + &:hover { + color: $devui-link !important; + } + } +} + +.devui-dropdown-menu { + top: 10px !important; + left: -6px !important; +} diff --git a/packages/devui-vue/devui/gantt/src/gantt-tools/index.tsx b/packages/devui-vue/devui/gantt/src/gantt-tools/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..070283dcd238d8814b02daeac1c0fff59eb5a634 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-tools/index.tsx @@ -0,0 +1,107 @@ +import { defineComponent, ref } from 'vue' +import './gantt-tools.scss' +import { GanttScaleUnit } from '../gantt-model' + +export default defineComponent({ + name: 'DGanttTools', + props: { + unit: { + type: String, + default: null, + }, + isFullScreen: { + type: Boolean, + default: false, + }, + }, + emits: ['goToday', 'reduceUnit', 'increaseUnit', 'switchView'], + setup(props, ctx) { + const currentUnitLabel = ref(props.unit) + const views = ref([ + { + name: 'Day', + value: 'day', + }, + { + name: 'Week', + value: 'week', + }, + { + name: 'Month', + value: 'month', + }, + ]) + const actionHandle = (type: string) => { + switch (type) { + case 'today': + ctx.emit('goToday') + break + case 'reduce': + ctx.emit('reduceUnit') + break + case 'increase': + ctx.emit('increaseUnit') + break + } + } + const selectView = (selectItem: { name: string; value: string; }) => { + ctx.emit('switchView', selectItem.value) + } + return { + actionHandle, + currentUnitLabel, + views, + selectView, + } + }, + render() { + const { isFullScreen, actionHandle, views, selectView, $slots } = this + + return ( + <div + class="tools-container" + style={{ position: isFullScreen ? 'fixed' : 'absolute' }} + > + <d-button + btnStyle="common" + onClick={() => actionHandle('today')} + class="tool" + > + Today + </d-button> + <div class="tool"> + <d-select + v-model={this.currentUnitLabel} + options={views} + onValueChange={selectView} + ></d-select> + </div> + <d-button + btnStyle="common" + class={[ + 'tool', + 'minus', + this.currentUnitLabel === GanttScaleUnit.day ? 'disabled' : '', + ]} + disabled={this.currentUnitLabel === GanttScaleUnit.day} + onClick={() => actionHandle('reduce')} + > + <d-icon name="minus"></d-icon> + </d-button> + <d-button + btnStyle="common" + class={[ + 'tool', + 'add', + this.currentUnitLabel === GanttScaleUnit.month ? 'disabled' : '', + ]} + disabled={this.currentUnitLabel === GanttScaleUnit.month} + onClick={() => actionHandle('increase')} + > + <d-icon name="add"></d-icon> + </d-button> + {$slots.default && $slots.default()} + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/gantt/src/gantt-types.ts b/packages/devui-vue/devui/gantt/src/gantt-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..02cf168da298fa82acf8186df9e073f036a8e974 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt-types.ts @@ -0,0 +1,20 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { GanttScaleUnit } from './gantt-model' +export const ganttProps = { + startDate: { + type: Date, + }, + endDate: { + type: Date, + }, + unit: { + type: String as PropType<GanttScaleUnit>, + default: GanttScaleUnit.day, + }, + progressRate:{ + type:Number + }, +} as const + + +export type GanttProps = ExtractPropTypes<typeof ganttProps> diff --git a/packages/devui-vue/devui/gantt/src/gantt.scss b/packages/devui-vue/devui/gantt/src/gantt.scss new file mode 100644 index 0000000000000000000000000000000000000000..6f2c3957f3cef96943163fd866472e1a9d5481ae --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt.scss @@ -0,0 +1,36 @@ +@import '../../styles-var/devui-var.scss'; + +.gantt-container { + overflow: scroll; + + .header { + position: relative; + border-bottom: 1px solid $devui-dividing-line; + } + + .body { + position: relative; + min-height: 400px; + height: 100%; + + .item { + height: 40px; + padding-top: 8px; + } + } +} + +.tool { + display: inline-flex; + align-items: center; + justify-content: center; + height: 32px; + margin-left: 12px; + background-color: $devui-base-bg; + box-shadow: $devui-shadow-length-base rgba(81, 112, 255, 0.4); + cursor: pointer; + + span { + border: 0 !important; + } +} diff --git a/packages/devui-vue/devui/gantt/src/gantt.tsx b/packages/devui-vue/devui/gantt/src/gantt.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e2ddae9b4d533172827a2cc52ed002bf0aa50703 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/gantt.tsx @@ -0,0 +1,50 @@ +import { defineComponent, onMounted, ref, toRefs } from 'vue' +import DGanttScale from './gantt-scale/index' +import DGanttTools from './gantt-tools/index' +import { ganttProps, GanttProps } from './gantt-types' +import './gantt.scss' +import { useGantt } from './use-gantt' +export default defineComponent({ + name: 'DGantt', + components: { DGanttScale, DGanttTools }, + props: ganttProps, + setup(props: GanttProps, ctx) { + const { startDate, endDate } = toRefs(props) + const ganttContainer = ref() + const ganttScaleWidth = ref<number>() + const { getDurationWidth } = useGantt() + onMounted(() => { + ganttScaleWidth.value = getDurationWidth(startDate.value, endDate.value) + }) + return { + ganttContainer, + ganttScaleWidth, + } + }, + render() { + const { + $slots, + startDate, + endDate, + unit, + ganttContainer, + ganttScaleWidth, + } = this + return ( + <div style={{ position: 'relative' }}> + <div class="devui-gantt gantt-container" ref="ganttContainer"> + <div class="header" style={{ width: `${ganttScaleWidth}px` }}> + <d-gantt-scale + startDate={startDate} + endDate={endDate} + unit={unit} + scrollElement={ganttContainer} + ></d-gantt-scale> + </div> + <d-gantt-tools unit={unit}></d-gantt-tools> + <div class="body" style={{ width: `${ganttScaleWidth}px` }}></div> + </div> + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/gantt/src/i18n-gantt.ts b/packages/devui-vue/devui/gantt/src/i18n-gantt.ts new file mode 100644 index 0000000000000000000000000000000000000000..82d0363b64a325fc836d91ee3392e2fea130552c --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/i18n-gantt.ts @@ -0,0 +1,54 @@ +export const i18nText = { + en: { + today: 'today', + monthsOfYear: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + yearDisplay(year: string): string { + return `${year}` + }, + monthDisplay(strMonthIndex: string): string { + return this.monthsOfYear[Number(strMonthIndex) - 1] + }, + yearAndMonthDisplay(year: string, strMonthIndex: string): string { + return this.yearDisplay(year) + this.monthDisplay(strMonthIndex) + }, + }, + zh: { + today: '今天', + monthsOfYear: [ + '1月', + '2月', + '3月', + '4月', + '5月', + '6月', + '7月', + '8月', + '9月', + '10月', + '11月', + '12月', + ], + yearDisplay(year: string): string { + return `${year}年` + }, + monthDisplay(strMonthIndex: string): string { + return this.monthsOfYear[Number(strMonthIndex) - 1] + }, + yearAndMonthDisplay(year: string, strMonthIndex: string): string { + return this.yearDisplay(year) + this.monthDisplay(strMonthIndex) + }, + }, +} diff --git a/packages/devui-vue/devui/gantt/src/use-gantt.ts b/packages/devui-vue/devui/gantt/src/use-gantt.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a59908c97f844955881aeb4ae331440c6d69955 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/use-gantt.ts @@ -0,0 +1,36 @@ +import { GanttScaleUnit } from './gantt-model' +export const useGantt = (scaleUnit = GanttScaleUnit.day) => { + const DAY_DURATION = 24 * 60 * 60 * 1000 + + const getScaleUnitPixel = () => { + switch (scaleUnit) { + case GanttScaleUnit.day: + return 40 + case GanttScaleUnit.week: + return 30 + case GanttScaleUnit.month: + return 20 + default: + break + } + } + + const getDuration = (startDate: Date, endDate: Date): number => { + if (startDate && endDate) { + const timeOffset = endDate.getTime() - startDate.getTime() + const duration = timeOffset / DAY_DURATION + 1 + console.log('duration => ', duration) + + return Math.round(duration) + } + } + const getDurationWidth = (startDate: Date, endDate: Date): number => { + if (startDate && endDate) { + const duration = getDuration(startDate, endDate) + return duration * getScaleUnitPixel() + } + } + return { + getDurationWidth, + } +} diff --git a/packages/devui-vue/devui/gantt/src/utils.ts b/packages/devui-vue/devui/gantt/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..a232b179f9a53f1bb128843d7426c8003a7eccf4 --- /dev/null +++ b/packages/devui-vue/devui/gantt/src/utils.ts @@ -0,0 +1,8 @@ +/** 判断是否是同一天 */ +export const isSameDate = (date: Date, compareDate: Date): boolean => { + return ( + date.getFullYear() === compareDate.getFullYear() && + date.getMonth() === compareDate.getMonth() && + date.getDate() === compareDate.getDate() + ) +} diff --git a/packages/devui-vue/devui/grid/__tests__/grid.spec.ts b/packages/devui-vue/devui/grid/__tests__/grid.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa33b9765e7ec5a8972716e9ccc95f1c53e2e097 --- /dev/null +++ b/packages/devui-vue/devui/grid/__tests__/grid.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Row } from '../index'; + +describe('grid test', () => { + it('grid init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/grid/index.ts b/packages/devui-vue/devui/grid/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb9577156f351ec9585a16ba63a0d0d18063409c --- /dev/null +++ b/packages/devui-vue/devui/grid/index.ts @@ -0,0 +1,22 @@ +import type { App } from 'vue' +import Row from './src/row' +import Col from './src/col' + +Row.install = function(app: App): void { + app.component(Row.name, Row) +} + +Col.install = function(app: App): void { + app.component(Col.name, Col) +} +export { Row, Col } + +export default { + title: 'Grid 栅格', + category: '布局', + status: '已完成', + install(app: App): void { + app.use(Col as any) + app.use(Row as any) + } +} diff --git a/packages/devui-vue/devui/grid/src/col.scss b/packages/devui-vue/devui/grid/src/col.scss new file mode 100644 index 0000000000000000000000000000000000000000..228c177d0c0c2314ee3c0bf0d575909fdf788c30 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/col.scss @@ -0,0 +1,67 @@ +@use 'sass:math'; + +.devui-col { + position: relative; + max-width: 100%; + min-height: 1px; +} + +@function percentage ($i, $sum: 24) { + @return math.div($i, $sum) * 100%; +} + +.devui-col-span-0 { + display: none; +} + +@for $i from 1 to 24 { + .devui-col-offset-#{$i} { + margin-left: percentage($i); + } + .devui-col-pull-#{$i} { + right: percentage($i); + } + .devui-col-push-#{$i} { + left: percentage($i); + } + .devui-col-span-#{$i} { + display: block; + flex: 0 0 percentage($i); + width: percentage($i); + } + .devui-col-xs-offset-#{$i} { + margin-left: percentage($i); + } + .devui-col-xs-pull-#{$i} { + right: percentage($i); + } + .devui-col-xs-push-#{$i} { + left: percentage($i); + } + .devui-col-xs-span-#{$i} { + display: block; + flex: 0 0 percentage($i); + width: percentage($i); + } +} + +@each $size, $value in (sm, 576), (md, 768), (lg, 992), (xl, 1200), (xxl, 1600) { + @media screen and (min-width: #{$value}px) { + @for $i from 1 to 24 { + .devui-col-#{$size}-offset-#{$i} { + margin-left: percentage($i); + } + .devui-col-#{$size}-pull-#{$i} { + right: percentage($i); + } + .devui-col-#{$size}-push-#{$i} { + left: percentage($i); + } + .devui-col-#{$size}-span-#{$i} { + display: block; + flex: 0 0 percentage($i); + width: percentage($i); + } + } + } +} diff --git a/packages/devui-vue/devui/grid/src/col.tsx b/packages/devui-vue/devui/grid/src/col.tsx new file mode 100644 index 0000000000000000000000000000000000000000..596cb8a73c4dc9d6dc86d1dea8f42357a2619690 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/col.tsx @@ -0,0 +1,35 @@ +import { defineComponent, computed, CSSProperties, Ref, inject } from 'vue' +import { colProps, ColProps } from './grid-types' +import { useSize, CLASS_PREFIX, useColClassNames } from './use-grid' +import './col.scss' + + +export default defineComponent({ + name: 'DCol', + props: colProps, + setup (props: ColProps, { slots }) { + + const formatFlex = (flex: typeof props.flex) => { + if (typeof flex === 'number') { + return `${flex} ${flex} auto` + } + if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(flex)) { + return `0 0 ${flex}` + } + return flex + } + + const colClassNames= useColClassNames(props) + + const sizeClassNames = useSize(props) + + const colStyle = computed<CSSProperties>(() => ({ + flex: formatFlex(props.flex), + order: props.order + })) + + const gutterStyle = inject<Ref<CSSProperties>>('gutterStyle') + + return () => <div class={`${CLASS_PREFIX}${colClassNames.value}${sizeClassNames.value}`} style={{ ...colStyle.value, ...gutterStyle.value }}>{slots.default?.()}</div> + } +}) diff --git a/packages/devui-vue/devui/grid/src/grid-types.ts b/packages/devui-vue/devui/grid/src/grid-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..a6491cf262525c3f8184abac3e93dd9c568abb29 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/grid-types.ts @@ -0,0 +1,70 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export type Align = 'top' | 'middle' | 'bottom' + +export type Justify = 'start' | 'end' | 'center' | 'around' | 'between' + +export interface GutterScreenSizes { + xs?: number | number[] + sm: number | number[] + md: number | number[] + lg: number | number[] + xl: number | number[] + xxl: number | number[] +} + +export const rowProps = { + align: { + type: String as PropType<Align>, + default: 'top' + }, + gutter: { + type: [Number, Object, Array] as PropType<number | GutterScreenSizes | number[]>, + default: 0 + }, + justify: { + type: String as PropType<Justify>, + default: 'start' + }, + wrap: { + type: Boolean as PropType<boolean>, + default: false + } +} as const + +export type RowProps = ExtractPropTypes<typeof rowProps> + +const screenSizesProp = [Number, Object] as PropType<number | ColPropsBaseClass> + +export const screenSizes = { + xs: screenSizesProp, + sm: screenSizesProp, + md: screenSizesProp, + lg: screenSizesProp, + xl: screenSizesProp, + xxl: screenSizesProp, +} as const + +const numberProp = Number as PropType<number> + +export const colPropsBaseStyle = { + flex: [String, Number] as PropType<string | number>, + order: numberProp, +} as const + +export const colPropsBaseClass = { + offset: numberProp, + pull: numberProp, + push: numberProp, + span: numberProp +} as const + +export type ColPropsBaseStyle = ExtractPropTypes<typeof colPropsBaseStyle> + +export type ColPropsBaseClass = ExtractPropTypes<typeof colPropsBaseClass> + +export type ScreenSizes = ExtractPropTypes<typeof screenSizes> + +export const colProps = { ...colPropsBaseStyle, ...colPropsBaseClass, ...screenSizes} + +export type ColProps = ExtractPropTypes<typeof colProps> diff --git a/packages/devui-vue/devui/grid/src/row.scss b/packages/devui-vue/devui/grid/src/row.scss new file mode 100644 index 0000000000000000000000000000000000000000..b5b3df4ad0830f343e0323418894c159fe702c4f --- /dev/null +++ b/packages/devui-vue/devui/grid/src/row.scss @@ -0,0 +1,19 @@ +.devui-row { + display: flex; +} + +.devui-row-wrap { + flex-wrap: wrap; +} + +@each $prefix, $value in (top, flex-start), (middle, center), (bottom, flex-end) { + .devui-row-align-#{$prefix} { + align-items: $value; + } +} + +@each $prefix, $value in (start, flex-start), (center, center), (end, flex-end), (around, space-around), (between, space-between) { + .devui-row-justify-#{$prefix} { + justify-content: $value; + } +} diff --git a/packages/devui-vue/devui/grid/src/row.tsx b/packages/devui-vue/devui/grid/src/row.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6e6bb5b35c4ec28dea954674b458e25f99c2bed6 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/row.tsx @@ -0,0 +1,69 @@ +import { defineComponent, computed, ref, Ref, CSSProperties, onMounted, onUnmounted, provide } from 'vue' +import { rowProps, RowProps } from './grid-types' +import { formatClass } from './use-grid' +import { responesScreen, Screen, RESULT_SCREEN, removeSubscribeCb } from './use-screen' +import './row.scss' + +const CLASS_PREFIX = 'devui-row' + +export default defineComponent({ + name: 'DRow', + props: rowProps, + emits: [], + setup(props: RowProps, { slots }) { + const gutterScreenSize = ref<Screen>({}) + + const rowClass = computed<string>(() => { + const alignClass = formatClass(`${CLASS_PREFIX}-align`, props.align) + const justifyClass = formatClass(`${CLASS_PREFIX}-justify`, props.justify) + const wrapClass = props.wrap ? ` ${CLASS_PREFIX}-wrap` : '' + return `${alignClass}${justifyClass}${wrapClass}` + }) + + let token + + onMounted(() => { + token = responesScreen(screen => { + gutterScreenSize.value = screen + }) + }) + + onUnmounted(() => { + removeSubscribeCb(token) + }) + + const gutterStyle = computed<CSSProperties>(() => { + if (!props.gutter) { + return {} + } + let currentGutter = [0, 0] + if (Array.isArray(props.gutter)) { + currentGutter = props.gutter as number[] + } else if (typeof props.gutter === 'number') { + currentGutter = [props.gutter as number, 0] + } else { + RESULT_SCREEN.some(size => { + const gzs = props.gutter[size] + if (gutterScreenSize.value[size] && gzs) { + if (typeof gzs === 'number') { + currentGutter = [gzs, 0] + } else { + currentGutter = gzs + } + return true + } + return false + }) + } + const paddingLeft = `${(currentGutter[0] || 0) / 2}px` + const paddingRight = `${(currentGutter[0] || 0) / 2}px` + const paddingTop = `${(currentGutter[1] || 0) / 2}px` + const paddingBottom = `${(currentGutter[1] || 0) / 2}px` + return { paddingLeft, paddingRight, paddingTop, paddingBottom } + }) + + provide<Ref<CSSProperties>>('gutterStyle', gutterStyle) + + return () => <div class={`${CLASS_PREFIX}${rowClass.value}`}>{slots.default?.()}</div> + } +}) diff --git a/packages/devui-vue/devui/grid/src/use-grid.ts b/packages/devui-vue/devui/grid/src/use-grid.ts new file mode 100644 index 0000000000000000000000000000000000000000..a303a3624638d7767d3190ce7c4b89468c682f58 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/use-grid.ts @@ -0,0 +1,47 @@ +import { computed } from 'vue' +import { ScreenSizes, ColPropsBaseClass, screenSizes, colPropsBaseClass } from './grid-types' + +export const CLASS_PREFIX = 'devui-col' + +export function formatClass (prefix: string, val: number | string | undefined) { + return val !== undefined ? ` ${prefix}-${val}` : '' +} + +export function useColClassNames (props: ColPropsBaseClass) { + return computed<string>(() => { + const spanClass = formatClass(`${CLASS_PREFIX}-span`, props.span) + const offsetClass = formatClass(`${CLASS_PREFIX}-offset`, props.offset) + const pullClass = formatClass(`${CLASS_PREFIX}-pull`, props.pull) + const pushClass = formatClass(`${CLASS_PREFIX}-push`, props.push) + return `${spanClass}${offsetClass}${pullClass}${pushClass}` + }) +} + +function setSpace (val:string) { + return val && ` ${val.trim()} ` +} + +export function useSize (colSizes: ScreenSizes) { + const keys = Object.keys(colSizes).filter(key => key in screenSizes) as (keyof ScreenSizes)[] + return computed<string>(() => { + return keys.reduce((total, key) => { + const valueType = typeof colSizes[key] + + if (valueType === 'number') { + total = `${setSpace(total)}${CLASS_PREFIX}-${key}-span-${colSizes[key]}` + } else if (valueType === 'object') { + const colSizesKeys = Object.keys(colSizes[key]) as (keyof ColPropsBaseClass)[] + const sum = colSizesKeys.filter(item => item in colPropsBaseClass).reduce((tot, k) => { + if (typeof colSizes[key][k] !== 'number') { + return '' + } else { + tot = `${setSpace(tot)}${CLASS_PREFIX}-${key}-${k}-${colSizes[key][k]}` + } + return tot + }, '') + total = `${setSpace(total)}${sum}` + } + return total + }, '') + }) +} diff --git a/packages/devui-vue/devui/grid/src/use-screen.ts b/packages/devui-vue/devui/grid/src/use-screen.ts new file mode 100644 index 0000000000000000000000000000000000000000..98d86f99acbe02fea94eb585b07ba9ec490b8a70 --- /dev/null +++ b/packages/devui-vue/devui/grid/src/use-screen.ts @@ -0,0 +1,84 @@ + +export const RESULT_SCREEN = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'] + +const screenMedias = { + xs: 'screen and (max-width: 575px)', + sm: 'screen and (min-width: 576px)', + md: 'screen and (min-width: 768px)', + lg: 'screen and (min-width: 992px)', + xl: 'screen and (min-width: 1200px)', + xxl: 'screen and (min-width: 1600px)', +} as const + +export interface Screen { + xs?: boolean + sm?: boolean + md?: boolean + lg?: boolean + xl?: boolean + xxl?: boolean +} + +export type ScreenMediasKey = keyof typeof screenMedias +type SubscribeCb = (screen: Screen) => void + +const subscribers = new Map<number, SubscribeCb>() +let subUid = -1 +const screen: Screen = {} +const results: { + [key: string]: { + res: MediaQueryList + listener: (this: MediaQueryList, ev: MediaQueryListEvent) => void + } + } = {}; + +export function responesScreen (func: SubscribeCb) { + if (!subscribers.size) { + register() + } + subUid += 1 + subscribers.set(subUid, func) + func({ ...screen }) + return subUid +} + +export function removeSubscribeCb (id: number) { + subscribers.delete(id) + if (subscribers.size === 0) { + unRegister() + } +} + +function register () { + Object.keys(screenMedias).forEach(key => { + const result = window.matchMedia(screenMedias[key]) + if (result.matches) { + screen[key as ScreenMediasKey] = true + dispatch() + } + const listener = e => { + screen[key as ScreenMediasKey] = e.matches + dispatch() + } + result.addEventListener('change', listener) + + results[key] = { + res: result, + listener + } + }) +} + +function unRegister () { + Object.keys(screenMedias).forEach(key => { + const handler = results[key] + handler.res.removeEventListener('change', handler.listener) + }) + subscribers.clear() +} + +function dispatch () { + subscribers.forEach(value => { + value({ ...screen }) + }) +} diff --git a/packages/devui-vue/devui/icon/__tests__/icon.spec.ts b/packages/devui-vue/devui/icon/__tests__/icon.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..91424ad144ad1dccd13c6259fad610405b318925 --- /dev/null +++ b/packages/devui-vue/devui/icon/__tests__/icon.spec.ts @@ -0,0 +1,30 @@ +import { mount } from '@vue/test-utils'; +import Icon from '../src/icon'; + +describe('d-icon', () => { + it('name', () => { + const wrapper = mount(Icon, { + props: { name:'add' }, + }); + expect(wrapper.find('.icon-add').exists()).toBeTruthy(); + }); + + it('classPrefix', () => { + const wrapper = mount(Icon, { + props: { name:'add',classPrefix:'dev' }, + }); + expect(wrapper.find('.dev-add').exists()).toBeTruthy(); + }); + it('size', () => { + const wrapper = mount(Icon, { + props: { name:'add',size:'80px'}, + }); + expect(wrapper.find('.icon-add').attributes('style').includes('font-size: 80px')).toBeTruthy(); + }); + it('color', () => { + const wrapper = mount(Icon, { + props: { name:'add',color:'red'}, + }); + expect(wrapper.find('.icon-add').attributes('style').includes('color: red')).toBeTruthy(); + }); +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/icon/index.ts b/packages/devui-vue/devui/icon/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..299989544a1fbb26a255defac595845b53d8e72b --- /dev/null +++ b/packages/devui-vue/devui/icon/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Icon from './src/icon' + +Icon.install = function(app: App) { + app.component(Icon.name, Icon) +} + +export { Icon } + +export default { + title: 'Icon 图标', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(Icon as any) + } +} diff --git a/packages/devui-vue/devui/icon/src/icon.tsx b/packages/devui-vue/devui/icon/src/icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..16e4593648a231e06a6a0f133fde0f30d57e70b9 --- /dev/null +++ b/packages/devui-vue/devui/icon/src/icon.tsx @@ -0,0 +1,46 @@ +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'DIcon', + props: { + name: { + type: String, + required: true + }, + size: { + type: String, + default: 'inherit' + }, + color: { + type: String, + default: 'inherit' + }, + classPrefix: { + type: String, + default: 'icon' + }, + }, + setup(props) { + return { + ...props + } + }, + render() { + const { name, size, color, classPrefix } = this + + return ( + <> + { + /^((https?):)?\/\//.test(name) + ? <img src={name} alt={name.split('/')[name.split('/').length - 1]} style={{ + width: size + }} /> + : <i class={`${classPrefix} ${classPrefix}-${name}`} style={{ + fontSize: size, + color + }}></i> + } + </> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/image-preview/__tests__/image-preview.spec.ts b/packages/devui-vue/devui/image-preview/__tests__/image-preview.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..519e4e62b15176d7b55b1b19f9ddc51a3443d28c --- /dev/null +++ b/packages/devui-vue/devui/image-preview/__tests__/image-preview.spec.ts @@ -0,0 +1,87 @@ +import { mount } from '@vue/test-utils' +import { ImagePreviewDirective } from '../index' +import { ref } from 'vue' + +// 指令图片模板 +const imageTemplate = ` + <img id="testImg" src="https://devui.design/components/assets/image1.png" /> + <img src="https://devui.design/components/assets/image3.png" /> +` +// 全局属性 +const global = { + directives: { + dImagePreview: ImagePreviewDirective + } +} + +describe('image-preview', () => { + it('image-preview click', async () => { + const wrapper = mount( + { + template: ` + <div v-d-image-preview> + ${imageTemplate} + </div> + ` + }, + { + global + } + ) + const img = wrapper.find('#testImg') + await img.trigger('click') + const ele = document.querySelector('.devui-image-preview-main-image') + expect(ele).toBeTruthy() + const closeBtn = document.querySelector('.devui-image-preview-close-btn') as any + closeBtn.click() + }) + + it('image-preview disableDefault', async () => { + const wrapper = mount( + { + template: ` + <div v-d-image-preview="{disableDefault: true}"> + ${imageTemplate} + </div> + ` + }, + { + global + } + ) + const img = wrapper.find('#testImg') + await img.trigger('click') + const ele = document.querySelector('.devui-image-preview-main-image') + expect(ele).toBeFalsy() + }) + + it('image-preview custom', async () => { + const custom: any = ref({}) + const open = () => custom.value.open() + const wrapper = mount( + { + template: ` + <div v-d-image-preview="{custom, disableDefault:true}"> + ${imageTemplate} + </div> + <button id="open" @click="open">open</button> + `, + setup() { + return { + custom, + open + } + } + }, + { + global + } + ) + const customBtn = wrapper.find('#open') + await customBtn.trigger('click') + const ele = document.querySelector('.devui-image-preview-main-image') + expect(ele).toBeTruthy() + const closeBtn = document.querySelector('.devui-image-preview-close-btn') as any + closeBtn.click() + }) +}) diff --git a/packages/devui-vue/devui/image-preview/index.ts b/packages/devui-vue/devui/image-preview/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1b883b96668ab2b20fb04b371e6cc8e89f17e15 --- /dev/null +++ b/packages/devui-vue/devui/image-preview/index.ts @@ -0,0 +1,15 @@ +import type { App } from 'vue' +import ImagePreviewDirective from './src/image-preview-directive' +import ImagePreviewService from './src/image-preview-service' + +export { ImagePreviewDirective, ImagePreviewService } + +export default { + title: 'ImagePreview 图片预览', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.directive('d-image-preview', ImagePreviewDirective) + app.config.globalProperties.$imagePreviewService = ImagePreviewService + } +} diff --git a/packages/devui-vue/devui/image-preview/src/image-preview-directive.ts b/packages/devui-vue/devui/image-preview/src/image-preview-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..5317dff6d37f419071351c395870ed25f4420ade --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/image-preview-directive.ts @@ -0,0 +1,52 @@ +import { BindingTypes } from './image-preview-types' +import ImagePreviewService from './image-preview-service' + +function mountedPreviewImages(url: string, urlList: Array<string>): void { + ImagePreviewService.open({ url, previewUrlList: urlList }) +} +function unmountedPreviewImages() { + ImagePreviewService.close() +} + +function getImgByEl(el: HTMLElement): Array<string> { + const urlList = [...el.querySelectorAll('img')].map((item: HTMLImageElement) => + item.getAttribute('src') + ) + return urlList +} + +function handleImgByEl(el: HTMLElement) { + el.addEventListener('click', (e: MouseEvent) => { + e.stopPropagation() + const target = e.target as HTMLElement + if (target?.nodeName?.toLowerCase() === 'img') { + const urlList = getImgByEl(el) + const url = target.getAttribute('src') + mountedPreviewImages(url, urlList) + } + }) +} + +export default { + mounted(el: HTMLElement, binding: BindingTypes | undefined) { + if (!binding.value) { + return handleImgByEl(el) + } + const { custom, disableDefault } = binding.value + // console.log('指令参数:', custom, disableDefault, zIndex, backDropZIndex) + if (custom instanceof Object) { + custom.open = () => { + const urlList = getImgByEl(el) + mountedPreviewImages(urlList?.[0], urlList) + } + custom.close = () => unmountedPreviewImages() + } + if (disableDefault) { + return + } + handleImgByEl(el) + }, + unmounted() { + unmountedPreviewImages() + } +} diff --git a/packages/devui-vue/devui/image-preview/src/image-preview-service.ts b/packages/devui-vue/devui/image-preview/src/image-preview-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd26b5c9e471140e3151f2f5b6941f4f44a6a0b3 --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/image-preview-service.ts @@ -0,0 +1,34 @@ +import { createApp } from 'vue' +import { ImagePreviewProps } from './image-preview-types' +import imagePreview from './image-preview' + +function createComponent(props: ImagePreviewProps) { + return createApp(imagePreview, props) +} + +class ImagePreviewService { + static $body: HTMLElement | null = null + static $div: HTMLDivElement | null = null + // 暂时的禁止滚动穿透,后续应该考虑用modal组件来渲染预览组件 + static $overflow = '' + + static open(props: ImagePreviewProps) { + this.$body = document.body + this.$div = document.createElement('div') + this.$overflow = this.$body.style.overflow + this.$body.appendChild(this.$div) + createComponent(props).mount(this.$div) + + this.$body.style.setProperty('overflow', 'hidden', 'important') + } + static close() { + this.$body?.style.setProperty('overflow', this.$overflow) + this.$overflow = null + + this.$div && this.$body.removeChild(this.$div) + this.$body = null + this.$div = null + } +} + +export default ImagePreviewService diff --git a/packages/devui-vue/devui/image-preview/src/image-preview-types.ts b/packages/devui-vue/devui/image-preview/src/image-preview-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f4053cb665ef1edabc0a59b2d25bb748cc7c945 --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/image-preview-types.ts @@ -0,0 +1,24 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export const imagePreviewProps = { + url: { + type: String, + default: '' + }, + previewUrlList: { + type: Array as PropType<string[]>, + default: () => [] + } +} as const + +export interface BindingTypes { + value: { + custom?: any + disableDefault?: boolean + zIndex?: number + backDropZIndex?: number + } + [key: string]: any +} + +export type ImagePreviewProps = ExtractPropTypes<typeof imagePreviewProps> diff --git a/packages/devui-vue/devui/image-preview/src/image-preview.scss b/packages/devui-vue/devui/image-preview/src/image-preview.scss new file mode 100644 index 0000000000000000000000000000000000000000..28a4f786dd980e419912750b48f772bc6009ef34 --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/image-preview.scss @@ -0,0 +1,115 @@ +@import '../../style/theme/_z-index'; +@import '../../style/theme/_shadow'; +@import '../../style/theme/_color'; +@import '../../style/theme/_corner'; + +.devui-image-preview { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: calc(#{$devui-z-index-modal} - 1); + background: $devui-shadow; + border-radius: $devui-border-radius; + box-shadow: $devui-shadow-length-fullscreen-overlay $devui-shadow; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + + svg, + polygon, + g, + path { + fill: $devui-icon-text; + } + @mixin fixed-button() { + position: fixed; + z-index: $devui-z-index-modal; + cursor: pointer; + width: 36px; + height: 36px; + border-radius: 50%; + background: $devui-highlight-overlay; + box-shadow: $devui-shadow-length-base $devui-light-shadow; + display: inline-flex; + align-items: center; + justify-content: center; + + &:hover { + background: $devui-area; + } + + svg { + width: 38px; + height: 18px; + } + } + + &-main-image { + width: auto; + height: auto; + max-width: 90%; + max-height: 90%; + margin-top: -20px; + cursor: grab; + } + + &-close-btn { + @include fixed-button(); + + top: 15px; + right: 20px; + } + + &-arrow-left { + @include fixed-button(); + + top: 50%; + left: 20px; + transform: translateY(-50%); + } + + &-arrow-right { + @include fixed-button(); + + top: 50%; + right: 20px; + transform: translateY(-50%); + } + + &-toolbar { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + background: $devui-highlight-overlay; + box-shadow: $devui-shadow-length-fullscreen-overlay $devui-light-shadow; + + button { + display: inline-flex; + width: 24px; + height: 24px; + align-items: center; + justify-content: center; + color: $devui-text; + } + + .devui-image-preview-index { + display: inline-flex; + width: 100px; + justify-content: center; + align-items: center; + cursor: pointer; + } + + & > :not(:first-child) { + margin-left: 20px; + } + } +} diff --git a/packages/devui-vue/devui/image-preview/src/image-preview.tsx b/packages/devui-vue/devui/image-preview/src/image-preview.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3076a4e2cd584834a394340c44b9679700c2d76c --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/image-preview.tsx @@ -0,0 +1,192 @@ +import './image-preview.scss' +import { defineComponent, ref, computed, onMounted, onUnmounted } from 'vue' +import { imagePreviewProps, ImagePreviewProps } from './image-preview-types' +import ImagePreviewService from './image-preview-service' +import Transform from './transform' + +export default defineComponent({ + name: 'DImagePreview', + props: imagePreviewProps, + emits: [], + setup(props: ImagePreviewProps) { + let transform: Transform = null + const index = ref(0) + const url = computed(() => props.previewUrlList[index.value]) + + function initTransform() { + const imageElement: HTMLImageElement = document.querySelector( + '.devui-image-preview-main-image' + ) + transform = new Transform(imageElement) + } + function initIndex() { + index.value = props.previewUrlList.findIndex(curUrl => curUrl === props.url) + } + function onPrev() { + index.value = index.value <= 0 ? props.previewUrlList.length - 1 : index.value - 1 + } + function onNext() { + index.value = index.value >= props.previewUrlList.length - 1 ? 0 : index.value + 1 + } + function onClose() { + ImagePreviewService.close() + } + function onZoomIn() { + transform.setZoomIn() + } + function onZoomOut() { + transform.setZoomOut() + } + function onRotate() { + transform.setRotate() + } + function onZoomBest() { + transform.setZoomBest() + } + function onZoomOriginal() { + transform.setZoomOriginal() + } + + function onKeyDown(event:KeyboardEvent) { + if(event.defaultPrevented) return; + + if(event.code == 'Escape') { + onClose(); + }else if(event.code == 'ArrowLeft') { + onPrev(); + }else if(event.code == 'ArrowRight') { + onNext(); + } + } + function initKeyboard() { + document.addEventListener('keydown', onKeyDown, false) + } + function unKeyBoard() { + document.removeEventListener('keydown', onKeyDown, false) + } + + onMounted(() => { + initIndex() + initTransform() + initKeyboard() + }) + onUnmounted(()=>{ + unKeyBoard(); + }) + + return () => { + return ( + <div class="devui-image-preview"> + {/* 预览图 */} + <img class="devui-image-preview-main-image" src={url.value} /> + {/* 按钮区 */} + <button class="devui-image-preview-close-btn" onClick={onClose}> + <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <polygon + fill="#293040" + fill-rule="nonzero" + points="8 6.58578644 12.2426407 2.34314575 13.6568542 3.75735931 9.41421356 8 13.6568542 12.2426407 12.2426407 13.6568542 8 9.41421356 3.75735931 13.6568542 2.34314575 12.2426407 6.58578644 8 2.34314575 3.75735931 3.75735931 2.34314575" + ></polygon> + </g> + </svg> + </button> + <button class="devui-image-preview-arrow-left" onClick={onPrev}> + <svg width="18px" height="18px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <polygon + fill="#293040" + fill-rule="nonzero" + points="10.7071068 12.2928932 9.29289322 13.7071068 3.58578644 8 9.29289322 2.29289322 10.7071068 3.70710678 6.41421356 8" + ></polygon> + </g> + </svg> + </button> + <button class="devui-image-preview-arrow-right" onClick={onNext}> + <svg width="18px" height="18px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <polygon + fill="#293040" + fill-rule="nonzero" + transform="translate(8.146447, 8.000000) scale(-1, 1) translate(-8.146447, -8.000000) " + points="11.7071068 12.2928932 10.2928932 13.7071068 4.58578644 8 10.2928932 2.29289322 11.7071068 3.70710678 7.41421356 8" + ></polygon> + </g> + </svg> + </button> + {/* 底部固定区 */} + <div class="devui-image-preview-toolbar"> + <button onClick={onZoomIn}> + <svg width="18px" height="18px" viewBox="0 0 16 16"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g fill="#293040" fill-rule="nonzero"> + <path d="M6,6 L6,4 L8,4 L8,6 L10,6 L10,8 L8,8 L8,10 L6,10 L6,8 L4,8 L4,6 L6,6 Z M12.6063847,11.1921711 L15.6568542,14.2426407 L14.2426407,15.6568542 L11.1921711,12.6063847 C10.0235906,13.4815965 8.5723351,14 7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,8.5723351 13.4815965,10.0235906 12.6063847,11.1921711 L12.6063847,11.1921711 Z M7,12 C9.76142375,12 12,9.76142375 12,7 C12,4.23857625 9.76142375,2 7,2 C4.23857625,2 2,4.23857625 2,7 C2,9.76142375 4.23857625,12 7,12 Z"></path> + </g> + </g> + </svg> + </button> + <button onClick={onZoomOut}> + <svg width="18px" height="18px" viewBox="0 0 16 16"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g fill="#293040" fill-rule="nonzero"> + <path d="M12.6063847,11.1921711 L15.6568542,14.2426407 L14.2426407,15.6568542 L11.1921711,12.6063847 C10.0235906,13.4815965 8.5723351,14 7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,8.5723351 13.4815965,10.0235906 12.6063847,11.1921711 L12.6063847,11.1921711 Z M7,12 C9.76142375,12 12,9.76142375 12,7 C12,4.23857625 9.76142375,2 7,2 C4.23857625,2 2,4.23857625 2,7 C2,9.76142375 4.23857625,12 7,12 Z M4,6 L10,6 L10,8 L4,8 L4,6 Z"></path> + </g> + </g> + </svg> + </button> + <button onClick={onRotate}> + <svg width="18px" height="18px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path + d="M7.5,3.02242151 L7.5,4 L4.5,2 L7.5,0 L7.5,1.01640228 C7.66526181,1.00552468 7.83198572,1 8,1 C12.1421356,1 15.5,4.35786438 15.5,8.5 C15.5,12.6421356 12.1421356,16 8,16 C3.85786438,16 0.5,12.6421356 0.5,8.5 C0.5,6.9828355 0.950484514,5.5708873 1.72499011,4.39061882 L3.42173231,5.4510827 C2.83944149,6.32371289 2.5,7.37221604 2.5,8.5 C2.5,11.5375661 4.96243388,14 8,14 C11.0375661,14 13.5,11.5375661 13.5,8.5 C13.5,5.46243388 11.0375661,3 8,3 C7.83145515,3 7.66468102,3.00758131 7.5,3.02242151 Z M8,11 C6.61928813,11 5.5,9.88071187 5.5,8.5 C5.5,7.11928813 6.61928813,6 8,6 C9.38071187,6 10.5,7.11928813 10.5,8.5 C10.5,9.88071187 9.38071187,11 8,11 Z M8,10 C8.82842712,10 9.5,9.32842712 9.5,8.5 C9.5,7.67157288 8.82842712,7 8,7 C7.17157288,7 6.5,7.67157288 6.5,8.5 C6.5,9.32842712 7.17157288,10 8,10 Z" + fill="#293040" + ></path> + </g> + </svg> + </button> + <button onClick={onPrev}> + <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <polygon + fill="#293040" + fill-rule="nonzero" + points="10.7071068 12.2928932 9.29289322 13.7071068 3.58578644 8 9.29289322 2.29289322 10.7071068 3.70710678 6.41421356 8" + ></polygon> + </g> + </svg> + </button> + <span class="devui-image-preview-index"> + {index.value + 1}:{props.previewUrlList.length} + </span> + <button class="devui-next" onClick={onNext}> + <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <polygon + fill="#293040" + fill-rule="nonzero" + transform="translate(8.146447, 8.000000) scale(-1, 1) translate(-8.146447, -8.000000) " + points="11.7071068 12.2928932 10.2928932 13.7071068 4.58578644 8 10.2928932 2.29289322 11.7071068 3.70710678 7.41421356 8" + ></polygon> + </g> + </svg> + </button> + <button onClick={onZoomBest}> + <svg width="18px" height="18px" viewBox="0 0 16 16"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path + d="M16,16 L11.429,16 L11.429,15 L14.456,15 L11.006,11.226 L11.652,10.519 L15.086,14.275 L15.086,11 L16,11 L16,16 Z M15.164,1.544 L12.009,4.994 L11.418,4.348 L14.558,0.914 L11.82,0.914 L11.82,0 L16,0 L16,4.571 L15.164,4.571 L15.164,1.544 Z M5,15 L5,16 L0,16 L0,11 L1,11 L1,14.275 L4.756,10.519 L5.463,11.226 L1.689,15 L5,15 Z M4.365,4.994 L0.914,1.544 L0.914,4.571 L3.41060513e-13,4.571 L3.41060513e-13,0 L4.571,0 L4.571,0.914 L1.578,0.914 L5.011,4.348 L4.365,4.994 Z" + fill="#293040" + fill-rule="nonzero" + ></path> + </g> + </svg> + </button> + <button onClick={onZoomOriginal}> + <span>1:1</span> + </button> + </div> + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/image-preview/src/transform.ts b/packages/devui-vue/devui/image-preview/src/transform.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff35f90fab0f2b9b8a46424967c5509bf49e3ee5 --- /dev/null +++ b/packages/devui-vue/devui/image-preview/src/transform.ts @@ -0,0 +1,130 @@ +interface Options { + transformX?: number + transformY?: number + zoom?: number + rotate?: number +} +interface HTMLElementPlus extends HTMLElement { + onmousewheel?: (...args: any[]) => void +} + +export default class Transform { + private el: HTMLElementPlus + + private oTransformX = 0 + private oTransformY = 0 + private transformX: number + private transformY: number + private zoom: number + private rotate: number + + private STEP = 0.25 + private MIN_SCALE = 0.2 + private MAX_SCALE = 2.5 + private TRANSFORMX = 0 + private TRANSFORMY = 0 + private ZOOM = 1 + private ROTATE = 0 + + constructor(el: HTMLElementPlus, options: Options = {}) { + this.el = el + this.transformX = options.transformX || this.TRANSFORMX + this.transformY = options.transformY || this.TRANSFORMY + this.zoom = options.zoom || this.ZOOM + this.rotate = options.rotate || this.ROTATE + + this.handleDefaultDraggable() + this.onDraggable() + this.onMouseWheel() + } + handleDefaultDraggable() { + document.body.ondragstart = () => { + window.event.returnValue = false + return false + } + } + onDraggable() { + this.el.onmousedown = (e: MouseEvent) => { + const ox = e.clientX + const oy = e.clientY + document.onmousemove = (e1: MouseEvent) => { + const disX = e1.clientX - ox + const disY = e1.clientY - oy + this.transformX = this.oTransformX + disX + this.transformY = this.oTransformY + disY + this.el.style.cursor = 'grabbing' + this.setPosition() + } + } + document.onmouseup = () => { + document.onmousemove = null + this.oTransformX = this.transformX + this.oTransformY = this.transformY + this.el.style.cursor = 'grab' + } + } + onMouseWheel() { + const handleWheel = this.throttle(this.setMouseWheel, 100) + this.el.onmousewheel = e => { + const value: number = -e.wheelDelta || e.deltaY || e.detail + handleWheel(value) + } + } + throttle(fn: (...args: any[]) => void, t: number) { + let timer = null + return (...args) => { + if (!timer) { + setTimeout(() => { + timer = null + fn.apply(this, args) + }, t) + } + } + } + setMouseWheel(value: number) { + if (value < 0) { + if (this.zoom >= this.MAX_SCALE) { + this.el.style.cursor = 'not-allowed' + return + } + this.el.style.cursor = 'zoom-in' + this.setZoomIn(this.STEP) + } else { + if (this.zoom <= this.MIN_SCALE) { + this.el.style.cursor = 'not-allowed' + return + } + this.el.style.cursor = 'zoom-out' + this.setZoomOut(this.STEP) + } + this.setPosition() + } + setZoomIn(step = this.STEP) { + this.zoom = Math.min(this.MAX_SCALE, this.zoom + step) + this.setPosition() + } + setZoomOut(step = this.STEP) { + this.zoom = Math.max(this.MIN_SCALE, this.zoom - step) + this.setPosition() + } + setZoomBest() { + this.reset() + this.setPosition() + } + setZoomOriginal() { + this.reset() + this.setPosition() + } + setRotate() { + this.rotate += 0.25 + this.setPosition() + } + reset() { + this.transformX = this.TRANSFORMX + this.transformY = this.TRANSFORMY + this.zoom = this.ZOOM + } + setPosition() { + this.el.style.transform = `translate(${this.transformX}px, ${this.transformY}px) scale(${this.zoom}) rotate(${this.rotate}turn)` + } +} diff --git a/packages/devui-vue/devui/input-number/index.ts b/packages/devui-vue/devui/input-number/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d2fea5f95f76f2dc1b243b8f6c64b5988ccba66e --- /dev/null +++ b/packages/devui-vue/devui/input-number/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import InputNumber from './src/input-number' + +InputNumber.install = function(app: App) { + app.component(InputNumber.name, InputNumber) +} + +export { InputNumber } + +export default { + title: 'InputNumber 数字输入框', + category: '数据录入', + status: '50%', + install(app: App):void { + app.use(InputNumber as any) + } +} diff --git a/packages/devui-vue/devui/input-number/src/input-number-types.ts b/packages/devui-vue/devui/input-number/src/input-number-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dc1b0022333e2a33f10b97b62fefd4653e1df12 --- /dev/null +++ b/packages/devui-vue/devui/input-number/src/input-number-types.ts @@ -0,0 +1,54 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export const inputNumberProps = { + placeholder: { + type: String, + default: undefined + }, + disabled: { + type: Boolean, + default: false + }, + step:{ + type: Number, + default: 0 + }, + max: { + type: Number, + default: Infinity + }, + min: { + type: Number, + default: -Infinity + }, + size: { + type: String, + default: '' + }, + modelValue: { + type: Number, + default: 0 + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: string) => void>, + default: undefined + }, + 'onChange': { + type: Function as PropType<(v: string) => void>, + default: undefined + }, + 'onKeydown': { + type: Function as PropType<(v: KeyboardEvent) => void>, + default: undefined + }, + 'onFocus': { + type: Function as PropType<() => void>, + default: undefined + }, + 'onBlur': { + type: Function as PropType<() => void>, + default: undefined + } +} as const + +export type InputNumberProps = ExtractPropTypes<typeof inputNumberProps> diff --git a/packages/devui-vue/devui/input-number/src/input-number.scss b/packages/devui-vue/devui/input-number/src/input-number.scss new file mode 100644 index 0000000000000000000000000000000000000000..287e4fb55be0ae1e153ec3d984ef6592cf8b2edc --- /dev/null +++ b/packages/devui-vue/devui/input-number/src/input-number.scss @@ -0,0 +1,177 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/font'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; + +.devui-input-number { + position: relative; + display: inline-block; + width: 80px; + line-height: 38px; + margin-right: 12px; + + &:hover:not(.devui-input-disabled) { + .devui-input-box { + border-color: var(--devui-form-control-line-hover); + } + + .devui-control-buttons:not(.disabled) { + display: flex; + border-color: var(--devui-form-control-line-hover); + } + } + + &:focus-within { + .devui-control-buttons { + display: flex; + } + } + + .active { + border: 1px solid var(--devui-form-control-line-active) !important; + display: flex !important; + } + + + &.devui-input-disabled { + .devui-subtract, + .devui-add, + .devui-input-style { + cursor: not-allowed; + border-color: #e4e7ed; + color: #e4e7ed; + } + + .devui-input-style { + border-color: var(--devui-disabled-line) !important; + color: var(--devui-disabled-text) !important; + background-color: var(--devui-disabled-bg) !important; + } + } + + &.devui-input-number-sm { + .devui-subtract, + .devui-add { + width: 40px; + height: 34px; + line-height: 34px; + } + + .devui-input-style { + height: 34px; + line-height: 34px; + } + } + + &.devui-input-number-lg { + .devui-subtract, + .devui-add { + width: 60px; + } + } + + .devui-input-item { + line-height: 100%; + } + + .devui-input-style::-webkit-outer-spin-button, + .devui-input-style::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + .devui-add, + .devui-subtract { + display: inline-block; + width: 50px; + height: 38px; + line-height: 38px; + text-align: center; + font-size: 16px; + color: #333333; + background: #f5f7fa; + cursor: pointer; + border: 1px solid #dcdfe6; + } + + .devui-add { + float: right; + margin-left: -1px; + border-radius: 0 4px 4px 0; + } + + .devui-subtract { + float: left; + margin-right: -1px; + border-radius: 4px 0 0 4px; + } + + .devui-input-style { + display: block; + -moz-appearance: textfield; + } + + .devui-input-style { + outline: none; + background-color: var(--devui-base-bg); + border: 1px solid var(--devui-form-control-line); + border-radius: var(--devui-border-radius); + padding: 4px 8px; + line-height: 18px; + font-size: var(--devui-font-size); + color: var(--devui-text); + width: 100%; + display: block; + cursor: text; + height: 28px; + transition: border-color 0.3s var(--devui-animation-ease-in-out-smooth); + } + + .devui-input-box { + box-sizing: border-box; + padding: 4px 8px; + font-size: var(--devui-font-size); + vertical-align: middle; + border-radius: var(--devui-border-radius); + outline: none; + width: 100%; + line-height: 20px; + height: 28px; + border-width: 1px; + border-style: solid; + + &:not(.disabled) { + background-color: var(--devui-base-bg); + border-color: var(--devui-line); + color: var(--devui-text); + } + } + + .disabled { + cursor: not-allowed; + } + + .devui-control-buttons { + display: none; + position: absolute; + right: 0; + width: 22px; + height: 100%; + flex-direction: column; + justify-content: center; + align-items: center; + border-left: 1px solid var(--devui-line); + box-sizing: border-box; + line-height: 100%; + border-radius: 0 var(--devui-border-radius) var(--devui-border-radius) 0; + + &:not(.disabled) { + cursor: pointer; + } + + & > span { + display: flex; + } + } +} diff --git a/packages/devui-vue/devui/input-number/src/input-number.tsx b/packages/devui-vue/devui/input-number/src/input-number.tsx new file mode 100644 index 0000000000000000000000000000000000000000..842f0a192dfb89ee843ab62355ad78efbca99e43 --- /dev/null +++ b/packages/devui-vue/devui/input-number/src/input-number.tsx @@ -0,0 +1,115 @@ +import { defineComponent, ref, computed } from 'vue'; +import { inputNumberProps, InputNumberProps } from './input-number-types'; +import './input-number.scss'; +import Icon from '../../icon/src/icon'; + +export default defineComponent({ + name: 'DInputNumber', + props: inputNumberProps, + emits: ['update:modelValue', 'change', 'input', 'focus', 'blur', 'keydown'], + setup(props: InputNumberProps, ctx) { + const inputVal = ref(props.modelValue); + + const focusVal = ref(''); + + // 大小 + const isSize = computed(() => { + return `devui-input-number-${props.size}`; + }); + + // 判断是否禁用 + const isDisabled = computed(() => { + return props.disabled; + }); + + //新增 + const add = () => { + if (props.disabled) return; + if (inputVal.value >= props.max) return; + inputVal.value += props.step != 0 ? props.step : 1; + focusVal.value = 'active'; + ctx.emit('change', inputVal.value); + ctx.emit('update:modelValue', inputVal.value); + }; + // 减少 + const subtract = () => { + if (props.disabled) return; + if (inputVal.value <= props.min) return; + inputVal.value -= props.step != 0 ? props.step : 1; + focusVal.value = 'active'; + ctx.emit('change', inputVal.value); + ctx.emit('update:modelValue', inputVal.value); + }; + const onInput = (val) => { + inputVal.value = parseInt(val.data); + ctx.emit('input', val.data); + ctx.emit('update:modelValue', val.data); + }; + const onFocus = ($event: Event) => { + focusVal.value = 'active'; + ctx.emit('focus', $event); + }; + const onBlur = ($event: Event) => { + focusVal.value = ''; + ctx.emit('blur', $event); + }; + const onChange = ($event: Event) => { + ctx.emit('change', ($event.target as HTMLInputElement).value); + }; + const onKeydown = ($event: KeyboardEvent) => { + ctx.emit('keydown', $event); + }; + return { + inputVal, + focusVal, + isDisabled, + isSize, + add, + subtract, + onInput, + onChange, + onKeydown, + onBlur, + onFocus, + }; + }, + render() { + const { + focusVal, + placeholder, + add, + inputVal, + isDisabled, + isSize, + subtract, + onInput, + onChange, + onKeydown, + onBlur, + onFocus, + } = this; + const dInputNum = ['devui-input-number', isDisabled ? 'devui-input-disabled' : '', isSize]; + return ( + <div class={dInputNum}> + <div onBlur={onBlur} tabindex="1" class={['devui-control-buttons', focusVal.value]}> + <span onClick={add}><Icon size="12px" name="chevron-up" ></Icon></span> + <span onClick={subtract}><Icon size="12px" name="chevron-down" ></Icon></span> + </div> + <div class="devui-input-item"> + <input + type="number" + value={inputVal} + placeholder={placeholder} + disabled={isDisabled} + class={['devui-input-style devui-input-box', focusVal.value]} + onInput={onInput} + onChange={onChange} + onFocus={onFocus} + onBlur={onBlur} + onKeydown={onKeydown} + /> + </div> + </div> + ); + }, +}); diff --git a/packages/devui-vue/devui/input/__tests__/input.spec.ts b/packages/devui-vue/devui/input/__tests__/input.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3256372c999522de38624df244eec58974bcf5a5 --- /dev/null +++ b/packages/devui-vue/devui/input/__tests__/input.spec.ts @@ -0,0 +1,129 @@ +import { mount } from '@vue/test-utils'; +import { ref, nextTick } from 'vue'; +import DInput from '../src/input'; + +describe('d-input', () => { + it('d-input render work', async () => { + const value = ref('abc'); + const wrapper = mount({ + components: { DInput }, + template: ` + <d-input v-model:value="value" /> + `, + setup () { + return { + value + }; + } + }); + const input = wrapper.find('input'); + expect(input.attributes('dinput')).toBe('true'); + expect(input.element.value).toBe('abc'); + + await input.setValue('def'); + expect(value.value).toBe('def'); + + value.value = 'thx'; + await nextTick(); + expect(input.element.value).toBe('thx'); + }); + + it('d-input bindEvents work', async () => { + const onChange = jest.fn(), + onFocus = jest.fn(), + onBlur = jest.fn(), + onKeydown = jest.fn(); + const wrapper = mount({ + components: { DInput }, + template: ` + <d-input + @change="onChange" + @focus="onFocus" + @blur="onBlur" + @keydown="onKeydown" /> + `, + setup () { + return { + onChange, + onFocus, + onBlur, + onKeydown + }; + } + }); + const input = wrapper.find('input'); + + await input.trigger('change'); + expect(onChange).toBeCalledTimes(1); + + await input.trigger('focus'); + expect(onFocus).toBeCalledTimes(1); + + await input.trigger('blur'); + expect(onBlur).toBeCalledTimes(1); + + await input.trigger('keydown'); + expect(onKeydown).toBeCalledTimes(1); + }); + + it('d-input disabled work', async () => { + const wrapper = mount(DInput, { + props: { + disabled: false + } + }); + const input = wrapper.find('input'); + expect(input.attributes('disabled')).toBe(undefined); + + await wrapper.setProps({ + disabled: true + }); + expect(input.attributes('disabled')).toBe(''); + }); + + it('d-input error work', async () => { + const wrapper = mount(DInput, { + props: { + error: false + } + }); + const input = wrapper.find('input'); + expect(input.classes()).not.toContain('error'); + + await wrapper.setProps({ + error: true + }); + expect(input.classes()).toContain('error'); + }); + + it('d-input size work', async () => { + const wrapper = mount(DInput); + const input = wrapper.find('input'); + expect(input.classes()).not.toContain('devui-input-sm'); + expect(input.classes()).not.toContain('devui-input-lg'); + + await wrapper.setProps({ + size: 'sm' + }); + expect(input.classes()).toContain('devui-input-sm'); + expect(input.classes()).not.toContain('devui-input-lg'); + + await wrapper.setProps({ + size: 'lg' + }); + expect(input.classes()).not.toContain('devui-input-sm'); + expect(input.classes()).toContain('devui-input-lg'); + }); + + it('d-input showPassword work', async () => { + const wrapper = mount(DInput); + const input = wrapper.find('input'); + + expect(input.attributes('type')).toBe('text'); + + await wrapper.setProps({ + showPassword: true + }); + expect(input.attributes('type')).toBe('password'); + }); +}); diff --git a/packages/devui-vue/devui/input/index.ts b/packages/devui-vue/devui/input/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd150ad09f121fee8565982445dd2ff05f7b2fab --- /dev/null +++ b/packages/devui-vue/devui/input/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Input from './src/input' + +Input.install = function(app: App) { + app.component(Input.name, Input) +} + +export { Input } + +export default { + title: 'Input 输入框', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(Input as any) + } +} diff --git a/packages/devui-vue/devui/input/src/input.scss b/packages/devui-vue/devui/input/src/input.scss new file mode 100644 index 0000000000000000000000000000000000000000..9f8397d3df2b1e59327e454a49c85399c8c5e7a6 --- /dev/null +++ b/packages/devui-vue/devui/input/src/input.scss @@ -0,0 +1,21 @@ +@import '../../style/core/form'; +@import '../../style/mixins/flex'; + +.devui-input { + &__wrap { + position: relative; + @include flex('space-between'); + } + + &__preview { + position: absolute; + width: 32px; + height: 16px; + right: 0; + text-align: center; + line-height: 16px; + cursor: pointer; + @include flex; + @include flex-direction; + } +} diff --git a/packages/devui-vue/devui/input/src/input.tsx b/packages/devui-vue/devui/input/src/input.tsx new file mode 100644 index 0000000000000000000000000000000000000000..22822ede377485f02af997e2424d0e5e178ca86e --- /dev/null +++ b/packages/devui-vue/devui/input/src/input.tsx @@ -0,0 +1,120 @@ +import { defineComponent, computed, ref, watch, nextTick, onMounted, toRefs, inject } from 'vue'; +import { inputProps, InputType } from './use-input'; +import './input.scss' +import { dFormItemEvents, IFormItem, formItemInjectionKey } from '../../form/src/form-types'; + +export default defineComponent({ + name: 'DInput', + directives: { + focus: { + mounted: function (el, binding) { + if (binding.value) { + el.focus() + } + } + } + }, + props: inputProps, + emits: ['update:value', 'focus', 'blur', 'change', 'keydown'], + setup(props, ctx) { + const formItem = inject(formItemInjectionKey, {} as IFormItem); + const hasFormItem = Object.keys(formItem).length > 0; + const sizeCls = computed(() => `devui-input-${props.size}`); + const showPwdIcon = ref(false) + const inputType = ref<InputType>('text') + const inputCls = computed(() => { + return { + error: props.error, + [props.cssClass]: true, + [sizeCls.value]: props.size !== '' + } + }) + const showPreviewIcon = computed(() => inputType.value === 'password') + watch(() => props.showPassword, flg => { + inputType.value = flg ? 'password' : 'text' + }, { immediate: true }) + + watch(() => props.value, value => { + (value && value.length > 0 && showPreviewIcon.value) ? showPwdIcon.value = true : showPwdIcon.value = false + }) + + const onInput = ($event: Event) => { + ctx.emit('update:value', ($event.target as HTMLInputElement).value); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.input); + }, + onFocus = () => { + ctx.emit('focus'); + }, + onBlur = () => { + ctx.emit('blur'); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.blur); + }, + onChange = ($event: Event) => { + ctx.emit('change', ($event.target as HTMLInputElement).value); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.change); + }, + onKeydown = ($event: KeyboardEvent) => { + ctx.emit('keydown', $event); + }, + onChangeInputType = () => { + inputType.value = inputType.value === 'password' ? 'text' : 'password' + } + return { + inputCls, + inputType, + showPreviewIcon, + showPwdIcon, + onInput, + onFocus, + onBlur, + onChange, + onKeydown, + onChangeInputType + }; + }, + render () { + const { + value, + showPreviewIcon, + showPwdIcon, + inputCls, + inputType, + maxLength, + autoFocus, + placeholder, + disabled, + onInput, + onFocus, + onBlur, + onChange, + onKeydown, + onChangeInputType, + } = this; + return ( + <div class="devui-input__wrap"> + <input + v-focus={autoFocus} + {...{dinput: true}} + value={value} + disabled={disabled} + type={inputType} + maxlength={maxLength} + placeholder={placeholder} + class={inputCls} + onInput={onInput} + onFocus={onFocus} + onBlur={onBlur} + onChange={onChange} + onKeydown={onKeydown} + /> + { + showPwdIcon && <div class="devui-input__preview" onClick={onChangeInputType}> + { showPreviewIcon + ? <d-icon name="preview" size="12px" key={1}/> + : <d-icon name="preview-forbidden" size="12px" key={2} /> + } + </div>} + </div> + ); + } +}); diff --git a/packages/devui-vue/devui/input/src/use-input.tsx b/packages/devui-vue/devui/input/src/use-input.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5706ad2774fdfe141ad03ea954b0897d7d274e41 --- /dev/null +++ b/packages/devui-vue/devui/input/src/use-input.tsx @@ -0,0 +1,63 @@ +import { PropType } from 'vue'; + +export const inputProps = { + placeholder: { + type: String, + default: undefined + }, + disabled: { + type: Boolean, + default: false + }, + autoFocus: { + type: Boolean, + default: false + }, + maxLength: { + type: Number, + default: Number.MAX_SAFE_INTEGER + }, + cssClass: { + type: String, + default: '' + }, + error: { + type: Boolean, + default: false + }, + size: { + type: String as PropType<'sm' | '' | 'lg'>, + default: '' + }, + showPassword: { + type: Boolean, + default: false + }, + value: { + type: String, + default: '' + }, + 'onUpdate:value': { + type: Function as PropType<(v: string) => void>, + default: undefined + }, + 'onChange': { + type: Function as PropType<(v: string) => void>, + default: undefined + }, + 'onKeydown': { + type: Function as PropType<(v: KeyboardEvent) => void>, + default: undefined + }, + 'onFocus': { + type: Function as PropType<() => void>, + default: undefined + }, + 'onBlur': { + type: Function as PropType<() => void>, + default: undefined + } +} as const; + +export type PreviewIconType = 'preview' | 'icon-preview-forbidden' +export type InputType = 'password' | 'text' diff --git a/packages/devui-vue/devui/layout/index.ts b/packages/devui-vue/devui/layout/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f6ec9b64e061adaa7b5ba0c648f8320950fbacf --- /dev/null +++ b/packages/devui-vue/devui/layout/index.ts @@ -0,0 +1,41 @@ +import type { App } from 'vue' +import Layout from './src/layout' +import Content from './src/content' +import Header from './src/header' +import Footer from './src/footer' +import Aside from './src/aside' + +Layout.install = function(app: App): void { + app.component(Layout.name, Layout) +} + +Content.install = function(app: App): void { + app.component(Content.name, Content) +} + +Header.install = function(app: App): void { + app.component(Header.name, Header) +} + +Footer.install = function(app: App): void { + app.component(Footer.name, Footer) +} + +Aside.install = function(app: App): void { + app.component(Aside.name, Aside) +} + +export { Layout, Content, Header, Footer, Aside } + +export default { + title: 'Layout 布局', + category: '布局', + status: '已完成', + install(app: App): void { + app.use(Layout as any) + app.use(Content as any) + app.use(Header as any) + app.use(Footer as any) + app.use(Aside as any) + } +} diff --git a/devui/tags/tags.tsx b/packages/devui-vue/devui/layout/src/aside.tsx similarity index 41% rename from devui/tags/tags.tsx rename to packages/devui-vue/devui/layout/src/aside.tsx index 431486ed3e6e413436c8f2a5e1920319d3688e17..ca650fdce7a02e0250020ba5b6a9931bdb4e6932 100644 --- a/devui/tags/tags.tsx +++ b/packages/devui-vue/devui/layout/src/aside.tsx @@ -1,12 +1,8 @@ import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-tags', - props: { - }, - setup(props, ctx) { - return () => { - return <div>devui-tags</div> + name: 'DAside', + setup (props, { slots }) { + return () => <div>{ slots.default?.() }</div> } - } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/layout/src/content.scss b/packages/devui-vue/devui/layout/src/content.scss new file mode 100644 index 0000000000000000000000000000000000000000..3314b4c4a32fae514875e62fffca49623642b211 --- /dev/null +++ b/packages/devui-vue/devui/layout/src/content.scss @@ -0,0 +1,4 @@ +.devui-content { + flex: auto; + min-height: 0; +} diff --git a/devui/accordion/demo/accordion-demo.tsx b/packages/devui-vue/devui/layout/src/content.tsx similarity index 34% rename from devui/accordion/demo/accordion-demo.tsx rename to packages/devui-vue/devui/layout/src/content.tsx index b39252ff123cfb75e8a5abfbb9d28a38c16d6292..d2caaecd191a5cd7be7dd29c0361bd14d2a519e4 100644 --- a/devui/accordion/demo/accordion-demo.tsx +++ b/packages/devui-vue/devui/layout/src/content.tsx @@ -1,12 +1,10 @@ +import './content.scss' + import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-accordion-demo', - props: { - }, - setup(props, ctx) { - return () => { - return <div>devui-accordion-demo</div> + name: 'DContent', + setup (props, { slots }) { + return () => <div class="devui-content">{slots.default?.()}</div> } - } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/layout/src/footer.scss b/packages/devui-vue/devui/layout/src/footer.scss new file mode 100644 index 0000000000000000000000000000000000000000..eeec01542b9c1b59694b0ba7f41cac854001deb2 --- /dev/null +++ b/packages/devui-vue/devui/layout/src/footer.scss @@ -0,0 +1,4 @@ +.devui-footer { + text-align: center; + line-height: 1.5; +} diff --git a/devui/select/select.tsx b/packages/devui-vue/devui/layout/src/footer.tsx similarity index 35% rename from devui/select/select.tsx rename to packages/devui-vue/devui/layout/src/footer.tsx index e011365d12a0dbb5f05e92e1df2b56a332bba62f..457ae984d5cb1445eccdef516289deb5ff2d1c16 100644 --- a/devui/select/select.tsx +++ b/packages/devui-vue/devui/layout/src/footer.tsx @@ -1,13 +1,10 @@ +import './footer.scss' import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-select', - props: { - }, - setup(props, ctx) { - return () => { - return <div>devui-select</div> + name: 'DFooter', + setup (props, { slots }) { + return () => <div class="devui-footer">{ slots.default?.() }</div> } - } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/layout/src/header.scss b/packages/devui-vue/devui/layout/src/header.scss new file mode 100644 index 0000000000000000000000000000000000000000..ada90cec6937ac6c43ed337614a850a8ef97047b --- /dev/null +++ b/packages/devui-vue/devui/layout/src/header.scss @@ -0,0 +1,4 @@ +.devui-header { + min-height: 40px; + flex: auto; +} diff --git a/devui/alert/demo/alert-demo.tsx b/packages/devui-vue/devui/layout/src/header.tsx similarity index 34% rename from devui/alert/demo/alert-demo.tsx rename to packages/devui-vue/devui/layout/src/header.tsx index c7b6550df24b2a695b49dbf1217415027a34c02f..e723aff3ab2739d1a531488adf9e9e5c15ab74d0 100644 --- a/devui/alert/demo/alert-demo.tsx +++ b/packages/devui-vue/devui/layout/src/header.tsx @@ -1,12 +1,10 @@ +import './header.scss' + import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-alert-demo', - props: { - }, - setup(props, ctx) { - return () => { - return <div>devui-alert-demo</div> + name: 'DHeader', + setup (props, { slots }) { + return () => <div class="devui-header">{ slots.default?.() }</div> } - } }) \ No newline at end of file diff --git a/packages/devui-vue/devui/layout/src/layout.scss b/packages/devui-vue/devui/layout/src/layout.scss new file mode 100644 index 0000000000000000000000000000000000000000..a513015a70c270042dd23c04c685eb5178a42cde --- /dev/null +++ b/packages/devui-vue/devui/layout/src/layout.scss @@ -0,0 +1,9 @@ +.devui-layout { + display: flex; + flex-direction: column; + flex: auto; + + &-aside { + flex-direction: row; + } +} diff --git a/packages/devui-vue/devui/layout/src/layout.tsx b/packages/devui-vue/devui/layout/src/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..da9306451c60461b82b6fc4f1ba3a2c48dafcbda --- /dev/null +++ b/packages/devui-vue/devui/layout/src/layout.tsx @@ -0,0 +1,16 @@ +import './layout.scss' + +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'DLayout', + emits: [], + setup(props, { slots }) { + return () => { + const slotDefault = slots.default?.() + const isAside = slotDefault.some(item => (item.type as any).name === 'DAside') + const classNames = `${isAside ? 'devui-layout-aside ': ''}devui-layout` + return <div class={classNames}>{ slotDefault }</div> + } + } +}) diff --git a/packages/devui-vue/devui/loading/__tests__/loading.spec.ts b/packages/devui-vue/devui/loading/__tests__/loading.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e6030a3b51d5ba4c7def22e864169d0cee6ec42 --- /dev/null +++ b/packages/devui-vue/devui/loading/__tests__/loading.spec.ts @@ -0,0 +1,320 @@ +/* eslint-disable */ +import { mount } from '@vue/test-utils'; +import { ref, Ref, nextTick, h, shallowReactive } from 'vue'; +import { LoadingService, Loading } from '../index'; + +// 全局属性 +const globalOption = { + directives: { + dLoading: Loading + } +} + +describe('Loading as directive', () => { + it('loading init render', async () => { + const wrapper = mount( + { + template: `<div v-dLoading="true"></div>` + }, + { + global: globalOption + } + ) + + await nextTick() + const loadingEl = wrapper.find('.devui-loading-contanier') + expect(loadingEl.exists()).toBeTruthy() + const loadingMask = wrapper.find('.devui-loading-mask') + expect(loadingMask.exists()).toBeTruthy() + }) + + it('loading test mask', async () => { + const wrapper = mount( + { + template: `<div v-dLoading="true" :backdrop="false"></div>` + }, + { + global: globalOption + } + ) + + const loadingMask = wrapper.find('.devui-loading-mask') + expect(loadingMask.exists()).toBeFalsy() + }) + + it('loading test positionType', async () => { + const wrapper = mount( + { + template: `<div v-dLoading="true" id="testLoading" positionType="absolute"></div>` + }, + { + global: globalOption + } + ) + + const loadingPType: any = wrapper.find('#testLoading') + expect(loadingPType).toBeTruthy() + // @_ts-ignore + // 不支持`ts-ignore`,强行修改确保eslint通过。@mrundef-210810 + const targetEle = (loadingPType as any).wrapperElement.instance.vnode.el + expect(targetEle.parentNode.style.position).toEqual('absolute') + }) + + it('loading test loadingTemplateRef', async () => { + const wrapper = mount( + { + template: `<div v-dLoading="true" id="testLoading" :loadingTemplateRef="ele"></div>`, + data() { + return { + ele: h('div', { + className: 'test-component' + }, '正在加载中...') + } + } + }, + { + global: globalOption + } + ) + + await nextTick() + const loadingComp = wrapper.find('.test-component') + expect(loadingComp.exists()).toBeTruthy() + expect(loadingComp.text()).toEqual('正在加载中...') + + const loadingContainer = wrapper.find('.devui-loading-wrapper') + expect(loadingContainer.exists()).toBeFalsy() + }) + + it('loading test vLoading', async () => { + const wrapper = mount( + { + template: ` + <div> + <button id="testbtn" @click="click"></button> + <div v-dLoading="isShow"></div> + </div> + `, + setup() { + const isShow = ref(false) + const click = () => { + isShow.value = !isShow.value + } + return { + isShow, + click + } + } + }, + { + global: globalOption + } + ) + + await nextTick() + const loadingContainer = wrapper.find('.devui-loading-contanier') + expect(loadingContainer.exists()).toBeFalsy() + const btn = wrapper.find('#testbtn') + expect(btn.exists()).toBeTruthy() + + await btn.trigger('click') + expect(wrapper.find('.devui-loading-contanier').exists()).toBeTruthy() + + await btn.trigger('click') + expect(wrapper.find('.devui-loading-contanier').exists()).toBeFalsy() + + }) + + it('loading test Promise', async () => { + const wrapper = mount( + { + template: ` + <div> + <button id="testbtn" @click="click"></button> + <div v-dLoading="loading" id="testLoading"></div> + </div> + `, + setup() { + const loading: Ref<Promise<any> | undefined | boolean> = ref(false) + + const click = () => { + loading.value = new Promise((res: any) => { + res(111) + }) + } + + return { + loading, + click + } + } + }, + { + global: globalOption + } + ) + + const btn = wrapper.find('#testbtn') + expect(btn.exists()).toBeTruthy() + + await btn.trigger('click') + expect(wrapper.find('.devui-loading-wrapper').exists()).toBeTruthy() + // TODO 组件移除是在finally内部移除,在微任务队列末尾,这里好像检测不到 + setTimeout(() => { + expect(wrapper.find('.devui-loading-wrapper').exists()).toBeFalsy() + }) + }) + + it('loading test mutiple Promise', async () => { + const wrapper = mount( + { + template: ` + <div> + <button id="testbtn" @click="fetchMutiplePromise"></button> + <div v-dLoading="promises.value" id="testLoading"></div> + </div> + `, + setup() { + const promises: any = shallowReactive({ + value: [] + }) + const fetchMutiplePromise = () => { + const list = [] + for (let i = 0; i < 3; i++) { + list.push(new Promise((res: any) => { + res(true) + })) + } + promises.value = list + } + + return { + fetchMutiplePromise, + promises + } + } + }, + { + global: globalOption + } + ) + + await nextTick() + const btn = wrapper.find('#testbtn') + expect(btn.exists()).toBeTruthy() + + await btn.trigger('click') + expect(wrapper.find('.devui-loading-wrapper').exists()).toBeTruthy() + // TODO 组件移除是在finally内部移除,在微任务队列末尾,这里好像检测不到 + setTimeout(() => { + expect(wrapper.find('.devui-loading-wrapper').exists()).toBeFalsy() + }) + }) +}) + +describe('Loading as Service', () => { + it('service init', async () => { + const loading = LoadingService.open() + + await nextTick() + const ele = document.querySelector('.devui-loading-contanier') + expect(ele).toBeTruthy() + expect(ele.parentNode == document.body).toBe(true) + + loading.loadingInstance.close() + await nextTick() + const ele2 = document.querySelector('.devui-loading-contanier') + expect(ele2).toBe(null) + }) + + it('service target', async () => { + const div = document.createElement('div') + document.body.appendChild(div) + + const loading = LoadingService.open({ + target: div + }) + + await nextTick() + const ele = document.querySelector('.devui-loading-contanier') + expect(ele).toBeTruthy() + expect(ele.parentNode === div).toBe(true) + + loading.loadingInstance.close() + }) + + it('service message', async () => { + const loading = LoadingService.open({ + message: '正在加载中...' + }) + + await nextTick() + const ele = document.querySelector('.devui-loading-contanier') + expect(ele).toBeTruthy() + expect(ele.textContent).toBe('正在加载中...') + + loading.loadingInstance.close() + }) + + it('service Style', async () => { + const loading = LoadingService.open({ + positionType: 'absolute', + view: { + top: '40%', + left: '60%' + }, + zIndex: 1000 + }) + + await nextTick() + const ele = document.querySelector('.devui-loading-contanier') + expect(ele).toBeTruthy() + // @_ts-ignore + // 不支持`ts-ignore`,强行修改确保eslint通过。@mrundef-210810 + expect((ele.parentNode as any).style.position).toBe('absolute') + + const loadingEle = ele.querySelector('.devui-loading-area') + // @_ts-ignore + // 不支持`ts-ignore`,强行修改确保eslint通过。@mrundef-210810 + const style = (loadingEle as any).style + expect(style.top).toBe('40%') + expect(style.left).toBe('60%') + expect(style.zIndex).toBe('1000') + + loading.loadingInstance.close() + }) + + it('service template', async () => { + const loading = LoadingService.open({ + loadingTemplateRef: h('div', { + className: 'test-class' + }, '正在加载中') + }) + + await nextTick() + const ele = document.querySelector('.test-class') + expect(ele).toBeTruthy() + expect(ele.textContent).toBe('正在加载中') + + const originEle = document.querySelector('.devui-loading-wrapper') + expect(originEle).toBeFalsy() + + loading.loadingInstance.close() + }) + + it('service mask', async () => { + const loading = LoadingService.open({ + backdrop: false + }) + + await nextTick() + + const wrapper = document.querySelector('.devui-loading-wrapper') + const mask = document.querySelector('.devui-loading-mask') + + expect(wrapper).toBeTruthy() + expect(mask).toBeFalsy() + + loading.loadingInstance.close() + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/loading/index.ts b/packages/devui-vue/devui/loading/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..61cf3112a442ed78bc2ccc146c35a1d7cc8f14b1 --- /dev/null +++ b/packages/devui-vue/devui/loading/index.ts @@ -0,0 +1,18 @@ +import { App } from 'vue' +import Loading from './src/directive' +import LoadingService from './src/service' + +export { + LoadingService, + Loading +} + +export default { + title: 'Loading 加载提示', + category: '反馈', + status: '已完成', + install(app: App): void { + app.directive('dLoading', Loading) + app.config.globalProperties.$loadingService = LoadingService + } +} diff --git a/packages/devui-vue/devui/loading/src/directive.ts b/packages/devui-vue/devui/loading/src/directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..859a61560ad63b0caaf5e1ff467a4c502989abc7 --- /dev/null +++ b/packages/devui-vue/devui/loading/src/directive.ts @@ -0,0 +1,138 @@ +/* eslint-disable */ +import { defineComponent } from 'vue' +import Loading from './loading' +import { LoadingProps, BindingType, TargetHTMLElement } from './types' + +import { createComponent, unmountComponent } from '../../shared/scripts/component' + +const loadingConstructor = defineComponent(Loading) + +const cacheInstance = new WeakSet() + +const isEmpty = (val: any) => { + if (!val) return true + + if (Array.isArray(val)) return val.length === 0 + + if (val instanceof Set || val instanceof Map) return val.size === 0 + + if (val instanceof Promise) return false + + if (typeof val === 'object') { + try { + return Object.keys(val).length === 0 + } catch(e) { + return false + } + } + + return false +} + +const getType = (vari: any) => { + return Object.prototype.toString.call(vari).slice(8, -1).toLowerCase() +} + +const isPromise = (value: any) => { + const type = getType(value) + + switch(type) { + case 'promise': + return [value] + case 'array': + if (value.some((val: any) => getType(val) !== 'promise')) { + console.error(new TypeError('Binding values should all be of type Promise')) + return 'error' + } + return value + default: + return false + } +} + +const unmount = (el: TargetHTMLElement) => { + cacheInstance.delete(el) + el.instance.proxy.close() + unmountComponent(el.instance) +} + +const toggleLoading = (el: TargetHTMLElement, binding: BindingType) => { + if (binding.value) { + const vals: Promise<any>[] | false | 'error' = isPromise(binding.value) + if (vals === 'error') return + + el.instance.proxy.open() + el.appendChild(el.mask!) + cacheInstance.add(el) + + if (vals) { + Promise.all(vals) + // eslint不允许空的then执行体 @mrundef-210810 + // .then((res: Array<boolean>) => { + // }) + .catch((err: any) => { + console.error(new Error('Promise handling errors'), err) + }).finally(() => { + unmount(el) + }) + } + } else { + unmount(el) + } +} + +const removeAttribute = (el: TargetHTMLElement) => { + el.removeAttribute('zindex') + el.removeAttribute('positiontype') + el.removeAttribute('backdrop') + el.removeAttribute('message') + el.removeAttribute('view') + el.removeAttribute('loadingtemplateref') +} + +const handleProps = (el: TargetHTMLElement, vprops: LoadingProps) => { + const props = { + ...new LoadingProps(), + ...vprops + } + + const loadingTemplateRef = props.loadingTemplateRef + + const loadingInstance = createComponent( + loadingConstructor, + { ...props }, + loadingTemplateRef ? () => loadingTemplateRef : null + ) + + el.style.position = props.positionType! + el.options = props + el.instance = loadingInstance + el.mask = loadingInstance.proxy.$el +} + +const loadingDirective = { + mounted: function (el: TargetHTMLElement, binding: BindingType, vnode: any) { + + handleProps(el, vnode.props) + + removeAttribute(el) + + !isEmpty(binding.value) && toggleLoading(el, binding) + }, + + updated: function (el: TargetHTMLElement, binding: BindingType, vnode: any) { + + if ((!isEmpty(binding.value) && cacheInstance.has(el)) || + (isEmpty(binding.value) && !cacheInstance.has(el))) return + + !cacheInstance.has(el) && handleProps(el, vnode.props) + + removeAttribute(el) + + toggleLoading(el, binding) + }, + // eslint不允许控的unmounted执行体 + // unmounted: function () { } +} + +export default loadingDirective diff --git a/packages/devui-vue/devui/loading/src/loading.scss b/packages/devui-vue/devui/loading/src/loading.scss new file mode 100644 index 0000000000000000000000000000000000000000..025dc9e6569013bb2d6fbf6364f80ba99d2f7614 --- /dev/null +++ b/packages/devui-vue/devui/loading/src/loading.scss @@ -0,0 +1,106 @@ +@import '../../style/theme/color'; + +@keyframes devui-busy-spinner-anim { + 0% { + transform: + rotate(0deg) + scale(1); + } + + 50% { + transform: + rotate(135deg) + scale(1.5); + } + + to { + transform: + rotate(270deg) + scale(1); + } +} + +.devui-loading-mask { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + background-color: $devui-line; + opacity: 0.3; +} + +.devui-loading-wrapper { + text-align: center; +} + +.devui-loading--full { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 9999; +} + +.devui-loading--hidden { + overflow: hidden; +} + +.devui-loading-text { + margin-left: 10px; +} + +// 默认加载样式 +.devui-loading-area { + position: absolute; + transform: translate(-50%, -50%); + padding: 12px 14px; + background: var(--devui-base-bg, #ffffff); + border-radius: var(--devui-border-radius-card, 6px); +} + +.devui-busy-default-spinner { + position: relative; + display: inline-block; + width: 15px; + height: 15px; + animation: devui-busy-spinner-anim 1s linear infinite; + + div { + position: absolute; + left: 44.5%; + top: 37%; + width: 6px; + height: 6px; + border-radius: 50%; + } + + .devui-loading-bar1 { + top: 0; + left: 0; + background: #5e7ce0; + background: var(--devui-brand, #5e7ce0); + } + + .devui-loading-bar2 { + top: 0; + left: 9px; + background: #859bff; + background: var(--devui-brand-foil, #859bff); + } + + .devui-loading-bar3 { + top: 9px; + left: 0; + background: #859bff; + background: var(--devui-brand-foil, #859bff); + } + + .devui-loading-bar4 { + top: 9px; + left: 9px; + background: #5e7ce0; + background: var(--devui-brand, #5e7ce0); + } +} diff --git a/packages/devui-vue/devui/loading/src/loading.tsx b/packages/devui-vue/devui/loading/src/loading.tsx new file mode 100644 index 0000000000000000000000000000000000000000..60234c0a460ca58b4b38b916211015f5ed7582a2 --- /dev/null +++ b/packages/devui-vue/devui/loading/src/loading.tsx @@ -0,0 +1,76 @@ +import { CSSProperties, defineComponent, ref } from 'vue' +import { componentProps, ComponentProps } from './types' + +import './loading.scss'; + +export default defineComponent({ + name: 'DLoading', + inheritAttrs: false, + props: componentProps, + setup(props: ComponentProps) { + + const style: CSSProperties = { + top: props.view.top, + left: props.view.left, + zIndex: props.zIndex + } + if (!props.message) { + style.background = 'none' + } + const isShow = ref(false) + + const open = () => { + isShow.value = true + } + + const close = () => { + isShow.value = false + } + + return { + style, + isShow, + open, + close + } + }, + render() { + const { + isShow, + isFull, + backdrop, + style, + message, + $slots + } = this + + return ( + isShow && + <div class={['devui-loading-contanier', isFull ? 'devui-loading--full' : '']}> + { + $slots.default?.() || + <div class="devui-loading-wrapper"> + { + backdrop + ? <div class="devui-loading-mask"></div> + : null + } + <div style={style} class="devui-loading-area"> + <div class="devui-busy-default-spinner"> + <div class="devui-loading-bar1"></div> + <div class="devui-loading-bar2"></div> + <div class="devui-loading-bar3"></div> + <div class="devui-loading-bar4"></div> + </div> + { + message + ? <span class="devui-loading-text">{message}</span> + : null + } + </div> + </div> + } + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/loading/src/service.ts b/packages/devui-vue/devui/loading/src/service.ts new file mode 100644 index 0000000000000000000000000000000000000000..76517e341f569d1fe131c756eb85b6ef1f2d7026 --- /dev/null +++ b/packages/devui-vue/devui/loading/src/service.ts @@ -0,0 +1,55 @@ +/* eslint-disable */ +import { defineComponent } from 'vue' +import { createComponent } from '../../shared/scripts/component' +import Loading from './loading' + +import { LoadingProps } from './types' + +const loadingConstructor = defineComponent(Loading) + +interface TargetElement extends Element { + style ?: any +} + +const cacheTarget = new WeakMap() + +const loading = { + open(options: LoadingProps = {}) { + + const parent: TargetElement = options.target || document.body + + if (cacheTarget.has(parent)) { + return cacheTarget.get(parent) + } + + parent.style.position = options.positionType + + const isFull = document.body === parent + + options = {...new LoadingProps(), ...options} + + const instance = createComponent(loadingConstructor, { + ...options, + isFull + }, options.loadingTemplateRef ? () => options.loadingTemplateRef : null) + + cacheTarget.set(parent, instance) + + instance.proxy.open() + parent.appendChild(instance.proxy.$el) + + const close = instance.proxy.close + instance.loadingInstance = instance.proxy + instance.loadingInstance.close = (...args: any[]) => { + cacheTarget.delete(parent) + // 1. 箭头函数内部并没有内置arguments对象 @mrundef-210810 + // 2. 如果没有上下文要求`apply(null)`,不必使用apply/call + // close.apply(null, arguments) + close(...args) + } + + return instance + } +} + +export default loading \ No newline at end of file diff --git a/packages/devui-vue/devui/loading/src/types.ts b/packages/devui-vue/devui/loading/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..32e3dd03d3623d49553916c6e92c87968233c172 --- /dev/null +++ b/packages/devui-vue/devui/loading/src/types.ts @@ -0,0 +1,45 @@ +import { ExtractPropTypes, PropType, VNode } from 'vue' + +type PositionType = 'static' | 'relative' | 'absolute' | 'fixed' |'sticky' + +export interface LoadingType { + value: Promise<any> | Array<Promise<any>> | undefined +} +export interface BindingType extends LoadingType { + [key: string] : any +} +export interface TargetHTMLElement extends HTMLElement { + mask ?: HTMLElement + instance ?: VNode | any + options ?: LoadingProps +} + +class View { + top ?: string = '50%' + left?: string = '50%' +} +export const componentProps = { + message: String, + backdrop: Boolean, + view: { + type: Object as PropType<View>, + default: () => (new View()) + }, + zIndex: Number, + isFull: { + type: Boolean, + default: false + } +} as const + +export class LoadingProps { + target ?: Element | null + message ?: string + loadingTemplateRef ?: any + backdrop ?: boolean = true + positionType ?: PositionType = 'relative' + view ?: View = new View() + zIndex ?: number +} + +export type ComponentProps = ExtractPropTypes<typeof componentProps> \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/index.ts b/packages/devui-vue/devui/modal/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..806c2cc7d6e473fe6230d838cc2845e0abaf750f --- /dev/null +++ b/packages/devui-vue/devui/modal/index.ts @@ -0,0 +1,34 @@ +import type { App } from 'vue' +import Modal from './src/modal' +import { ModalService } from './src/services/modal-service' +import { DialogService } from './src/services/dialog-service' +import { inBrowser } from '../shared/util/common-var' + +Modal.install = function(app: App): void { + app.component(Modal.name, Modal) +} + +export { Modal } + +export default { + title: 'Modal 弹窗', + category: '反馈', + status: '已完成', + install(app: App): void { + app.use(Modal as any) + + if (!inBrowser) { + return; + } + + let anchorsContainer = document.getElementById('d-modal-anchors-container'); + if (!anchorsContainer) { + anchorsContainer = document.createElement('div'); + anchorsContainer.setAttribute('id', 'd-modal-anchors-container'); + document.body.appendChild(anchorsContainer); + } + // 新增 modalService + app.provide(ModalService.token, new ModalService(anchorsContainer)); + app.provide(DialogService.token, new DialogService(anchorsContainer)); + } +} diff --git a/packages/devui-vue/devui/modal/src/dialog-types.ts b/packages/devui-vue/devui/modal/src/dialog-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbae5c5eae7c0d627d5fe978842a5f99c557ee7d --- /dev/null +++ b/packages/devui-vue/devui/modal/src/dialog-types.ts @@ -0,0 +1,95 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { IButtonStyle } from '../../button/src/button' + +export interface ButtonOptions { + btnStyle: IButtonStyle + text: string + disabled: boolean + handler: ($event: Event) => void +} + +export const dialogProps = { + // id: { + // type: String, + // required: true + // }, + width: { + type: String, + default: '300px' + }, + maxHeight: { + type: String, + }, + + zIndex: { + type: Number, + default: 1050 + }, + backdropZIndex: { + type: Number, + default: 1049 + }, + + placement: { + type: String as PropType<'center' | 'top' | 'bottom'>, + default: 'center' + }, + offsetX: { + type: String, + default: '0px' + }, + + offsetY: { + type: String, + default: '0px' + }, + + title: { + type: String + }, + + showAnimation: { + type: Boolean, + default: true + }, + backdropCloseable: { + type: Boolean, + default: false + }, + bodyScrollable: { + type: Boolean, + default: true + }, + + escapeable: { + type: Boolean, + default: true + }, + + onClose: { + type: Function as PropType<() => void>, + }, + beforeHidden: { + type: [Promise, Function] as PropType<Promise<boolean> | (() => boolean | Promise<boolean>)> + }, + + buttons: { + type: Array as PropType<ButtonOptions[]>, + default: [] + }, + + dialogType: { + type: String as PropType<'standard' | 'success' | 'failed' | 'warning' | 'info'>, + default: 'standard' + }, + + + modelValue: { + type: Boolean, + }, + 'onUpdate:modelValue': { + type: Function as PropType<(value: boolean) => void> + } +} as const + +export type DialogProps = ExtractPropTypes<typeof dialogProps> diff --git a/packages/devui-vue/devui/modal/src/dialog.tsx b/packages/devui-vue/devui/modal/src/dialog.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c493aeac0be6d06b1f91a3bd75f3798ec89e8102 --- /dev/null +++ b/packages/devui-vue/devui/modal/src/dialog.tsx @@ -0,0 +1,135 @@ +import { defineComponent, computed, CSSProperties, watch, ref } from 'vue'; +import { DialogProps, dialogProps } from './dialog-types'; +import { useMoveable } from './use-moveable'; + +import { Button } from '../../button'; +import Modal from './modal'; + +import './modal.scss'; +import { Icon } from '../../icon'; + +export default defineComponent({ + name: 'DModal', + inheritAttrs: false, + props: dialogProps, + emits: ['onUpdate:modelValue'], + setup(props: DialogProps, ctx) { + + // 获取鼠标拖拽的偏移量 + const { + movingX, + movingY, + handleRef, + moveElRef, + reset + } = useMoveable(); + + watch(() => props.modelValue, (value) => { + if (value) { + reset(); + } + }); + + // 拖拽的样式 + const movingStyle = computed<CSSProperties>(() => ({ + position: 'relative', + left: `${movingX.value}px`, + top: `${movingY.value}px`, + })); + + // 容器的样式 + const containerStyle = computed<CSSProperties>(() => ({ + width: props.width, + maxHeight: props.maxHeight, + transform: `translate(${props.offsetX}, ${props.offsetY})`, + zIndex: props.zIndex + })); + + const iconName = computed(() => { + switch (props.dialogType) { + case 'standard': + return ''; + case 'info': + return 'icon-info-o'; + case 'success': + return 'icon-right-o'; + case 'warning': + return 'icon-warning-o'; + case 'failed': + return 'icon-error-o'; + default: + return ''; + } + }); + + // 处理按钮 + const buttonsRef = computed(() => { + return props.buttons.map((buttonProps, index) => { + const { btnStyle, disabled, handler, text } = buttonProps; + return ( + <Button + key={index} + style={{ display: 'inline-block', margin: '0 5px' }} + btnStyle={btnStyle} + disabled={disabled} + onClick={handler} + > + {text} + </Button> + ); + }); + }); + + const modalRef = ref<{ onVisibleChange(v: boolean): void; } | null>(); + const closeModal = () => { + modalRef.value?.onVisibleChange?.(false) + } + ctx.expose({ closeModal }); + + return () => ( + <Modal + ref={modalRef} + width={props.width} + maxHeight={props.maxHeight} + offsetX={props.offsetX} + offsetY={props.offsetY} + zIndex={props.zIndex} + backdropZIndex={props.backdropZIndex} + backdropCloseable={props.backdropCloseable} + bodyScrollable={props.bodyScrollable} + placement={props.placement} + onClose={props.onClose} + beforeHidden={props.beforeHidden} + modelValue={props.modelValue} + onUpdate:modelValue={props['onUpdate:modelValue']} + > + <div + class="devui-modal-content" + style={[containerStyle.value, movingStyle.value]} + ref={moveElRef} + > + <div class="devui-modal-header" ref={handleRef}> + {!!iconName.value ? ( + <Icon name={iconName.value} size="24px" class="header-alert-icon" /> + ) : null} + <span> + {props.title} + </span> + <Button + class="btn-close" + icon="close" + btnStyle="text-dark" + onClick={closeModal} + /> + </div> + <div class="devui-modal-body"> + {ctx.slots.default?.()} + </div> + <div class="devui-modal-footer"> + {buttonsRef.value} + </div> + </div> + </Modal> + ); + } +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/src/modal-types.ts b/packages/devui-vue/devui/modal/src/modal-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..897eae827a53431aaf08fc54113011d9fa2ed30d --- /dev/null +++ b/packages/devui-vue/devui/modal/src/modal-types.ts @@ -0,0 +1,72 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export const modalProps = { + // id: { + // type: String, + // required: true + // }, + width: { + type: String, + default: '300px' + }, + maxHeight: { + type: String, + }, + + zIndex: { + type: Number, + default: 1050 + }, + backdropZIndex: { + type: Number, + default: 1049 + }, + + placement: { + type: String as PropType<'center' | 'top' | 'bottom'>, + default: 'center' + }, + offsetX: { + type: String, + default: '0px' + }, + + offsetY: { + type: String, + default: '0px' + }, + + showAnimation: { + type: Boolean, + default: true + }, + backdropCloseable: { + type: Boolean, + default: false + }, + bodyScrollable: { + type: Boolean, + default: true + }, + + escapeable: { + type: Boolean, + default: true + }, + + onClose: { + type: Function as PropType<() => void>, + }, + beforeHidden: { + type: [Object, Function] as PropType<Promise<boolean> | (() => boolean| Promise<boolean>)> + }, + + modelValue: { + type: Boolean, + }, + 'onUpdate:modelValue': { + type: Function as PropType<(value: boolean) => void> + } +} as const + +export type ModalProps = ExtractPropTypes<typeof modalProps> diff --git a/packages/devui-vue/devui/modal/src/modal.scss b/packages/devui-vue/devui/modal/src/modal.scss new file mode 100644 index 0000000000000000000000000000000000000000..dda282b5b6bc46c612bab3557123aa11dd56a099 --- /dev/null +++ b/packages/devui-vue/devui/modal/src/modal.scss @@ -0,0 +1,92 @@ +@import '../../style/theme/color'; +@import '../../style/theme/corner'; +@import '../../style/theme/font'; +@import '../../style/theme/animation'; + +.devui-modal-wrapper { + justify-content: center; + align-items: center; + background-color: $devui-shadow; +} + +.devui-modal-content { + background: $devui-fullscreen-overlay-bg; + border-radius: $devui-border-radius; +} + +.devui-modal-body { + padding: 20px 32px; + color: $devui-text-weak; +} + +.devui-modal-header { + padding: 32px 32px 0; + height: 56px; + position: relative; + border: none; + user-select: none; + + .btn-close { + position: absolute; + right: 20px; + top: 20px; + font-size: $devui-font-size-icon; + font-weight: 700; + line-height: 1; + color: #000000; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } + + .header-alert-icon { + display: inline-block; + vertical-align: middle; + margin-right: 8px; + line-height: 16px; + text-align: center; + } +} + +.devui-modal-footer { + border-top: none; + text-align: center; + padding: 0 32px 24px; +} + +.devui-modal-wipe { + @mixin wipe-in-out-animation { + animation-name: wipe-in-out; + animation-duration: 0.3s; + } + @keyframes wipe-in-out { + 0% { + opacity: 0.2; + transform: translateY(-24px); + } + + 100% { + opacity: 1; + transform: translateY(0); + } + } + + &-enter-from { + opacity: 0.2; + } + + &-enter-active { + @include wipe-in-out-animation; + } + + &-leave-to { + opacity: 1; + } + + &-leave-active { + @include wipe-in-out-animation; + + animation-direction: reverse; + } +} diff --git a/packages/devui-vue/devui/modal/src/modal.tsx b/packages/devui-vue/devui/modal/src/modal.tsx new file mode 100644 index 0000000000000000000000000000000000000000..82002416f281c4ccb0a3ee512614889ea20da00c --- /dev/null +++ b/packages/devui-vue/devui/modal/src/modal.tsx @@ -0,0 +1,63 @@ +import { + computed, + defineComponent, + Transition, + watch +} from 'vue' +import { modalProps, ModalProps } from './modal-types' +import { FixedOverlay } from '../../overlay' +import './modal.scss'; + +export default defineComponent({ + name: 'DModal', + props: modalProps, + emits: ['onUpdate:modelValue'], + setup(props: ModalProps, ctx) { + const animatedVisible = computed(() => { + return props.showAnimation ? props.modelValue : true; + }); + + // 处理取消事件 + const onVisibleChange = (value: boolean) => { + const update = props['onUpdate:modelValue']; + if (value) { + update?.(value); + } else { + const beforeHidden = props.beforeHidden; + const close = (enabledClose: boolean) => { + if (enabledClose) { + update?.(false); + props.onClose?.(); + } + } + // true: 确认关闭 + // false: 仍然开启 + const result = (typeof beforeHidden === 'function' ? beforeHidden() : beforeHidden) ?? true; + if (result instanceof Promise) { + result.then(close); + } else { + close(result); + } + } + } + + ctx.expose({ onVisibleChange }); + + return () => ( + <FixedOverlay + visible={props.modelValue} + onUpdate:visible={onVisibleChange} + backgroundClass="devui-modal-wrapper" + // overlay feature + // backgroundStyle={{ zIndex: props.backdropZIndex }} + backgroundBlock={!props.bodyScrollable} + backdropClose={props.backdropCloseable} + > + <Transition name="devui-modal-wipe"> + {animatedVisible.value ? ctx.slots.default?.() : null} + </Transition> + </FixedOverlay> + ) + } +}) + diff --git a/packages/devui-vue/devui/modal/src/services/common-modal-service.ts b/packages/devui-vue/devui/modal/src/services/common-modal-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..befc1d05216f31c1fb816f2cceb3848b82bf0712 --- /dev/null +++ b/packages/devui-vue/devui/modal/src/services/common-modal-service.ts @@ -0,0 +1,27 @@ +import { h, render, Slots, VNode } from 'vue'; + +export interface ModalOpenResult { + hide(): void +} + +export abstract class CommonModalService<Options, Props> { + + constructor(public anchorContainer: HTMLElement) {} + + abstract component(): any; + + abstract open(options: Partial<Options>): ModalOpenResult; + + protected renderModal(anchor: HTMLElement, props: Partial<Props>, children?: Slots): VNode { + const vnode = h(this.component(), props, children); + render(vnode, anchor); + return vnode; + } + + protected renderNull(anchor: HTMLElement): void { + // 动画运行完毕后 + setTimeout(() => { + render(null, anchor); + }, 500); + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/src/services/dialog-service.ts b/packages/devui-vue/devui/modal/src/services/dialog-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..31eb9dd811775220849f46635c1b5a6a2adf268e --- /dev/null +++ b/packages/devui-vue/devui/modal/src/services/dialog-service.ts @@ -0,0 +1,119 @@ +import { Slot, InjectionKey } from 'vue'; +// import {h, ref, SetupContext, defineComponent, customRef} from 'vue' +import { CommonModalService, ModalOpenResult } from './common-modal-service'; +import Dialog from '../dialog'; +import { ButtonOptions, DialogProps } from '../dialog-types'; + + +export interface DialogOptions { + width: string + maxHeight: string + zIndex: number + backdropZIndex: number + placement: 'center' | 'top' | 'bottom' + offsetX: string + offsetY: string + showAnimation: boolean + backdropCloseable: boolean + escapeable: boolean + bodyScrollable: boolean + dialogtype: 'standard' | 'success' | 'failed' | 'warning'| 'info' + + title: string + content: Slot + buttons: ButtonOptions[] + + onClose(): void + beforeHidden: (() => boolean | Promise<boolean>) | Promise<boolean> +} + +export class DialogService extends CommonModalService<DialogOptions, DialogProps> { + + static token = 'DIALOG_SERVICE_TOKEN' as unknown as InjectionKey<DialogService>; + + component(): any { + return Dialog; + } + + open(props: Partial<DialogOptions> = {}): ModalOpenResult & {updateButtonOptions(options: ButtonOptions[]): void;} { + // TODO:手动的方式可能抛弃了 content 内部的响应式,这里需要再优化。 + const anchor = document.createElement('div'); + this.anchorContainer.appendChild(anchor); + + const {content, ...resProps} = props; + + const needHideOrNot = (value: boolean) => { + if (!value) { + hide(); + } + } + + const renderOrigin = (props: typeof resProps, onUpdateModelValue = needHideOrNot) => { + return this.renderModal(anchor, { + ...props, + modelValue: true, + 'onUpdate:modelValue': onUpdateModelValue + }, {default: content}); + } + + + + // 隐藏按钮 + const hide = () => { + const vnode = renderOrigin(resProps, (value: boolean) => { + if (!value) { + this.renderModal(anchor, {...resProps, modelValue: false}); + this.renderNull(anchor); + } else { + renderOrigin(resProps); + } + }); + vnode.component.exposed.closeModal?.(); + } + + // 更新按钮选项 + const updateButtonOptions = (buttonOptions: ButtonOptions[]) => { + const { buttons, ...innerResProps } = resProps; + const newButtonOptions = buttons.map((option, index) => ({ + ...option, + ...buttonOptions[index] + })); + renderOrigin({...innerResProps, buttons: newButtonOptions}); + } + + // 先渲染一次,触发动画用 + this.renderModal(anchor, { modelValue: false }); + + // 再渲染详细内容 + renderOrigin(resProps); + + return { hide, updateButtonOptions } + + // TODO: 这个需要再考虑设计 + // const CurrentDialog = defineComponent((currentProps: typeof props, ctx: SetupContext) => { + // const dialogRef = ref<{closeModal(): void;} | null>(); + // const visibleRef = ref(true); + // const buttonsRef = ref(currentProps.buttons); + // ctx.expose({ + // closeModal() { + // dialogRef.value?.closeModal?.(); + // }, + // updateButtons(buttons: ButtonOptions) { + // buttonsRef.value = buttonsRef.value.map((option, index) => ({ + // ...option, + // ...buttons[index] + // })); + // } + // }); + // return () => { + // const {content, ...resProps} = currentProps; + // return h(Dialog, { + // ...resProps, + // ref: dialogRef, + // modelValue: visibleRef.value, + // 'onUpdate:modelValue': (value) => visibleRef.value = value + // }, {default: content}); + // }; + // }); + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/src/services/modal-service.ts b/packages/devui-vue/devui/modal/src/services/modal-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e7ffe2ff257e34784b5c370c6606025238149ae --- /dev/null +++ b/packages/devui-vue/devui/modal/src/services/modal-service.ts @@ -0,0 +1,76 @@ +import { InjectionKey, Slot } from 'vue'; +import { ModalProps } from '../modal-types'; +import { CommonModalService, ModalOpenResult } from './common-modal-service'; +import Modal from '../modal'; + +export interface ModalOptions { + width: string + maxHeight: string + zIndex: number + backdropZIndex: number + placement: 'center' | 'top' | 'bottom' + offsetX: string + offsetY: string + showAnimation: boolean + backdropCloseable: boolean + escapeable: boolean + bodyScrollable: boolean + content: Slot + + onClose(): void + beforeHidden: (() => boolean | Promise<boolean>) | Promise<boolean> +} + + +export class ModalService extends CommonModalService<ModalOptions, ModalProps> { + + static token = 'MODAL_SERVICE_TOKEN' as unknown as InjectionKey<ModalService>; + + component(): any { + return Modal; + } + + open(props: Partial<ModalOptions> = {}): ModalOpenResult { + // TODO:手动的方式可能抛弃了 content 内部的响应式,这里需要再优化。 + const anchor = document.createElement('div'); + this.anchorContainer.appendChild(anchor); + + const { content, ...resProps } = props; + + const needHideOrNot = (value: boolean) => { + if (!value) { + hide(); + } + } + const renderOrigin = (props: typeof resProps, onUpdateModelValue = needHideOrNot) => { + return this.renderModal(anchor, { + ...props, + modelValue: true, + 'onUpdate:modelValue': onUpdateModelValue + }, { default: content }); + } + + + // 隐藏按钮 + const hide = () => { + const vnode = renderOrigin(resProps, (value: boolean) => { + if (!value) { + this.renderModal(anchor, { ...resProps, modelValue: false }); + this.renderNull(anchor); + } else { + renderOrigin(resProps); + } + }); + vnode.component.exposed.onVisibleChange?.(false); + } + + + // 先渲染一次,触发动画用 + this.renderModal(anchor, { modelValue: false }); + + // 再渲染详细内容 + renderOrigin(resProps); + + return { hide } + } +} diff --git a/packages/devui-vue/devui/modal/src/use-moveable.ts b/packages/devui-vue/devui/modal/src/use-moveable.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f8b50b69f280ac3242cff4b09e780c649a19e0b --- /dev/null +++ b/packages/devui-vue/devui/modal/src/use-moveable.ts @@ -0,0 +1,127 @@ +import { + ref, + watch, + readonly, + Ref, + isRef, +} from 'vue' + +export interface MoveableResult { + movingX: Ref<number> + movingY: Ref<number> + // 可拖拽的元素 + handleRef: Ref<HTMLElement | null> + // 可移动的元素 + moveElRef: Ref<HTMLElement | null> + reset(): void +} + +// 当前某个元素被拖拽时鼠标的偏移量 +export const useMoveable = (moveable: Ref<boolean> | boolean = true): MoveableResult => { + // X,Y 偏移量 + const movingX = ref(0); + const movingY = ref(0); + const reset = () => { + movingX.value = 0; + movingY.value = 0; + } + + // 可拖拽的元素 + const handleRef = ref<HTMLElement | null>(); + // 可移动的元素 + const moveElRef = ref<HTMLElement | null>(); + // 是否允许拖拽 + const enabledMoving = isRef(moveable) ? moveable : ref(moveable); + + // 可视化 + watch([moveElRef, handleRef], ([container, target], ov, onInvalidate) => { + if (!(target instanceof HTMLElement && container instanceof HTMLElement)) { + return; + } + // 更改为拖动样式 + target.style.cursor = 'all-scroll'; + + // 初始化内容 + let startX = 0; + let startY = 0; + let prevMovingX = 0; + let prevMovingY = 0; + let containerRect = container.getBoundingClientRect(); + let bodyRect = document.body.getBoundingClientRect(); + let isDown = false; + + const handleMouseDown = (event: MouseEvent) => { + event.preventDefault(); + if (!enabledMoving.value) { + return; + } + startX = event.clientX; + startY = event.clientY; + // 只拿最新的 + const targetRect = target.getBoundingClientRect(); + // 判断鼠标点是否在 target 元素内 + if ( + (target === event.target || target.contains(event.target as Node)) && + targetRect.x < startX && + targetRect.y < startY && + (targetRect.width + targetRect.x) >= startX && + (targetRect.height + targetRect.y) >= startY + ) { + isDown = true; + prevMovingX = movingX.value; + prevMovingY = movingY.value; + bodyRect = document.body.getBoundingClientRect(); + containerRect = container.getBoundingClientRect(); + } + } + + const handleMouseMove = (event: MouseEvent) => { + event.preventDefault(); + if (!isDown) { + return; + } + const currentX = prevMovingX + event.clientX - startX; + const currentY = prevMovingY + event.clientY - startY; + const containerOriginX = containerRect.x - prevMovingX; + const containerOriginY = containerRect.y - prevMovingY; + movingX.value = getRangeValueOf(currentX, -containerOriginX, bodyRect.width - containerRect.width - containerOriginX); + movingY.value = getRangeValueOf(currentY, -containerOriginY, bodyRect.height - containerRect.height - containerOriginY); + } + + const handleMouseUp = (event: MouseEvent) => { + event.preventDefault(); + if (!isDown) { + return; + } + isDown = false; + } + + window.addEventListener('mousedown', handleMouseDown); + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); + onInvalidate(() => { + window.removeEventListener('mousedown', handleMouseDown); + window.removeEventListener('mousemove', handleMouseMove); + window.removeEventListener('mouseup', handleMouseUp); + }); + }); + + return { + movingX: readonly(movingX), + movingY: readonly(movingY), + handleRef, + moveElRef, + reset + } +} + + +const getRangeValueOf = (value: number, min: number, max: number) => { + if (value < min) { + return min; + } + if (value > max) { + return max; + } + return value; +} diff --git a/packages/devui-vue/devui/nav-sprite/index.ts b/packages/devui-vue/devui/nav-sprite/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3fbd5abbdb1f0d4c0c87de42445cf60a18964d3 --- /dev/null +++ b/packages/devui-vue/devui/nav-sprite/index.ts @@ -0,0 +1,17 @@ +import { App } from 'vue'; +import NavSprite from './src/nav-sprite'; + +NavSprite.install = function (app: App) { + app.component(NavSprite.name, NavSprite); +}; + +export { NavSprite }; + +export default { + title: 'NavSprite 导航精灵', + category: '导航', + status: '10%', + install(app: App): void { + app.use(NavSprite as any); + } +}; diff --git a/packages/devui-vue/devui/nav-sprite/src/nav-sprite-types.ts b/packages/devui-vue/devui/nav-sprite/src/nav-sprite-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..b786c855d00a3148801f5585a2e6ca4157e4e10a --- /dev/null +++ b/packages/devui-vue/devui/nav-sprite/src/nav-sprite-types.ts @@ -0,0 +1,74 @@ +import { PropType } from 'vue'; +export type SpriteMode = 'default' | 'sprite'; + +export interface SpriteOption { + top: string + left: string + zIndex: number +} +export interface NavMenu { + originEle: HTMLElement + label: string + level: number + scrollPosition: { + top: number + startLine: number + } +} +export const navSpriteProps = { + // // 爬取目录的容器 + target: { + type: Object, + }, + // // 指定滚动的DOM + scrollTarget: { + type: Object, + }, + // // 矫正参数 + view: { + type: Object as () => { + top?: number + bottom?: number + }, + default: { top: 0, bottom: 0 } + }, + // // 支持锚点 + hashSupport: { + type: Boolean, + default: false + }, + mode: { + type: String as () => SpriteMode, + default: 'default' + }, + maxLevel: { + type: Number, + default: 3 + }, + title: { + type: String, + default: 'menu' + }, + // 缩进 + indent: { + type: Number, + default: 2 + }, + width: { + type: Number, + default: 300 + }, + height: { + type: Number, + default: 400 + }, + // sprite模式下的初始状态 + isOpen: { + type: Boolean, + default: true + }, + // sprite模式下的初始位置 + spriteOption: { + type: Object as () => SpriteOption, + } +} diff --git a/packages/devui-vue/devui/nav-sprite/src/nav-sprite.scss b/packages/devui-vue/devui/nav-sprite/src/nav-sprite.scss new file mode 100644 index 0000000000000000000000000000000000000000..eb16092ec8eb848361ea3263f871602a4b2a1b92 --- /dev/null +++ b/packages/devui-vue/devui/nav-sprite/src/nav-sprite.scss @@ -0,0 +1,112 @@ +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/theme/shadow'; +@import '../../styles-var/devui-var.scss'; + +.devui-is-sprite { + background-color: $devui-connected-overlay-bg; + box-shadow: $devui-shadow-length-connected-overlay $devui-shadow; + cursor: move; + padding: 0 16px 16px; + max-width: 300px; + + &.is-min { + display: flex; + align-items: center; + justify-content: center; + width: 40px !important; + height: 40px !important; + border-radius: 100%; + padding: 0; + + &:hover { + color: $devui-light-text; + background-color: $devui-brand; + } + + i { + cursor: pointer; + } + } + + .devui-nav-sprite-menus { + width: 100%; + height: 100%; + max-height: 240px; + } +} + +.devui-nav-sprite-content { + width: 100%; + height: 100%; + padding: 0 12px 16px 12px; + + .devui-nav-sprite-header { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + color: $devui-text; + line-height: 32px; + font-weight: bold; + font-size: $devui-font-size-card-title; + border-bottom: 1px solid $devui-dividing-line; + + .devui-nav-spiri-close { + cursor: pointer; + } + } +} + +.devui-nav-sprite-menus { + margin-top: 10px; + overflow-y: hidden; + height: calc(100% - 80px); + + &:hover { + overflow-y: auto; + } + + & > li { + list-style: none; + cursor: pointer; + height: 30px; + line-height: 30px; + font-size: $devui-font-size; + color: $devui-text; + position: relative; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + a { + color: $devui-text; + } + + &.active { + a { + color: $devui-link; + } + + color: $devui-link; + } + + &:not(.disabled):hover { + color: $devui-list-item-hover-text; + } + + .nav-item { + a, + span { + &:hover { + color: $devui-list-item-hover-text; + } + } + } + } +} + +.devui-no-data { + line-height: 32px; + color: $devui-text; +} diff --git a/packages/devui-vue/devui/nav-sprite/src/nav-sprite.tsx b/packages/devui-vue/devui/nav-sprite/src/nav-sprite.tsx new file mode 100644 index 0000000000000000000000000000000000000000..378e15c6b1a80d673bb1ec2db097526779dd8bb6 --- /dev/null +++ b/packages/devui-vue/devui/nav-sprite/src/nav-sprite.tsx @@ -0,0 +1,11 @@ +import { defineComponent } from '@vue/runtime-core'; +import { navSpriteProps } from './nav-sprite-types'; + +export default defineComponent({ + name: 'DNavSprite', + props: navSpriteProps, + emits: ['afterNavInit'], + setup(props) { + return {}; + } +}); diff --git a/packages/devui-vue/devui/overlay/index.ts b/packages/devui-vue/devui/overlay/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c995acc956c4db3c2c9535f6087b88579d6d25d6 --- /dev/null +++ b/packages/devui-vue/devui/overlay/index.ts @@ -0,0 +1,34 @@ +import type { App } from 'vue' +import {FixedOverlay} from './src/fixed-overlay'; +import {FlexibleOverlay } from './src/flexible-overlay'; +import {inBrowser} from '../shared/util/common-var'; + +FlexibleOverlay.install = function(app: App) { + app.component(FlexibleOverlay.name, FlexibleOverlay); +} + +FixedOverlay.install = function(app: App) { + app.component(FixedOverlay.name, FixedOverlay); +} + +export { FlexibleOverlay, FixedOverlay } + +export default { + title: 'Overlay 遮罩层', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(FixedOverlay as any); + app.use(FlexibleOverlay as any); + + if (inBrowser && !document.getElementById('d-overlay-anchor')) { + const overlayAnchor = document.createElement('div'); + overlayAnchor.setAttribute('id', 'd-overlay-anchor'); + overlayAnchor.style.position = 'fixed'; + overlayAnchor.style.left = '0'; + overlayAnchor.style.top = '0'; + overlayAnchor.style.zIndex = '1000'; + document.body.appendChild(overlayAnchor); + } + } +} diff --git a/packages/devui-vue/devui/overlay/src/common-overlay.tsx b/packages/devui-vue/devui/overlay/src/common-overlay.tsx new file mode 100644 index 0000000000000000000000000000000000000000..51a9e5dfbc7c6cba16ea9fca91776eb15a8412ea --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/common-overlay.tsx @@ -0,0 +1,14 @@ +import { defineComponent, renderSlot, Teleport, Transition } from 'vue'; +import './overlay.scss'; + +export const CommonOverlay = defineComponent({ + setup(props, ctx) { + return () => ( + <Teleport to="#d-overlay-anchor"> + <Transition name="devui-overlay-fade"> + {renderSlot(ctx.slots, 'default')} + </Transition> + </Teleport> + ); + }, +}); diff --git a/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx b/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c4ccfa03ec89e41c599e1037da30dfdfdbcf17a8 --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx @@ -0,0 +1,37 @@ +import { defineComponent, ref, renderSlot, CSSProperties, PropType } from 'vue'; +import { CommonOverlay } from './common-overlay'; +import { fixedOverlayProps, FixedOverlayProps } from './overlay-types'; +import { useOverlayLogic } from './utils'; +import './overlay.scss'; + +export const FixedOverlay = defineComponent({ + name: 'DFixedOverlay', + props: fixedOverlayProps, + setup(props: FixedOverlayProps, ctx) { + const { + backgroundClass, + overlayClass, + handleBackdropClick, + handleOverlayBubbleCancel + } = useOverlayLogic(props); + + return () => ( + <CommonOverlay> + <div + v-show={props.visible} + class={backgroundClass.value} + style={props.backgroundStyle} + onClick={handleBackdropClick} + > + <div + class={overlayClass.value} + style={props.overlayStyle} + onClick={handleOverlayBubbleCancel} + > + {renderSlot(ctx.slots, 'default')} + </div> + </div> + </CommonOverlay> + ); + }, +}); diff --git a/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx b/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx new file mode 100644 index 0000000000000000000000000000000000000000..42556b58eac8d580e2c83d54579947b50d4b8a04 --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx @@ -0,0 +1,280 @@ +import { + CSSProperties, + defineComponent, + getCurrentInstance, + isRef, + nextTick, + onBeforeUnmount, + onMounted, + reactive, + ref, + renderSlot, + toRef, + watch, +} from 'vue'; +import { CommonOverlay } from './common-overlay'; +import { OriginOrDomRef, flexibleOverlayProps, FlexibleOverlayProps, Point, Origin, ConnectionPosition } from './overlay-types'; +import { useOverlayLogic } from './utils'; + +import { getElement, isComponent } from '../../shared/util/dom'; + +/** + * 弹性的 Overlay,用于连接固定的和相对点 + */ +export const FlexibleOverlay = defineComponent({ + name: 'DFlexibleOverlay', + props: flexibleOverlayProps, + emits: ['onUpdate:visible'], + setup(props: FlexibleOverlayProps, ctx) { + // lift cycle + const overlayRef = ref<Element | null>(null); + const positionedStyle = reactive<CSSProperties>({ position: 'absolute' }); + const instance = getCurrentInstance(); + onMounted(async () => { + await nextTick(); + + // 获取背景 + const overlay = overlayRef.value; + if (!overlay) { + return; + } + + // 获取原点 + const origin = getOrigin(props.origin); + if (!origin) { + return; + } + + const handleRectChange = (rect: DOMRect) => { + // TODO: add optimize for throttle + const point = calculatePosition(props.position, rect, origin); + + // set the current position style's value. + // the current position style is a 'ref'. + positionedStyle.left = `${point.x}px`; + positionedStyle.top = `${point.y}px`; + }; + const handleChange = () => handleRectChange(overlay.getBoundingClientRect()); + + const visibleRef = toRef(props, 'visible'); + const positionRef = toRef(props, 'position'); + + watch(visibleRef, (visible, ov, onInvalidate) => { + if (visible) { + subscribeLayoutEvent(handleChange); + } else { + unsbscribeLayoutEvent(handleChange); + } + onInvalidate(() => { + unsbscribeLayoutEvent(handleChange); + }); + }); + + watch([visibleRef, positionRef], () => { + handleChange(); + }); + + const resizeObserver = new ResizeObserver((entries) => { + handleRectChange(entries[0].contentRect); + }); + resizeObserver.observe(overlay as unknown as Element); + onBeforeUnmount(() => { + resizeObserver.disconnect(); + }, instance); + + if (origin instanceof Element) { + // Only when the style changing, you can change the position. + const observer = new MutationObserver(handleChange); + observer.observe(origin, { + attributeFilter: ['style'], + }); + onBeforeUnmount(() => { + observer.disconnect(); + }, instance); + } + }, instance); + + const { + backgroundClass, + overlayClass, + handleBackdropClick, + handleOverlayBubbleCancel + } = useOverlayLogic(props); + + return () => ( + <CommonOverlay> + <div + v-show={props.visible} + style={props.backgroundStyle} + class={backgroundClass.value} + onClick={handleBackdropClick} + > + <div + ref={overlayRef} + class={overlayClass.value} + style={positionedStyle} + onClick={handleOverlayBubbleCancel} + > + {renderSlot(ctx.slots, 'default')} + </div> + </div> + </CommonOverlay> + ); + }, +}); + + +/** + * 获取原点,可能是 Element 或者 Rect + * @param {OriginOrDomRef} origin + * @returns {Origin} + */ +function getOrigin(origin: OriginOrDomRef): Origin { + // Check for Element so SVG elements are also supported. + if (origin instanceof Element) { + return origin; + } + + if (isRef(origin)) { + return getElement(origin.value); + } + + if (isComponent(origin)) { + return getElement(origin); + } + + // is point { x: number, y: number, width: number, height: number } + return origin; +} + +/** + * 计算坐标系 + * @param {ConnectionPosition} position + * @param {HTMLElement | DOMRect} panelOrRect + * @param {Origin} origin + * @returns + */ +function calculatePosition( + position: ConnectionPosition, + panelOrRect: HTMLElement | DOMRect, + origin: Origin +): Point { + // get overlay rect + const originRect = getOriginRect(origin); + + // calculate the origin point + const originPoint = getOriginRelativePoint(originRect, position); + + let rect: DOMRect; + if (panelOrRect instanceof HTMLElement) { + rect = panelOrRect.getBoundingClientRect(); + } else { + rect = panelOrRect; + } + + // calculate the overlay anchor point + return getOverlayPoint(originPoint, rect, position); +} + +/** + * 返回原点元素的 ClientRect + * @param origin + * @returns {DOMRect} + */ +function getOriginRect(origin: Origin): DOMRect { + if (origin instanceof Element) { + return origin.getBoundingClientRect(); + } + // Origin is point + const width = origin.width || 0; + const height = origin.height || 0; + + // If the origin is a point, return a client rect as if it was a 0x0 element at the point. + return { + top: origin.y, + bottom: origin.y + height, + left: origin.x, + right: origin.x + width, + height, + width, + } as DOMRect; +} + +/** + * 获取遮罩层的左上角坐标 + * @param {Point} originPoint + * @param {DOMRect} rect + * @param {ConnectionPosition} position + * @returns + */ +function getOverlayPoint( + originPoint: Point, + rect: DOMRect, + position: ConnectionPosition +): Point { + let x: number; + const { width, height } = rect; + if (position.overlayX == 'center') { + x = originPoint.x - width / 2; + } else { + x = position.overlayX == 'left' ? originPoint.x : originPoint.x - width; + } + + let y: number; + if (position.overlayY == 'center') { + y = originPoint.y - height / 2; + } else { + y = position.overlayY == 'top' ? originPoint.y : originPoint.y - height; + } + + return { x, y }; +} + +/** + * 获取原点相对于 position 的坐标 (x, y) + * @param originRect + * @param position + * @returns + */ +function getOriginRelativePoint( + originRect: ClientRect, + position: ConnectionPosition +): Point { + let x: number; + if (position.originX == 'center') { + x = originRect.left + originRect.width / 2; + } else { + const startX = originRect.left; + const endX = originRect.right; + x = position.originX == 'left' ? startX : endX; + } + + let y: number; + if (position.originY == 'center') { + y = originRect.top + originRect.height / 2; + } else { + y = position.originY == 'top' ? originRect.top : originRect.bottom; + } + + return { x, y }; +} + +/** + * 订阅 layout 变化事件 + * @param event + */ +function subscribeLayoutEvent(event: (e?: Event) => void) { + window.addEventListener('scroll', event, true); + window.addEventListener('resize', event); + window.addEventListener('orientationchange', event); +} + +/** + * 取消 layout 变化事件 + * @param event + */ +function unsbscribeLayoutEvent(event: (e?: Event) => void) { + window.removeEventListener('scroll', event, true); + window.removeEventListener('resize', event); + window.removeEventListener('orientationchange', event); +} diff --git a/packages/devui-vue/devui/overlay/src/overlay-types.ts b/packages/devui-vue/devui/overlay/src/overlay-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f90ccfb71b1086cdc7f528fffd8447deeccba49b --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/overlay-types.ts @@ -0,0 +1,107 @@ +import { ExtractPropTypes, PropType, StyleValue, ComponentPublicInstance, Ref } from 'vue'; + +export const overlayProps = { + visible: { + type: Boolean, + }, + 'onUpdate:visible': { + type: Function as PropType<(v: boolean) => void> + }, + backgroundBlock: { + type: Boolean, + default: false + }, + backgroundClass: { + type: String, + default: '' + }, + backgroundStyle: { + type: [String, Object] as PropType<StyleValue> + }, + backdropClick: { + type: Function, + }, + backdropClose: { + type: Boolean, + default: true + }, + hasBackdrop: { + type: Boolean, + default: true + }, +} as const; + +export type OverlayProps = ExtractPropTypes<typeof overlayProps>; + + +export const fixedOverlayProps = { + ...overlayProps, + overlayStyle: { + type: [String, Object] as PropType<StyleValue>, + default: undefined, + }, +}; + +export type FixedOverlayProps = ExtractPropTypes<typeof fixedOverlayProps>; + +export const flexibleOverlayProps = { + origin: { + type: Object as PropType<OriginOrDomRef>, + require: true, + }, + position: { + type: Object as PropType<ConnectionPosition>, + default: () => ({ + originX: 'left', + originY: 'top', + overlayX: 'left', + overlayY: 'top', + }), + }, + ...overlayProps, +} + + +export interface ClientRect { + bottom: number + readonly height: number + left: number + right: number + top: number + readonly width: number +} + +export interface Point { + x: number + y: number +} + +export interface Rect { + x: number + y: number + width?: number + height?: number +} + +export type Origin = Element | Rect; + +type HorizontalConnectionPos = 'left' | 'center' | 'right'; +type VerticalConnectionPos = 'top' | 'center' | 'bottom'; + +export interface ConnectionPosition { + originX: HorizontalConnectionPos + originY: VerticalConnectionPos + overlayX: HorizontalConnectionPos + overlayY: VerticalConnectionPos +} + +export type OriginOrDomRef = + | Element + | ComponentPublicInstance + | Ref<ComponentPublicInstance | Element | undefined | null> + | Rect + | null; + +export type FlexibleOverlayProps = ExtractPropTypes<typeof flexibleOverlayProps>; + + diff --git a/packages/devui-vue/devui/overlay/src/overlay.scss b/packages/devui-vue/devui/overlay/src/overlay.scss new file mode 100644 index 0000000000000000000000000000000000000000..d9c754e5c1ebcc378eae097817f9d83982d9ae0c --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/overlay.scss @@ -0,0 +1,56 @@ +.devui-overlay-background { + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 100vw; + display: flex; + + &__color { + background: rgba(0, 0, 0, 0.4); + } + + .devui-overlay { + position: relative; + z-index: 1000; + pointer-events: auto; + } + + &__disabled { + pointer-events: none; + } +} + +.devui-overlay-fade { + @mixin d-overlay-fade-animation { + animation-name: d-overlay-fade; + animation-duration: 0.3s; + } + @keyframes d-overlay-fade { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } + + &-enter { + opacity: 0; + } + + &-enter-active { + @include d-overlay-fade-animation; + } + + &-leave { + opacity: 1; + } + + &-leave-active { + @include d-overlay-fade-animation; + + animation-direction: reverse; + } +} diff --git a/packages/devui-vue/devui/overlay/src/utils.ts b/packages/devui-vue/devui/overlay/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f115130a5184a1421f5153a7ee85751fe26053a --- /dev/null +++ b/packages/devui-vue/devui/overlay/src/utils.ts @@ -0,0 +1,64 @@ +import { onUnmounted, watch, computed, ComputedRef, onMounted } from 'vue'; +import { OverlayProps } from './overlay-types'; + +interface CommonInfo { + backgroundClass: ComputedRef<string[]> + overlayClass: ComputedRef<string> + handleBackdropClick: (e: Event) => void + handleOverlayBubbleCancel: (e: Event) => void +} + +export function useOverlayLogic(props: OverlayProps): CommonInfo { + const backgroundClass = computed(() => { + return [ + 'devui-overlay-background', + props.backgroundClass, + !props.hasBackdrop ? 'devui-overlay-background__disabled' : 'devui-overlay-background__color', + ]; + }); + const overlayClass = computed(() => { + return 'devui-overlay'; + }); + + const handleBackdropClick = (event: Event) => { + event.preventDefault(); + + props.backdropClick?.(); + if (props.backdropClose) { + props['onUpdate:visible']?.(false); + } + }; + + const handleOverlayBubbleCancel = (event: Event) => (event.cancelBubble = true); + + onMounted(() => { + const body = document.body; + const originOverflow = body.style.overflow; + const originPosition = body.style.position; + watch([() => props.visible, () => props.backgroundBlock], ([visible, backgroundBlock]) => { + if (backgroundBlock) { + const top = body.getBoundingClientRect().y; + if (visible) { + body.style.overflowY = 'scroll'; + body.style.position = visible ? 'fixed' : ''; + body.style.top = `${top}px`; + } else { + body.style.overflowY = originOverflow; + body.style.position = originPosition; + body.style.top = ''; + window.scrollTo(0, -top); + } + } + }); + onUnmounted(() => { + document.body.style.overflow = originOverflow; + }); + }); + + return { + backgroundClass, + overlayClass, + handleBackdropClick, + handleOverlayBubbleCancel + } +} diff --git a/packages/devui-vue/devui/pagination/__tests__/pagination.spec.ts b/packages/devui-vue/devui/pagination/__tests__/pagination.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..99bc8f76993eff001b57735534b32c19c5f3c898 --- /dev/null +++ b/packages/devui-vue/devui/pagination/__tests__/pagination.spec.ts @@ -0,0 +1,307 @@ +import { mount } from '@vue/test-utils'; +import { reactive } from 'vue'; +import { Pagination } from '../index' +import { Select } from '../../select' +import { Input } from '../../input' + +const globalOption = { + global: { + components: { + DSelect: Select, + DInput: Input + } + } +} + +describe('pagination: ', () => { + it('test pageSize', async () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + :showJumpButton="true" + /> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 20, + pageIndex: 5 + }) + return { pager } + } + }, globalOption) + + expect(wrapper.find('.devui-pagination-item.active').text()).toEqual('5') + expect((wrapper.find('.devui-select-input').element as HTMLInputElement).value).toEqual('20') + + const btns = wrapper.findAll('a.devui-pagination-link') + expect(btns.map((ele: any) => ele.text()).join()).toEqual('<,1,...,4,5,6,...,16,>'); + expect(wrapper.find('.devui-pagination-list').classes()).toContain('devui-pagination-sm') + + // 跳转按钮 + expect(wrapper.find('.devui-jump-container').exists()).toBeTruthy() + expect(wrapper.find('.devui-jump-button').exists()).toBeTruthy() + + // 翻页 + await btns[0].trigger('click') + expect(wrapper.find('.devui-pagination-item.active').text()).toEqual('4') + const btns1 = wrapper.findAll('a.devui-pagination-link') + expect(btns1.map((ele: any) => ele.text()).join()).toEqual('<,1,...,3,4,5,...,16,>'); + + // 改变每页条数 + await wrapper.find('.devui-select-input').trigger('click') + await wrapper.findAll('.devui-select-item')[1].trigger('click') + + expect((wrapper.find('.devui-select-input').element as HTMLInputElement).value).toEqual('10') + const btns2 = wrapper.findAll('a.devui-pagination-link') + expect(btns2.map((ele: any) => ele.text()).join()).toEqual('<,1,...,3,4,5,...,31,>'); + }) + + it('test callback', async () => { + const pageIndexChange = jest.fn() + const pageSizeChange = jest.fn() + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + size="lg" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="10" + @pageIndexChange="pageIndexChange" + @pageSizeChange="pageSizeChange" + /> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 10, + pageIndex: 10 + }) + return { pager, pageIndexChange, pageSizeChange } + } + }, globalOption) + + expect(wrapper.find('.devui-pagination-list').classes()).toContain('devui-pagination-lg') + const btns = wrapper.findAll('a.devui-pagination-link') + const pageIndexs = btns.map((ele: any) => ele.text()) + expect(pageIndexs.join()).toEqual('<,1,...,6,7,8,9,10,11,12,13,...,31,>'); + + // 当前页改变回调 + await btns[0].trigger('click') + expect(pageIndexChange).toHaveBeenCalled() + + // 每页条数改变回调 + await wrapper.find('.devui-select-input').trigger('click') + await wrapper.findAll('.devui-select-item')[1].trigger('click') + expect(pageSizeChange).toHaveBeenCalled() + }) + + it('test first or lastest pageIndex disabled', async () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + :showJumpButton="true" + /> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 20, + pageIndex: 1 + }) + return { pager } + } + }, globalOption) + + const btns = wrapper.findAll('.devui-pagination-item') + expect(btns[0].classes()).toContain('disabled') + + await btns[btns.length - 2].trigger('click') + const btns1 = wrapper.findAll('.devui-pagination-item') + expect(btns1[btns1.length - 1].classes()).toContain('disabled') + + }) + + it('test lite', () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + totalItemText="Total" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :lite="true" + /> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 10, + pageIndex: 10 + }) + return { pager } + } + }, globalOption) + + expect(wrapper.find('.devui-total-size').text()).toContain('Total') + expect(wrapper.findAll('a.devui-pagination-link').length).toBe(2) + expect(wrapper.find('.devui-jump-container').exists()).toBeFalsy() + }) + + it('test super lite', () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + :showPageSelector="false" + v-model:pageIndex="pager.pageIndex" + :canChangePageSize="true" + :lite="true" + /> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 10, + pageIndex: 10 + }) + return { pager } + } + }, globalOption) + + expect(wrapper.find('.devui-total-size').exists()).toBeFalsy() + expect(wrapper.find('.devui-page-size').exists()).toBeFalsy() + expect(wrapper.findAll('a.devui-pagination-link').length).toBe(2) + expect(wrapper.find('.devui-jump-container').exists()).toBeFalsy() + }) + + it('test haveConfigMenu', async () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + :showPageSelector="false" + v-model:pageIndex="pager.pageIndex" + :canChangePageSize="true" + :lite="true" + :haveConfigMenu="true" + > + <div class="pagination-config-item"> + <div class="config-item-title">show field</div> + <div class="config-item-words">setting</div> + </div> + <div class="pagination-config-item"> + <div class="config-item-title">display method</div> + <div style="padding-left: 8px; margin-top: 4px"> + <i class="icon-list-view"></i> + <i class="icon-veIcon-briefcase"></i> + </div> + </div> + </d-pagination> + `, + setup() { + const pager = reactive({ + total: 306, + pageSize: 10, + pageIndex: 10 + }) + return { pager } + } + }, globalOption) + + expect(wrapper.findAll('a.devui-pagination-link').length).toBe(2) + expect(wrapper.find('.devui-pagination-config').exists()).toBeTruthy() + expect(wrapper.find('.devui-config-container').exists()).toBeFalsy() + + await wrapper.find('.devui-pagination-config').trigger('click') + expect(wrapper.find('.devui-config-container').exists()).toBeTruthy() + expect(wrapper.find('.config-item-words').exists()).toBeTruthy() + expect(wrapper.find('.choosed').text()).toBe('10') + }) + + it('test special', async () => { + const wrapper = mount({ + components: { + DPagination: Pagination + }, + template: ` + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :maxItems="5" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :showTruePageIndex="true" + /> + `, + setup() { + const pager = reactive({ + total: 10, + pageIndex: 3, + pageSize: 10 + }) + return { pager } + } + }, globalOption) + + const btns = wrapper.findAll('.devui-pagination-item') + expect(btns.length).toBe(5) + expect(wrapper.findAll('.devui-pagination-item.disabled').length).toBe(3) + expect(wrapper.find('.devui-pagination-item.active.disabled').text()).toBe('3') + + await btns[0].trigger('click') + expect(wrapper.findAll('.devui-pagination-item').length).toBe(4) + expect(wrapper.findAll('.devui-pagination-item.disabled').length).toBe(2) + + await wrapper.setProps({ + showTruePageIndex: false + }) + + expect(wrapper.findAll('.devui-pagination-item').length).toBe(3) + expect(wrapper.findAll('.devui-pagination-item.disabled').length).toBe(2) + expect(wrapper.find('.devui-pagination-item.active').text()).toBe('1') + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/pagination/index.ts b/packages/devui-vue/devui/pagination/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa7e383c57436c38e33ce3f8c4bebc116df9507b --- /dev/null +++ b/packages/devui-vue/devui/pagination/index.ts @@ -0,0 +1,17 @@ +import { App } from 'vue' +import Pagination from './src/pagination' + +Pagination.install = (app: App): void => { + app.component(Pagination.name, Pagination) +} + +export { Pagination } + +export default { + title: 'Pagination 分页', + category: '导航', + status: '已完成', + install(app: App): void { + app.use(Pagination as any) + } +} diff --git a/packages/devui-vue/devui/pagination/src/components/config-menu.tsx b/packages/devui-vue/devui/pagination/src/components/config-menu.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2f1f1f0bed057041b944f601363ac376f4fa32be --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/components/config-menu.tsx @@ -0,0 +1,76 @@ +import { defineComponent, onMounted, onUnmounted, PropType, ref } from 'vue'; +import { on, off } from '../../../shared/devui-directive/utils' + +import clickoutsideDirective from '../../../shared/devui-directive/clickoutside' + +export default defineComponent({ + directives: { + clickoutside: clickoutsideDirective + }, + props: { + currentPageSize: Number, + pageSizeChange: Function, + pageSizeOptions: Array as PropType<Array<number>> + } as const, + setup() { + const paginationConfig = ref(null) + const isShowConfig = ref(false) + + onMounted(() => { + on(paginationConfig.value, 'click', closeConfigMenu) + }) + onUnmounted(() => { + off(paginationConfig.value, 'click', closeConfigMenu) + }) + const closeConfigMenu = (e: Event) => { + isShowConfig.value = isShowConfig.value ? false : !!e + } + + return { + paginationConfig, + isShowConfig, + closeConfigMenu + } + }, + render() { + const { + closeConfigMenu, + currentPageSize, + pageSizeChange, + pageSizeOptions, + isShowConfig, + $slots + } = this + + return ( + <div class="devui-pagination-config" v-clickoutside={closeConfigMenu} ref="paginationConfig"> + <div class="devui-setup-icon"> + <i class="icon-setting" style="font-weight: bold;"></i> + </div> + { + isShowConfig && + <div class="devui-config-container"> + {$slots.default?.()} + + <div class="pagination-config-item"> + <div class="config-item-title">每页条数</div> + <div class="devui-page-number"> + { + pageSizeOptions.map((v: number) => { + return ( + <div + class={{choosed: v === currentPageSize}} + key={v} + onClick={pageSizeChange.bind(null, {value: v})} + >{v}</div> + ) + }) + } + </div> + </div> + </div> + } + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/pagination/src/components/jump-page.tsx b/packages/devui-vue/devui/pagination/src/components/jump-page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a4e7e2f8bf85c806f0085a3551d168a61a81a99e --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/components/jump-page.tsx @@ -0,0 +1,101 @@ +import { defineComponent, PropType, ref, watch, toRefs, ExtractPropTypes } from 'vue'; + +const jumpPageProps = { + goToText: String, + size: { + type: String as PropType<'lg' | '' | 'sm'>, + default: '' + }, + pageIndex: Number, + showJumpButton: Boolean, + totalPages: Number, + cursor: Number, + onChangeCursorEmit: Function as PropType<(v: number) => void> +} + +type JumpPageProps = ExtractPropTypes<typeof jumpPageProps> + +export default defineComponent({ + props: jumpPageProps, + emits: ['changeCursorEmit'], + setup(props: JumpPageProps, { emit }) { + const { + pageIndex, + totalPages, + cursor + } = toRefs(props) + + // 输入跳转页码 + const inputNum = ref(pageIndex.value) + watch( + () => pageIndex.value, + (val: number) => { + inputNum.value = val + } + ) + let curPage = pageIndex.value + const jumpPageChange = (currentPage: number) => { + curPage = +currentPage + inputNum.value = currentPage + if (isNaN(currentPage)) { + setTimeout(() => { + inputNum.value = pageIndex.value + }, 300) + } + } + // 跳转指定页码 + const jump = (e: KeyboardEvent | 'btn') => { + if (curPage > totalPages.value) { + return + } + if ((e === 'btn' || e.key === 'Enter') && cursor.value !== curPage) { + emit('changeCursorEmit', curPage) + } + } + + return { + inputNum, + jumpPageChange, + jump + } + }, + render() { + const { + goToText, + size, + inputNum, + jumpPageChange, + jump, + showJumpButton + } = this + + return ( + <div class="devui-jump-container"> + {goToText} + + <d-input + class={['devui-pagination-input', size ? 'devui-pagination-input-' + size : '']} + size={size} + value={String(inputNum)} + onUpdate:value={jumpPageChange} + onKeydown={jump} + /> + + { + // TODO 加入国际化后,替换为当前语言为中文的时候加上 '页' + goToText === '跳至' && '页' + } + { + showJumpButton && + <div + class={['devui-jump-button', size ? 'devui-jump-size-' + size : 'devui-jump-size-default']} + onClick={jump.bind(null, 'btn')} + title={goToText} + > + <div class="devui-pagination-go"></div> + </div> + } + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/pagination/src/components/page-nums.tsx b/packages/devui-vue/devui/pagination/src/components/page-nums.tsx new file mode 100644 index 0000000000000000000000000000000000000000..eaccee591e463c646433af9d79c8d9f3d8fd30d9 --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/components/page-nums.tsx @@ -0,0 +1,151 @@ +import { defineComponent, PropType, computed, ExtractPropTypes } from 'vue'; +import { handlePages } from '../utils' + +const pageNumBtnProps = { + size: { + type: String as PropType<'lg' | '' | 'sm'>, + default: '' + }, + preLink: String, + nextLink: String, + lite: Boolean, + cursor: Number, + maxItems: Number, + totalPages: Number, + onChangeCursorEmit: Function as PropType<(v: number) => void>, + showTruePageIndex: Boolean +} as const + +type PageNumBtnProps = ExtractPropTypes<typeof pageNumBtnProps> + +export default defineComponent({ + props: pageNumBtnProps, + emits: ['changeCursorEmit'], + setup(props: PageNumBtnProps, { emit }) { + + // 页码较多时,计算中间的显示页码的起始页码数 + const showPageNum = computed(() => handlePages(props.cursor, props.maxItems, props.totalPages)) + + // 点击页码 + const changeCursor = (pageSize: number) => { + if (isNaN(pageSize)) return + const page = pageSize < 1 ? 1 : pageSize > props.totalPages ? props.totalPages : pageSize | 0 + + emit('changeCursorEmit', page) + } + // 上一页 + const prevChange = (page: number) => { + if (props.cursor > 1) { + const toPage = page === -1 ? props.cursor - 1 : page + + emit('changeCursorEmit', toPage) + } + } + // 下一页 + const nextChange = (page: number) => { + if (props.cursor < props.totalPages) { + const toPage = page === -1 ? props.cursor + 1 : page + + emit('changeCursorEmit', toPage) + } + } + + return { + showPageNum, + changeCursor, + prevChange, + nextChange + } + }, + render() { + const { + size, + preLink, + nextLink, + lite, + changeCursor, + cursor, + showPageNum, + prevChange, + totalPages, + nextChange, + showTruePageIndex + } = this + + return ( + <ul class={['devui-pagination-list', size ? 'devui-pagination-' + size : '']}> + {/* 左侧上一页按钮 */} + <li onClick={prevChange.bind(null, -1)} class={{'devui-pagination-item': true, disabled: cursor <= 1}}> + <a v-html={preLink} class="devui-pagination-link"></a> + </li> + { + !lite && + <> + {/* 页码展示 */} + {/* 单独展示第一页 */} + <li onClick={changeCursor.bind(null, 1)} class={{'devui-pagination-item': true, active: cursor === 1}}> + <a class="devui-pagination-link">1</a> + </li> + { + // 是否展示第一个 ... + showPageNum[0] > 2 && ( + <li onClick={prevChange.bind(null, showPageNum[0] - 1)} class="devui-pagination-item"> + <a class="devui-pagination-link">...</a> + </li> + ) + } + { + // 中间显示页码 + (() => { + const list = [] + for(let i = showPageNum[0]; i <= showPageNum[1]; i++) { + list.push( + <li onClick={changeCursor.bind(null, i)} key={i} class={{'devui-pagination-item': true, active: cursor === i}}> + <a class="devui-pagination-link">{i}</a> + </li> + ) + } + return list + })() + } + { + // 是否展示第二个 ... + showPageNum[1] < totalPages - 1 && ( + <li onClick={nextChange.bind(null, showPageNum[1] + 1)} class="devui-pagination-item"> + <a class="devui-pagination-link">...</a> + </li> + ) + } + { + // 是否单独展示最后一页 + showPageNum[1] < totalPages && ( + <li onClick={changeCursor.bind(null, totalPages)} class={{'devui-pagination-item': true, active: cursor === totalPages}}> + <a class="devui-pagination-link">{totalPages}</a> + </li> + ) + } + { + // 在默认页码超出总页码的时候 + showTruePageIndex && cursor > totalPages && totalPages > 0 && + <> + { + cursor > totalPages + 1 && + <li class="devui-pagination-item disabled"> + <a class="devui-pagination-link">...</a> + </li> + } + <li class="devui-pagination-item disabled active"> + <a class="devui-pagination-link">{ cursor }</a> + </li> + </> + } + </> + } + {/* 右侧下一页按钮 */} + <li onClick={nextChange.bind(null, -1)} class={{'devui-pagination-item': true, disabled: cursor >= totalPages}}> + <a v-html={nextLink} class="devui-pagination-link"></a> + </li> + </ul> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/pagination/src/pagination.scss b/packages/devui-vue/devui/pagination/src/pagination.scss new file mode 100644 index 0000000000000000000000000000000000000000..c950daef8cf0c4e0bbe9c26f569fb3d6ac4eed35 --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/pagination.scss @@ -0,0 +1,303 @@ +@import '../../style/theme/color'; +@import '../../style/theme/_corner'; +@import '../../style/core/_font'; + +.devui-pagination { + font-size: var(--devui-font-size, 12px); + + .devui-page-size { + display: inline-block; + max-width: 100px; + line-height: 24px; + margin: 0 12px 0 0; + position: relative; + vertical-align: middle; + + &.devui-page-size-sm { + max-width: 80px; + + .devui-select-input { + height: 24px; + } + } + + &.devui-page-size-lg { + max-width: 100px; + + .devui-select-input { + height: 46px; + } + + .devui-select-item { + height: 46px; + } + } + } + + .devui-select-input { + height: 26px; + } + + .devui-total-size { + display: inline-block; + position: relative; + vertical-align: middle; + margin: 0 12px 0 0; + color: var(--devui-text-weak, #575d6c); + } + + .devui-pagination-list, + .devui-pagination-item { + padding: 0; + margin: 0; + list-style: none; + } + + a { + text-decoration: none; + color: #3eaf7c; + } + + .devui-pagination-list { + vertical-align: middle; + display: inline-flex; + align-items: center; + + li.devui-pagination-item { + cursor: pointer; + + &.active { + a.devui-pagination-link { + text-decoration: none; + background-color: var(--devui-list-item-active-bg, #5e7ce0); + color: var(--devui-list-item-active-text, #ffffff); + } + } + + &.disabled { + a.devui-pagination-link { + cursor: not-allowed; + opacity: 0.5; + background-color: #ffffff; + color: var(--devui-text-weak, #575d6c); + } + } + + .devui-pagination-link { + margin-left: 5px; + padding: 3px 7px; + line-height: 1.5; + border-radius: var(--devui-border-radius, 2px); + color: var(--devui-text-weak, #575d6c); + display: flex; + align-items: center; + transition: background-color var(--devui-animation-duration-slow, 0.3s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(0.645, 0.045, 0.355, 1)); + + &:hover { + text-decoration: none; + background-color: var(--devui-list-item-hover-bg, #f2f5fc); + color: var(--devui-list-item-hover-text, #526ecc); + } + } + } + } + + .devui-pagination-sm > li.devui-pagination-item > a.devui-pagination-link { + padding: 0 5px; + min-width: 18px; + height: 22px; + line-height: 1.5; + font-size: $devui-font-size-sm; + } + + .devui-pagination-lg > li.devui-pagination-item > a.devui-pagination-link { + padding: 0 12px; + height: 38px; + font-size: $devui-font-size-lg; + line-height: 1.5; + } + + .devui-jump-container { + display: inline-flex; + position: relative; + margin: 0 12px; + vertical-align: middle; + align-items: center; + + .devui-pagination-input { + display: inline-block; + width: 42px; + vertical-align: middle; + margin: 0 3px; + } + + .devui-pagination-input-lg { + width: 56px; + } + } + + .devui-jump-button { + display: inline-flex; + vertical-align: middle; + width: 24px; + height: 24px; + border-radius: var(--devui-border-radius, 2px); + border: 1px solid var(--devui-line, #adb0b8); + cursor: pointer; + margin-left: 4px; + align-items: center; + justify-content: center; + + .devui-pagination-go { + width: 0; + height: 0; + border-top: 6px solid transparent; + border-left: 6px solid var(--devui-icon-text, #252b3a); + border-bottom: 6px solid transparent; + } + + &:hover { + border-color: $devui-brand-active; + + .devui-pagination-go { + border-left-color: $devui-brand-active; + } + } + } + + .devui-jump-size-default { + width: 28px; + height: 28px; + + .devui-pagination-go { + width: 0; + height: 0; + border-top: 8px solid transparent; + border-left: 10px solid $devui-icon-text; + border-bottom: 8px solid transparent; + } + } + + .devui-jump-size-sm { + width: 24px; + height: 24px; + + .devui-pagination-go { + width: 0; + height: 0; + border-top: 6px solid transparent; + border-left: 6px solid $devui-icon-text; + border-bottom: 6px solid transparent; + } + + .devui-pagination-link { + height: 30px; + line-height: 32px; + } + } + + .devui-jump-size-lg { + width: 46px; + height: 46px; + + .devui-pagination-go { + width: 0; + height: 0; + border-top: 14px solid transparent; + border-left: 14px solid $devui-icon-text; + border-bottom: 14px solid transparent; + } + } + + .devui-pagination-config { + color: var(--devui-text, #252b3a); + position: relative; + display: inline-block; + vertical-align: middle; + margin: 0 4px; + } + + .devui-setup-icon { + line-height: 30px; + cursor: pointer; + display: flex; + } + + .devui-config-container { + padding: 4px 0; + box-shadow: var(--devui-shadow-connected-overlay, 0 2px 8px 0) var(--devui-shadow, rgba(0, 0, 0, 0.2)); + border-radius: var(--devui-border-radius, 2px); + width: 150px; + background-color: var(--devui-connected-overlay-bg, #ffffff); + line-height: 26px; + position: absolute; + left: -136px; + top: 28px; + cursor: auto; + z-index: var(--devui-z-index-dropdown, 1052); + user-select: none; + } + + /* 配置中的每一项,自定义项建议应用此样式或在此基础上修改 */ + .pagination-config-item { + padding-bottom: 8px; + padding-top: 4px; + border-bottom: 1px solid $devui-line; + + &:last-child { + border-bottom: none; + } + } + + /* 配置中每一项的标题样式,自定义项建议应用此样式或在此基础上修改 */ + .config-item-title { + color: $devui-line; + padding-left: 8px; + font-size: $devui-font-size; + line-height: 1.5; + } + + .devui-page-number { + padding-left: 8px; + margin-top: 4px; + display: flex; + + div { + color: var(--devui-text, #252b3a); + cursor: pointer; + border-top: 1px solid var(--devui-line, #adb0b8); + border-bottom: 1px solid var(--devui-line, #adb0b8); + border-right: 1px solid var(--devui-line, #adb0b8); + text-align: center; + height: 26px; + width: 26px; + + &:first-child { + border-left: 1px solid var(--devui-line, #adb0b8); + } + + &:hover { + background-color: var(--devui-list-item-hover-bg, #f2f5fc); + color: var(--devui-list-item-hover-text, #526ecc); + } + + &.choosed { + color: var(--devui-list-item-active-text, #ffffff); + background-color: var(--devui-list-item-active-bg, #5e7ce0) !important; + cursor: auto !important; + } + } + } + + .config-item-words { + color: $devui-text; + padding-left: 8px; + font-size: $devui-font-size; + margin-top: 4px; + } + + .config-item-words:hover { + background-color: $devui-area; + cursor: pointer; + } +} diff --git a/packages/devui-vue/devui/pagination/src/pagination.tsx b/packages/devui-vue/devui/pagination/src/pagination.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a27c319bc5db3d4101f368119f9a7608d99b2b35 --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/pagination.tsx @@ -0,0 +1,198 @@ +import { defineComponent, computed, nextTick } from 'vue' +import { ComponentProps, componentProps } from './use-pagination' +import { liteSelectOptions } from './utils' + +import ConfigMenu from './components/config-menu' +import JumpPage from './components/jump-page' +import PageNumBtn from './components/page-nums' + +import './pagination.scss' + +export default defineComponent({ + name: 'DPagination', + components: { + ConfigMenu, + JumpPage, + PageNumBtn + }, + props: componentProps, + emits: ['pageIndexChange', 'pageSizeChange', 'update:pageSize', 'update:pageIndex'], + setup(props: ComponentProps, { emit }) { + + // 极简模式下,可选的下拉选择页码 + const litePageOptions = computed(() => liteSelectOptions(totalPages.value)) + + // 当前页码 + const cursor = computed({ + get() { + // 是否需要修正错误的pageIndex + if (!props.showTruePageIndex && props.pageIndex > totalPages.value) { + emit('update:pageIndex', totalPages.value || 1) + return totalPages.value || 1 + } + return props.pageIndex || 1 + }, + set(val: number) { + emit('update:pageIndex', val) + } + }) + // 每页显示最大条目数量 + const currentPageSize = computed({ + get() { + return props.pageSize + }, + set(val: number) { + emit('update:pageSize', val) + } + }) + // 总页数 + const totalPages = computed(() => Math.ceil(props.total / props.pageSize)) + + const changeCursorEmit = (val: number) => { + cursor.value = val + emit('pageIndexChange', val) + } + + // 每页条数改变 + const pageSizeChange = (val: Record<string, string | number>) => { + currentPageSize.value = val.value as number + // 页数改变后,如果当前页码超出最大页码时修正 + if (props.autoFixPageIndex) { + nextTick(() => { + if (cursor.value > totalPages.value) { + changeCursorEmit(totalPages.value) + } + }) + } + emit('pageSizeChange', val.value as number) + } + // 极简模式下的跳转页码 + const litePageIndexChange = (page: {name: string; value: number;}) => { + changeCursorEmit(page.value) + } + + return { + cursor, + totalPages, + changeCursorEmit, + currentPageSize, + pageSizeChange, + litePageOptions, + litePageIndexChange + } + }, + render() { + + const { + total, + pageIndex, + pageSizeOptions, + pageSizeDirection, + preLink, + nextLink, + size, + canJumpPage, + canChangePageSize, + canViewTotal, + totalItemText, + goToText, + maxItems, + showJumpButton, + showTruePageIndex, + lite, + showPageSelector, + haveConfigMenu, + autoHide, + $slots, + + cursor, + totalPages, + currentPageSize, + pageSizeChange, + changeCursorEmit, + litePageOptions, + litePageIndexChange + } = this + + return ( + // autoHide为 true 并且 pageSizeOptions最小值 > total 不展示分页 + autoHide && Math.min(...pageSizeOptions) > total + ? null + : <div class="devui-pagination"> + { + canChangePageSize && !lite && + <div class={['devui-page-size', size ? 'devui-page-size-' + size : '']}> + <d-select + options={pageSizeOptions} + modelValue={currentPageSize} + onValueChange={pageSizeChange} + pageSizeDirection={pageSizeDirection} + /> + </div> + } + { + // 总页数显示 + ((!lite || (lite && showPageSelector)) && canViewTotal) && + <div class="devui-total-size">{totalItemText}: {total}</div> + } + { + // 极简模式下的选择页码下拉框 + lite && showPageSelector && + <div class="devui-page-size"> + <d-select + options={litePageOptions} + disabled={total === 0} + modelValue={cursor} + onValueChange={litePageIndexChange} + pageSizeDirection={pageSizeDirection} + /> + </div> + } + + {/* 页码展示 */} + <page-num-btn + {...{ + cursor, + totalPages, + size, + lite, + maxItems, + preLink, + nextLink, + showTruePageIndex + }} + onChangeCursorEmit={changeCursorEmit} + /> + + { + // 跳转页码 + canJumpPage && !lite && + <jump-page + {...{ + goToText, + size, + pageIndex, + totalPages, + cursor, + showJumpButton + }} + onChangeCursorEmit={changeCursorEmit} + /> + } + { + // 极简模式下是否显示配置 + lite && haveConfigMenu && + <config-menu + {...{ + currentPageSize, + pageSizeChange, + pageSizeOptions + }} + > + {$slots.default?.()} + </config-menu> + } + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/pagination/src/use-pagination.ts b/packages/devui-vue/devui/pagination/src/use-pagination.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6663598c32a3fd3beaf84043e49fe6fea18b5c8 --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/use-pagination.ts @@ -0,0 +1,120 @@ +import { PropType, ExtractPropTypes } from 'vue'; + +type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; + +interface ConnectedPosition { + originX : 'start' | 'center' | 'end' + originY : 'top' | 'center' | 'bottom' + + overlayX : 'start' | 'center' | 'end' + overlayY : 'top' | 'center' | 'bottom' + + weight ?: number + offsetX ?: number + offsetY ?: number + panelClass ?: string | string[] +} + +type Size = 'lg' | '' | 'sm' + +export const componentProps = { + pageSize: { + type: Number, + default: 10 + }, + total: { + type: Number, + default: 0 + }, + pageSizeOptions: { + type: Array as PropType<number[]>, + default: () => [5, 10, 20, 50] + }, + pageSizeDirection: { + type: Array as PropType<Array<AppendToBodyDirection | ConnectedPosition>>, + default: () => ['centerDown', 'centerUp'] + }, + pageIndex: { + type: Number, + default: 1 + }, + maxItems: { + type: Number, + default: 10 + }, + preLink: { + type: String, + default: '<' + }, + nextLink: { + type: String, + default: '>' + }, + size: { + type: String as PropType<Size>, + default: '' + }, + canJumpPage: { + type: Boolean, + default: false + }, + canChangePageSize: { + type: Boolean, + default: false + }, + canViewTotal: { + type: Boolean, + default: false + }, + totalItemText: { + type: String, + default: '所有条目' + }, + goToText: { + type: String, + default: '跳至' + }, + showJumpButton: { + type: Boolean, + default: false + }, + showTruePageIndex: { + type: Boolean, + default: false + }, + lite: { + type: Boolean, + default: false + }, + showPageSelector: { + type: Boolean, + default: true + }, + haveConfigMenu: { + type: Boolean, + default: false + }, + autoFixPageIndex: { + type: Boolean, + default: true + }, + autoHide: { + type: Boolean, + default: false + }, + 'onUpdate:pageIndex': { + type: Function as PropType<(v: number) => void> + }, + 'onUpdate:pageSize': { + type: Function as PropType<(v: number) => void> + }, + 'onPageIndexChange': { + type: Function as PropType<(v: number) => void> + }, + 'onPageSizeChange': { + type: Function as PropType<(v: number) => void> + } +} as const + +// 组件props +export type ComponentProps = ExtractPropTypes<typeof componentProps> diff --git a/packages/devui-vue/devui/pagination/src/utils.ts b/packages/devui-vue/devui/pagination/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..095b5a4360977206b12f191d630dcf38c25b8a66 --- /dev/null +++ b/packages/devui-vue/devui/pagination/src/utils.ts @@ -0,0 +1,42 @@ +/** + * 功能函数 + */ + +// 处理页码显示 +// 1 ... 5 6 7 8 ... 11 +export const handlePages = (cursor: number, maxItems: number, totalPages: number): number[] => { + const currentPage = cursor // 当前页码 + const maxPages = maxItems // 能显示的最大页码 + if (maxPages >= totalPages) { + return [2, totalPages] + } + + const midPages = maxPages - 2 // 中间显示的页码 + // 1 ... 5 6 7 8 ... 11 + // 获取 5 和 8 + let midStart = currentPage - (midPages >> 1) + let midEnd = currentPage + (midPages - 1 >> 1) + + if (midStart < 2) { + midStart = 2 + midEnd = maxPages - 2 + } + + if (midEnd > totalPages) { + midStart = totalPages - maxPages + 3 + midEnd = totalPages + } + + return [midStart, midEnd] +} + +// 处理极简模式下的页码下拉多选显示 +export function liteSelectOptions(total: number): Array<{name: string; value: number;}> { + return new Array(total || 1).fill(0).map((v: number, index: number) => { + return { + name: `${index + 1}/${total}`, + value: index + 1 + } + }) +} + diff --git a/packages/devui-vue/devui/panel/__tests__/panel.spec.ts b/packages/devui-vue/devui/panel/__tests__/panel.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a7b0ce7665bc4d3dc854e8f3083e75e0c9cd7a2 --- /dev/null +++ b/packages/devui-vue/devui/panel/__tests__/panel.spec.ts @@ -0,0 +1,137 @@ +import { shallowMount,mount } from "@vue/test-utils"; +import {ref,nextTick,Transition } from 'vue'; +import DButton from '../../button/index'; +import DPanel from '../src/panel' +import DPanelHeader from '../src/header/panel-header'; +import DPanelBody from '../src/body/panel-body'; +import DPanelFooter from '../src/foot/panel-footer'; + + +describe('DPanel',()=>{ + + // 渲染测试 + it('Render',()=>{ + // except(wrapper.html()) + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + <d-panel> + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + `, + }); + expect(wrapper.find('transition-stub').html()).toContain('<transition-stub><!----></transition-stub>'); + }) + + it('isCollapsed', async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + <d-panel :isCollapsed="isCollapsed"> + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + `, + setup(){ + let isCollapsed = ref(false); + return {isCollapsed} + } + }); + expect(wrapper.find('.devui-panel .devui-panel-default').element.children[0].innerHTML).toBe('<!---->'); + }) + // // 动态hasLeftPadding 测试 + it('padding-dynamic', async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + <d-panel :hasLeftPadding = "leftPadding" isCollapsed> + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + <br /><br /> + <d-button @click="leftPadding = !leftPadding" > + 切换LeftPadding + </d-button> + `, + setup(){ + let leftPadding = ref(false); + return { + leftPadding, + } + } + }); + expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(3); + await wrapper.find('button').trigger('click'); + expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(2); + }) + + + it('beforeToggle-dynamic',async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + <d-panel :beforeToggle="beforeToggle" isCollapsed> + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + <br /><br /> + <d-button @click="panelToggle = !panelToggle" > + {{ panelToggle ? '阻止折叠' : '允许折叠' }} + </d-button> + `, + setup(){ + let panelToggle = ref(false); + const beforeToggle = () => panelToggle.value; + return { + panelToggle, + beforeToggle, + } + } + }); + await wrapper.find('button').trigger('click'); + expect(wrapper.vm.panelToggle).toBe(true); + await wrapper.find('button').trigger('click'); + expect(wrapper.vm.panelToggle).toBe(false); + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/index.ts b/packages/devui-vue/devui/panel/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..56eaba1e71bd0c1e7dc24f381a7b83273a9979e5 --- /dev/null +++ b/packages/devui-vue/devui/panel/index.ts @@ -0,0 +1,24 @@ +import type { App } from 'vue' +import Panel from './src/panel' +import PanelHeader from './src/header/panel-header'; +import PanelBody from './src/body/panel-body'; +import PanelFooter from './src/foot/panel-footer'; + +Panel.install = function(app: App) { + app.component(Panel.name, Panel) + app.component(PanelHeader.name, PanelHeader); + app.component(PanelBody.name, PanelBody); + app.component(PanelFooter.name, PanelFooter); +} + +export { Panel } + +export default { + title: 'Panel 面板', + category: '通用', + status: '100%', + install(app: App): void { + app.use(Panel as any) + } +} + diff --git a/packages/devui-vue/devui/panel/src/body/panel-body.tsx b/packages/devui-vue/devui/panel/src/body/panel-body.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a7827f365ef07c05a6d6186de037011bc2ae676 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/body/panel-body.tsx @@ -0,0 +1,51 @@ +import { defineComponent,ref,onMounted,Transition,inject,Ref } from 'vue'; +import { PanelProps } from '../panel.type'; +import Store from '../store/store'; + +export default defineComponent({ + name: 'DPanelBody', + props:PanelProps, + setup(props,ctx){ + let animationName = inject('showAnimation') as Ref<any>; + let hasLeftPadding = inject('hasLeftPadding') as Ref<any>; + const keys = Object.keys(Store.state()); + const key = keys.pop(); + const isCollapsed = Store.state(); + const bodyEl = ref(); + onMounted(() => { + if(bodyEl.value) { + const dom = bodyEl.value; + if(isCollapsed[key]) + dom.style.height = `${dom.offsetHeight}px`; + } + }) + + const enter = (element: Element ) => { + const el = (element as HTMLElement); + el.style.height = ''; + const height = el.offsetHeight; + el.style.height = '0px'; + // 需要执行一次才会生效 + el.offsetHeight; + el.style.height = `${height}px`; + } + const leave = (element: Element) => { + const el = (element as HTMLElement); + el.style.height = '0px'; + } + return () => { + return ( + <div class={`devui-panel devui-panel-${props.type} ${props.cssClass}`}> + <Transition name={animationName.value ? 'devui-panel' : ''} onEnter={ enter } onLeave={leave}> + {isCollapsed[key] === undefined || isCollapsed[key] ? + <div ref={bodyEl} class={`devui-panel-body ${isCollapsed[key] !== undefined ? 'devui-panel-body-collapse': ''} ${!hasLeftPadding.value ? 'no-left-padding' : ''}`}> + <div class="devui-panel-content"> + {ctx.slots.default?.()} + </div> + </div>: null } + </Transition> + </div> + ) + } + }, +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/src/foot/panel-footer.tsx b/packages/devui-vue/devui/panel/src/foot/panel-footer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..65d7a3ad6e53d042558a2f1d1402e31ec22ab4a3 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/foot/panel-footer.tsx @@ -0,0 +1,14 @@ +import {ref,defineComponent} from 'vue'; + +export default defineComponent({ + name: 'DPanelFooter', + setup(props,ctx){ + return () => { + const footerContent = (ctx.slots.default ? + <div class="devui-panel-footer"> + { ctx.slots.default?.() } + </div> : null); + return footerContent + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/src/header/panel-header.tsx b/packages/devui-vue/devui/panel/src/header/panel-header.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9b8c7a4c15e880cfe7ee9ce05431b57f7f0aa986 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/header/panel-header.tsx @@ -0,0 +1,70 @@ +import { defineComponent,ref,inject } from 'vue'; +import {PanelProps} from '../panel.type'; +import Store from '../store/store'; + +export default defineComponent({ + name: 'DPanelHeader', + props: PanelProps, + setup(props,ctx){ + const beforeToggle = inject('beforeToggle'); + const keys = Object.keys(Store.state()); + const key = keys.pop(); + const isCollapsed = ref(Store.state()[key]); + // 当beforeToggle为fals时 + // 最好cursor是default 而不是 pointer; + // pointer一般用于可点击的 + // 用changeFlag + let changeFlag = ref(); + let header = null; + + + const canToggle = (): Promise<boolean> => { + let changeResult = Promise.resolve(true); + if(beforeToggle) { + const result = beforeToggle(isCollapsed); + if(typeof result !== undefined) { + if(result instanceof Promise) { + changeResult = result; + } else { + changeResult = Promise.resolve(result); + } + } + } + return changeResult; + } + + // 需要执行一次才能生效; + canToggle().then((val)=>changeFlag.value = val) + + const toggleBody = (): void => { + canToggle().then((val) => { + changeFlag.value = val; + if (!val){ + // 禁止折叠不影响展开 + if (!isCollapsed.value){ + Store.setData(`${key}`, !isCollapsed.value); + isCollapsed.value = !isCollapsed.value; + props.toggle?.(isCollapsed.value); + } + return; + } + if (isCollapsed.value !== undefined) { + Store.setData(`${key}`, !isCollapsed.value); + isCollapsed.value = !isCollapsed.value; + props.toggle?.(isCollapsed.value); + } + }) + + }; + return () => { + if (ctx.slots.default){ + header = ( + <div class="devui-panel-heading" onClick={toggleBody} style={{ 'cursor': changeFlag.value ? 'pointer' : 'auto' }}> + {ctx.slots.default?.()} + </div> + ) + } + return header + } + }, +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/src/panel.scss b/packages/devui-vue/devui/panel/src/panel.scss new file mode 100644 index 0000000000000000000000000000000000000000..76ab896446dded584c1060a274f615b42c96e670 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/panel.scss @@ -0,0 +1,173 @@ +@import '../../style/theme/color'; + +.no-left-padding { + &.devui-panel-body-collapse { + &::before { + content: none !important; + } + + .devui-panel-content { + border-left: none !important; + } + } +} + +.devui-panel { + line-height: 1.5; + background-color: $devui-base-bg; + + .devui-panel-heading { + padding: 12px 20px; + color: $devui-text; + + d-panel-header { + line-height: 1.5; + } + } + + + .devui-panel-body { + display: flex; + position: relative; + border-top: 1px solid $devui-dividing-line; + + .devui-panel-content { + line-height: 1.5; + padding: 15px; + background: $devui-base-bg; + flex: 1; + } + + &.devui-panel-body-collapse { + &::before { + content: ''; + width: 30px; + height: 100%; + } + + .devui-panel-content { + border-left: 2px solid $devui-dividing-line; + } + } + } + + .devui-panel-footer { + padding: 10px 15px; + color: $devui-text; + background-color: $devui-area; + + d-panel-footer { + line-height: 1.5; + } + } + + &.devui-panel-default { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-default-bg; + } + } + + &.devui-panel-primary { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-primary-bg; + } + + .devui-panel-body-collapse { + .devui-panel-content { + border-color: $devui-primary-line; + } + } + } + + &.devui-panel-info { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-info-bg; + } + + .devui-panel-body-collapse { + .devui-panel-content { + border-color: $devui-info-line; + } + } + } + + &.devui-panel-success { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-success-bg; + } + + .devui-panel-body-collapse { + .devui-panel-content { + border-color: $devui-success-line; + } + } + } + + &.devui-panel-warning { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-warning-bg; + } + + .devui-panel-body-collapse { + .devui-panel-content { + border-color: $devui-warning-line; + } + } + } + + &.devui-panel-danger { + .devui-panel-heading, + .devui-panel-body { + background-color: $devui-danger-bg; + } + + .devui-panel-body-collapse { + .devui-panel-content { + border-color: $devui-danger-line; + } + } + } + + .devui-panel-leave-active { + transition: all 0.3s ease-in-out; + animation: panelUpOut 0.3s ease-in-out; + animation-fill-mode: both; + } + + .devui-panel-enter-active { + transition: all 0.3s ease-in-out; + animation: panelUpIn 0.3s ease-in-out; + animation-fill-mode: both; + } + @keyframes panelUpOut { + 0% { + transform: scaleY(1); + transform-origin: 0% 0%; + opacity: 1; + } + + 100% { + transform: scaleY(0); + transform-origin: 0% 0%; + opacity: 0; + } + } + @keyframes panelUpIn { + 0% { + transform: scaleY(0); + transform-origin: 0% 0%; + opacity: 0; + } + + 100% { + transform: scaleY(1); + transform-origin: 0% 0%; + opacity: 1; + } + } +} diff --git a/packages/devui-vue/devui/panel/src/panel.tsx b/packages/devui-vue/devui/panel/src/panel.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5c601aee231c63e8cf41b4c4d3e4494c55eba6cc --- /dev/null +++ b/packages/devui-vue/devui/panel/src/panel.tsx @@ -0,0 +1,29 @@ +import { defineComponent, ref, provide, computed} from 'vue'; +import './panel.scss'; +import { PanelProps } from './panel.type'; +import Store from './store/store'; + +export default defineComponent({ + name: 'DPanel', + props: PanelProps, + setup(props, ctx) { + provide('beforeToggle', props.beforeToggle); + provide('showAnimation', computed(()=>props.showAnimation)); + provide('hasLeftPadding', computed(()=>props.hasLeftPadding)); + const isCollapsed = ref(props.isCollapsed); + const type = computed(()=>props.type); + const cssClass = computed(()=>props.cssClass); + const onToggle = ()=> { + props.toggle?.(Store.getByKey(`isCollapsed[${timeStamp}]`)) + }; + const timeStamp = new Date().getTime().toString(); + Store.setData(`isCollapsed[${timeStamp}]`, isCollapsed.value); + return () => { + return ( + <div onClick = {onToggle} class={`devui-panel devui-panel-${type.value} ${cssClass.value}`}> + {ctx.slots.default?.()} + </div> + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/src/panel.type.ts b/packages/devui-vue/devui/panel/src/panel.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed23606652499788f8776bc3d70316e5c9c95e15 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/panel.type.ts @@ -0,0 +1,36 @@ +import {ExtractPropTypes} from 'vue'; + +export type PanelType = 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info'; + +export const PanelProps = { + type: { + type: String as () => PanelType, + default: 'default' + }, + cssClass: { + type: String, + default: '' + }, + isCollapsed: { + type: Boolean, + default: false + }, + beforeToggle: { + type: Function as unknown as () => (value: boolean) => boolean | Promise<boolean>, + default: null + }, + toggle: { + type: Function as unknown as ()=> ((value: boolean) => void), + default: null + }, + showAnimation: { + type: Boolean, + default: true, + }, + hasLeftPadding:{ + type: Boolean, + default: true, + } +} + +export type PanelPropsType = ExtractPropTypes<typeof PanelProps>; \ No newline at end of file diff --git a/packages/devui-vue/devui/panel/src/store/store.ts b/packages/devui-vue/devui/panel/src/store/store.ts new file mode 100644 index 0000000000000000000000000000000000000000..d274bff2952b6bc4275d10671f49b9720e47f8a0 --- /dev/null +++ b/packages/devui-vue/devui/panel/src/store/store.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import {ref,reactive} from 'vue'; + +export const option = reactive({}) + +class Store { + public static getByKey(timeStamp){ + return option[timeStamp]; + } + public static state() { + return option; + } + public static setData(key,value){ + option[key] = ref(value); + } +} + +export default Store \ No newline at end of file diff --git a/packages/devui-vue/devui/popover/__tests__/popover.spec.ts b/packages/devui-vue/devui/popover/__tests__/popover.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..699d892214d613a444c317e219d6a20ddb0dc5e3 --- /dev/null +++ b/packages/devui-vue/devui/popover/__tests__/popover.spec.ts @@ -0,0 +1,96 @@ +import {shallowMount } from '@vue/test-utils'; +import DPopover from '../src/popover' +describe('DPopover', () => { + it('visible', () => { + const wrapper = shallowMount(DPopover, { + props: { + visible: true + } + }) + expect(wrapper.props().visible).toBeTruthy() + expect(wrapper.classes().includes('devui-popover-isVisible')).toBeTruthy() + }) + + it('position', () => { + const left = 'left' + const wrapper = shallowMount(DPopover, { + props: { + position: left + } + }) + expect(wrapper.props().position).toBe(left) + expect(wrapper.classes().includes(left)).toBeTruthy() + }) + + it('content', () => { + const content = '自定义内容' + const wrapper = shallowMount(DPopover, { + props: { + content + } + }) + expect(wrapper.props().content).toBe(content) + expect(wrapper.find('.devui-popover-content').text()).toBe(content) + }) + + it('trigger click', async () => { + const wrapper = shallowMount(DPopover) + const isVisible = () => expect(wrapper.classes().includes('devui-popover-isVisible')) + isVisible().toBeFalsy() + await wrapper.find('.devui-popover-reference').trigger('click') + isVisible().toBeTruthy(); + }) + + it('trigger mouse', async () => { + const wrapper = shallowMount(DPopover, { + props: { + trigger: 'hover' + } + }) + const isVisible = () => expect(wrapper.classes().includes('devui-popover-isVisible')) + isVisible().toBeFalsy() + wrapper.find('.devui-popover-reference').trigger('onMouseenter') + wrapper.vm.$nextTick(() => { + isVisible().toBeTruthy() + }) + }) + + it('zIndex', () => { + const zIndex = 1000 + const wrapper = shallowMount(DPopover, { + props: { + zIndex + } + }) + expect(wrapper.props().zIndex).toBe(zIndex); + }) + + it('popType', () => { + const wrapper = shallowMount(DPopover, { + props: { + popType: 'warning' + } + }) + expect(wrapper.find('.devui-popover-icon').attributes().name).toBe('warning-o') + }) + + it('showAnimation', () => { + const wrapper = shallowMount(DPopover, { + props: { + showAnimation: false, + } + }) + expect(wrapper.classes().includes('devui-popover-animation')).toBeFalsy() + }) + + it('popMaxWidth', () => { + const popMaxWidth = 30 + const wrapper = shallowMount(DPopover, { + props: { + popMaxWidth + } + }) + expect(wrapper.props().popMaxWidth).toBe(popMaxWidth) + }) + +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/popover/index.ts b/packages/devui-vue/devui/popover/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d9070c3656c29051f4fd1a6a1f45c62283390c6 --- /dev/null +++ b/packages/devui-vue/devui/popover/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Popover from './src/popover' + +Popover.install = function (app: App): void { + app.component(Popover.name, Popover) +} + +export { Popover } + +export default { + title: 'Popover 悬浮提示', + category: '反馈', + status: '已完成', + install(app: App): void { + app.use(Popover as any); + } +} diff --git a/packages/devui-vue/devui/popover/src/debounce.ts b/packages/devui-vue/devui/popover/src/debounce.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9e0115be26301e123b8e44bb28e165fa9eb4f24 --- /dev/null +++ b/packages/devui-vue/devui/popover/src/debounce.ts @@ -0,0 +1,9 @@ +export default ( callBack,wait: number) => { + let time = null + return () => { + time && clearTimeout(time); + time = setTimeout(() => { + callBack?.() + }, wait) + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/popover/src/popover.scss b/packages/devui-vue/devui/popover/src/popover.scss new file mode 100644 index 0000000000000000000000000000000000000000..4923d1df120a3b5b2bd847f84480266e35746997 --- /dev/null +++ b/packages/devui-vue/devui/popover/src/popover.scss @@ -0,0 +1,309 @@ +@import '../../style/theme/color'; +@import '../../style//theme//corner'; +@import '../../style//theme/font'; +@import '../../style//theme//animation'; + +$devui-popover-margin: -8px; +$devui-popover-width: -6px; +$devui-popover-offset: 8px; + +@mixin some-display { + display: inline-flex; +} + +.devui-popover { + position: relative; + @include some-display; + + &.devui-popover-isVisible { + .devui-popover-content { + @include some-display; + } + } + + .devui-popover-content { + position: absolute; + display: none; + padding: 5px 14px; + align-items: center; + flex-wrap: wrap; + white-space: nowrap; + border-radius: $devui-border-radius-feedback; + color: $devui-feedback-overlay-text; + background-color: $devui-feedback-overlay-bg; + font-size: $devui-font-size-sm; + + .after { + content: ''; + width: 12px; + height: 12px; + transform: rotate(45deg); + position: absolute; + background-color: $devui-feedback-overlay-bg; + } + + &.is-icon { + flex-wrap: nowrap; + } + + .devui-popover-icon { + margin-right: 5px; + } + } +} + +@keyframes some-animation { + 0% { + opacity: 0; + @include some-display; + } + + 100% { + opacity: 1; + } +} + +//动画效果 +.devui-popover { + &.devui-popover-animation { + @mixin some-animation { + animation: some-animation 0.5s $devui-animation-linear 1 forwards; + } + + .devui-popover-content { + @include some-animation; + } + } +} + +//left等方向 +.devui-popover { + @mixin left-postion--content { + left: $devui-popover-margin; + top: 0; + transform: translate(-100%, 0); + } + @mixin left-postion--after { + right: $devui-popover-width; + top: 50%; + margin-top: $devui-popover-width; + margin-left: $devui-popover-margin; + } + + &.left { + .devui-popover-content { + @include left-postion--content; + + top: 50%; + transform: translate(-100%, -50%); + } + + .after { + @include left-postion--after; + } + } + + &.left-top { + .devui-popover-content { + @include left-postion--content; + } + + .after { + @include left-postion--after; + + top: $devui-popover-offset; + margin-top: auto; + } + } + + &.left-bottom { + .devui-popover-content { + @include left-postion--content; + + top: auto; + bottom: 0; + } + + .after { + @include left-postion--after; + + bottom: $devui-popover-offset; + margin-top: auto; + } + } +} + +// //top等方向 +.devui-popover { + @mixin top-postion--content { + top: $devui-popover-margin; + left: 0; + transform: translate(0, -100%); + } + @mixin top-postion--after { + bottom: $devui-popover-width; + margin-left: $devui-popover-width; + } + + &.top { + .devui-popover-content { + @include top-postion--content; + + left: 50%; + transform: translate(-50%, -100%); + } + + .after { + left: 50%; + @include top-postion--after; + } + } + + &.top-left { + .devui-popover-content { + @include top-postion--content; + } + + .after { + @include top-postion--after; + + left: $devui-popover-offset; + margin-left: auto; + margin-right: $devui-popover-width; + } + } + + &.top-right { + .devui-popover-content { + @include top-postion--content; + + left: auto; + right: 0; + } + + .after { + @include top-postion--after; + + right: $devui-popover-offset; + } + } +} + +//right等方向 +.devui-popover { + @mixin right-postion--content { + right: $devui-popover-margin; + top: 50%; + transform: translate(100%, 0); + } + @mixin right-postion--after { + left: $devui-popover-width; + margin-right: $devui-popover-width; + top: $devui-popover-offset; + } + + &.right { + .devui-popover-content { + @include right-postion--content; + + transform: translate(100%, -50%); + } + + .after { + @include right-postion--after; + + top: 50%; + margin-top: $devui-popover-width; + } + } + + &.right-top { + .devui-popover-content { + @include right-postion--content; + + top: 0; + } + + .after { + @include right-postion--after; + } + } + + &.right-bottom { + .devui-popover-content { + @include right-postion--content; + + bottom: 0; + top: auto; + } + + .after { + @include right-postion--after; + + top: auto; + bottom: $devui-popover-offset; + } + } +} + +//bottom等方向 +.devui-popover { + @mixin bottom-postion--content { + left: 0; + bottom: 0; + margin-bottom: $devui-popover-width; + transform: translate(0, 100%); + } + @mixin bottom-postion--after { + left: $devui-popover-offset; + top: $devui-popover-width; + margin-bottom: $devui-popover-width; + margin-right: $devui-popover-width; + } + + &.bottom { + .devui-popover-content { + @include bottom-postion--content; + + left: 50%; + bottom: 0; + transform: translate(-50%, 100%); + } + + .after { + @include bottom-postion--after; + + left: 50%; + margin-right: auto; + margin-left: $devui-popover-width; + } + } + + &.bottom-left { + .devui-popover-content { + @include bottom-postion--content; + } + + .after { + @include bottom-postion--after; + } + } + + &.bottom-right { + .devui-popover-content { + @include bottom-postion--content; + + left: auto; + right: 0; + } + + .after { + @include bottom-postion--after; + + left: auto; + margin-right: auto; + right: $devui-popover-offset; + margin-left: $devui-popover-width; + } + } +} diff --git a/packages/devui-vue/devui/popover/src/popover.tsx b/packages/devui-vue/devui/popover/src/popover.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d0b367c3efb2e16373162adb9ded6e6084ff8e13 --- /dev/null +++ b/packages/devui-vue/devui/popover/src/popover.tsx @@ -0,0 +1,134 @@ +import { defineComponent, toRefs, ref, CSSProperties, reactive } from 'vue' +import debounce from './debounce'; +import clickoutsideDirective from '../../shared/devui-directive/clickoutside' +import './popover.scss' + +type positionType = 'top' | 'right' | 'bottom' | 'left' +type triggerType = 'click' | 'hover' +type popType = 'success' | 'error' | 'warning' | 'info' | 'default' +const popTypeClass = { + success: { name: 'right-o', color: 'rgb(61, 204, 166)' }, + error: { name: 'error-o', color: 'rgb(249, 95, 91)' }, + info: { name: 'info-o', color: 'rgb(81, 112, 255)' }, + warning: { name: 'warning-o', color: 'rgb(254, 204, 85)' }, + default: {} +} + +export default defineComponent({ + name: 'DPopover', + + directives: { + clickoutside: clickoutsideDirective + }, + + props: { + visible: { + type: Boolean, + default: false + }, + + position: { + type: String as () => positionType, + default: 'bottom' + }, + + content: { + type: String, + default: 'default' + }, + + trigger: { + type: String as () => triggerType, + default: 'click', + }, + + zIndex: { + type: Number as () => CSSProperties, + default: 1060 + }, + + popType: { + type: String as () => popType, + default: 'default' + }, + + showAnimation: { + type: Boolean, + default: true + }, + + mouseEnterDelay: { + type: Number, + default: 150 + }, + + mouseLeaveDelay: { + type: Number, + default: 100 + }, + + popMaxWidth: { + type: Number, + default: undefined + }, + + popoverStyle: { + type: Object, + default: () => ({}) + } + }, + + setup(props, ctx) { + const { slots } = ctx; + const visible = ref(props.visible); + const { + position, content, zIndex, trigger, popType, + popoverStyle, mouseEnterDelay, mouseLeaveDelay, + showAnimation, popMaxWidth + } = toRefs(props); + const style: CSSProperties = { zIndex: zIndex.value, ...popoverStyle.value } + const isClick = trigger.value === 'click' + const iconType = reactive(popTypeClass[popType.value]) + const event = function () { + if (visible.value) { + visible.value = false; + return + } + visible.value = true + } + const onClick = isClick ? event : null; + const enter = debounce(() => { visible.value = true }, mouseEnterDelay.value) + const leave = debounce(() => { visible.value = false }, mouseLeaveDelay.value) + const onMouseenter = isClick ? null : enter + const onMouseleave = isClick ? null : leave + const hiddenContext = () => { visible.value = false } + popMaxWidth.value && (style.maxWidth = `${popMaxWidth.value}px`) + + return () => { + return ( + <div class={ + ['devui-popover', + position.value, + { + 'devui-popover-animation': showAnimation.value, + 'devui-popover-isVisible': visible.value + } + ]} > + <div + class='devui-popover-reference' + onMouseenter={onMouseenter} + onMouseleave={onMouseleave} + onClick={onClick} + v-clickoutside={hiddenContext}> + {slots.reference?.()} + </div> + <div class={['devui-popover-content', iconType.name ? 'is-icon' : '']} style={style}> + {iconType.name && <d-icon name={iconType.name} color={iconType.color} class="devui-popover-icon" size="16px" />} + {slots.content?.() || <span>{content.value}</span>} + <span class="after" style={style}></span> + </div> + </div> + ) + } + }, +}) diff --git a/packages/devui-vue/devui/progress/__tests__/progress.spec.ts b/packages/devui-vue/devui/progress/__tests__/progress.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ade6e88eff48569605ca7d1531e74b6c998718e --- /dev/null +++ b/packages/devui-vue/devui/progress/__tests__/progress.spec.ts @@ -0,0 +1,53 @@ +import { mount } from '@vue/test-utils'; +import Progress from '../progress'; + +describe('d-progress', () => { + it('height', () => { + const wrapper = mount(Progress, { + props: { height: '20px' }, + }); + expect(wrapper.props().height).toBe('20px'); + }); + + it('percentage', () => { + const wrapper = mount(Progress, { + props: { percentage: 20 }, + }); + expect(wrapper.props().percentage).toBe(20); + }); + + it('percentageText', () => { + const wrapper = mount(Progress, { + props: { percentageText: '30%' }, + }); + expect(wrapper.props().percentageText).toBe('30%'); + }); + + it('barbgcolor', () => { + const wrapper = mount(Progress, { + props: { barbgcolor: '#5170ff' }, + }); + expect(wrapper.props().barbgcolor).toBe('#5170ff'); + }); + + it('isCircle', () => { + const wrapper = mount(Progress, { + props: { isCircle: false }, + }); + expect(wrapper.props().isCircle).toBe(false); + }); + + it('strokeWidth', () => { + const wrapper = mount(Progress, { + props: { strokeWidth: 6 }, + }); + expect(wrapper.props().strokeWidth).toBe(6); + }); + + it('showContent', () => { + const wrapper = mount(Progress, { + props: { showContent: true }, + }); + expect(wrapper.props().showContent).toBe(true); + }); +}); diff --git a/packages/devui-vue/devui/progress/index.ts b/packages/devui-vue/devui/progress/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d96a7ec9f3a33a8bbe8d897dbad2584a92da0819 --- /dev/null +++ b/packages/devui-vue/devui/progress/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Progress from './src/progress' + +Progress.install = function(app: App) { + app.component(Progress.name, Progress) +} + +export { Progress } + +export default { + title: 'Progress 进度条', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Progress as any) + } +} diff --git a/packages/devui-vue/devui/progress/src/progress.scss b/packages/devui-vue/devui/progress/src/progress.scss new file mode 100644 index 0000000000000000000000000000000000000000..0cd85d7bc37f1ccb862fbf303919d7a76c2af6cd --- /dev/null +++ b/packages/devui-vue/devui/progress/src/progress.scss @@ -0,0 +1,43 @@ +.devui-progress--line { + position: relative; + background: #dfe1e6; + + .devui-progress-bar { + width: 0; + height: 100%; + transition: width 0.6s ease; + background-color: #5e7ce0; + } + + > span { + display: block; + white-space: nowrap; + color: #ffffff; + text-align: center; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + font-size: 12px; + line-height: 1.5; + } +} + +.devui-progress-circle { + position: relative; + + .devui-progress-circle-text { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + margin: 0; + padding: 0; + color: #252b3a; + line-height: 1; + white-space: normal; + text-align: center; + transform: translate(-50%, -50%); + } +} diff --git a/packages/devui-vue/devui/progress/src/progress.tsx b/packages/devui-vue/devui/progress/src/progress.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0f9c88beaa1b032246f7e7fdb3b2869f557e32ad --- /dev/null +++ b/packages/devui-vue/devui/progress/src/progress.tsx @@ -0,0 +1,180 @@ +import { + defineComponent, + reactive, + toRefs, + watch, +} from 'vue' + +import './progress.scss' + +interface data { + pathString: string + trailPath: any + strokePath: any +} + +export default defineComponent({ + name: 'DProgress', + props: { + height: { + type: String, + default: '20px', + }, + percentage: { + type: Number, + default: 0, + }, + percentageText: { + type: String, + default: '', + }, + barBgColor: { + type: String, + default: '#5170ff', + }, + isCircle: { + type: Boolean, + default: false, + }, + strokeWidth: { + type: Number, + default: 6, + }, + showContent: { + type: Boolean, + default: true, + } + }, + setup(props) { + const { + height, + percentage, + percentageText, + barBgColor, + isCircle, + strokeWidth, + showContent, + } = toRefs(props); + + const data: data = reactive({ + pathString: '', + trailPath: null, + strokePath: null, + }); + + const setCircleProgress = () => { + if (!isCircle) { + return; + } + + const radius = 50 - strokeWidth.value / 2; + const beginPositionY = -radius; + const endPositionY = radius * -2; + + data.pathString = `M 50,50 m 0,${beginPositionY} + a ${radius},${radius} 0 1 1 0,${-endPositionY} + a ${radius},${radius} 0 1 1 0,${endPositionY}`; + + const len = Math.PI * 2 * radius; + + data.trailPath = { + stroke: '#dfe1e6', + strokeDasharray: `${len}px ${len}px`, + strokeDashoffset: `0`, + transition: 'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s' + }; + + data.strokePath = { + stroke: barBgColor || null, + strokeDasharray: `${(percentage.value / 100) * len }px ${len}px`, + strokeDashoffset: `0`, + transition: 'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s' + }; + } + + setCircleProgress(); + + watch([height, percentage, percentageText, barBgColor, isCircle, strokeWidth, showContent], () => { + setCircleProgress(); + }) + + return { + data, + }; + }, + render() { + const { + height, + percentage, + percentageText, + barBgColor, + isCircle, + strokeWidth, + showContent, + data, + $slots, + } = this; + + const progressLine = ( + <div + className="devui-progress--line" + style={{ + height: height, + borderRadius: height, + }} + > + <div + className="devui-progress-bar" + style={{ + height: height, + borderRadius: height, + width: `${percentage}%`, + backgroundColor: barBgColor, + }} + /> + <span + style={{ + lineHeight: height, + }} + > + {percentageText} + </span> + </div> + ); + + const textElement = ( + <span className="devui-progress-circle-text">{percentage}%</span> + ); + + const progressCircle = ( + <div className="devui-progress-circle"> + <svg className="devui-progress-circle" viewBox="0 0 100 100"> + <path + className="devui-progress-circle-trail" + fill-opacity="0" + stroke-width={strokeWidth} + style={data.trailPath} + d={data.pathString} + /> + <path + className="devui-progress-circle-path" + d={data.pathString} + stroke-linecap="round" + fill-opacity="0" + stroke={barBgColor} + stroke-width={percentage ? strokeWidth : 0} + style={data.strokePath} + /> + </svg> + {showContent && $slots.default?.()} + {showContent && !$slots.default && textElement} + </div> + ); + + return ( + <div className="devui-progress"> + {!isCircle ? progressLine : progressCircle} + </div> + ); + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/quadrant-diagram/__tests__/quadrant-diagram.spec.ts b/packages/devui-vue/devui/quadrant-diagram/__tests__/quadrant-diagram.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb4f8a5688e5dbfbcbe68871f949205756aaa29c --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/__tests__/quadrant-diagram.spec.ts @@ -0,0 +1,32 @@ +import { mount } from '@vue/test-utils'; +import { reactive, nextTick } from 'vue'; + +import DQuadrantDiagram from '../src/quadrant-diagram'; + +describe('d-quadrant-diagram', () => { + it('quadrantDiagramResponse', async () => { + const view = reactive({ + height: 200, + width: 200, + }); + + const wrapper = mount({ + components: { DQuadrantDiagram }, + template: `<d-quadrant-diagram :view='view'/>`, + propsData: { + view, + }, + setup() { + return { + view + }; + } + }); + console.log(wrapper.html()) + + expect(wrapper.find('#devui-quadrant-axis-1').element['height']).toEqual(200); + view.height = 400; + await nextTick(); + expect(wrapper.find('#devui-quadrant-axis-1').element['height']).toEqual(400); + }) +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/quadrant-diagram/config.ts b/packages/devui-vue/devui/quadrant-diagram/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..c89a9443fabb944eb60aed1846432de4825d9540 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/config.ts @@ -0,0 +1,45 @@ +export const QUADRANT_CONFIGS = []; +export const LABEL_SIZE = ['small', 'normal', 'large']; +export const DEFAULT_AXIS_CONFIGS = { + tickWidth: 10, + spaceBetweenLabelsAxis: 20, + xAxisLabel: '紧急度', + yAxisLabel: '重要度', + xAxisRange: { + min: 0, + max: 100, + step: 10 + }, + yAxisRange: { + min: 0, + max: 50, + step: 5 + }, + originPosition: { + left: 30, + bottom: 30 + }, + axisMargin: 35, + xWeight: 1, + yWeight: 1 +}; +export const DEFAULT_QUADRANT_CONFIGS = [ + { title: '重要紧急' }, + { title: '重要不紧急' }, + { title: '不重要不紧急' }, + { title: '不重要紧急' } +]; +export const DEFAULT_VIEW_CONFIGS = { + height: 900, + width: 950, +} +export const AXIS_TITLE_SPACE = 15; +export const SMALL_LABEL_SIZE_CENTER_POINT = { + x: 6, y: 6 +}; +export const NORMAL_LABEL_SIZE_CENTER_POINT = { + x: 45, y: 14 +}; +export const LARGE_LABEL_SIZE_CENTER_POINT = { + x: 60, y: 18 +}; diff --git a/packages/devui-vue/devui/quadrant-diagram/index.ts b/packages/devui-vue/devui/quadrant-diagram/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..db4125190f6053e1497ae4cf30f360ffbfba1a07 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import QuadrantDiagram from './src/quadrant-diagram' + +QuadrantDiagram.install = function (app: App) { + app.component(QuadrantDiagram.name, QuadrantDiagram) +} + +export { QuadrantDiagram } + +export default { + title: 'QuadrantDiagram 象限图', + category: '数据展示', + status: '10%', + install(app: App): void { + app.use(QuadrantDiagram as any) + } +} diff --git a/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.scss b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..b83d55a81572f72800e4f3b1d03e7f7f6da3331e --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.scss @@ -0,0 +1,3 @@ +canvas { + z-index: 1; +} diff --git a/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.tsx b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b4b25b9f80a2d54ee46f95eea34b0b1cfa5600b5 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/index.tsx @@ -0,0 +1,224 @@ +import { defineComponent, toRefs, onMounted, ExtractPropTypes, reactive, ref, watch } from 'vue' +import { IViewConfigs, IAxisConfigs } from '../../../type' +import { AXIS_TITLE_SPACE } from '../../../config' +import { quadrantDiagramAxisProps, QuadrantDiagramAxisProps } from './types' +import { debounce } from 'lodash-es' + +import './index.scss' + +export default defineComponent({ + name: 'DQuadrantDiagramAxis', + props: quadrantDiagramAxisProps, + setup(props: QuadrantDiagramAxisProps) { + + const { diagramId, view, axisConfigs } = toRefs(props) + const AXIS_COLOR = ref('#0000ff') + const AXIS_LABEL_COLOR = ref('#ff0000') + + const quadrantAxis = ref() + const context = ref() + const axisInnerAttr = reactive({ + axisOrigin: { + x: 0, + y: 0, + }, + axisTop: 0, + axisRight: 0, + axisWidth: 0, + axisHeight: 0, + yAxisTicksNum: 0, + xAxisTicksNum: 0, + xTickSpacing: 0, + yTickSpacing: 0, + }) + + const axisConfigsVal: IAxisConfigs = axisConfigs.value + + onMounted(() => { + resetAxis() + }) + + watch(view.value, () => { + resetAxis() + }) + + const resetAxis = debounce(() => { + initAxisData() + setAxisData() + drawAxis() + drawAxisLabels() + }, 200) + + /** + * 获取 canvas 并赋值宽高 + */ + const initAxisData = () => { + quadrantAxis.value = document.querySelector('#devui-quadrant-axis-' + diagramId.value) + } + + const setAxisData = () => { + context.value = quadrantAxis.value.getContext('2d') + axisInnerAttr.axisOrigin = axisConfigsVal.axisOrigin + axisInnerAttr.axisTop = axisConfigsVal.axisTop + axisInnerAttr.axisRight = axisConfigsVal.axisRight + axisInnerAttr.axisWidth = axisConfigsVal.axisWidth + axisInnerAttr.axisHeight = axisConfigsVal.axisHeight + axisInnerAttr.yAxisTicksNum = axisConfigsVal.yAxisTicksNum + axisInnerAttr.xAxisTicksNum = axisConfigsVal.xAxisTicksNum + axisInnerAttr.xTickSpacing = axisConfigsVal.xTickSpacing + axisInnerAttr.yTickSpacing = axisConfigsVal.yTickSpacing + } + + /** + * 执行绘制 + */ + const drawAxis = () => { + context.value.save() + context.value.fillStyle = AXIS_COLOR.value + context.value.strokeStyle = AXIS_COLOR.value + drawXAxis() + drawYAxis() + context.value.lineWidth = 0.5 + drawXAxisTicks() + drawYAxisTicks() + context.value.restore() + } + + /** + * 绘制 XY 轴 + */ + const drawYAxis = () => { + context.value.beginPath() + context.value.moveTo(axisInnerAttr.axisOrigin.x, axisInnerAttr.axisOrigin.y) + context.value.lineTo(axisInnerAttr.axisOrigin.x, axisInnerAttr.axisTop - axisConfigsVal.axisMargin) + context.value.stroke() + context.value.moveTo(axisInnerAttr.axisOrigin.x, axisInnerAttr.axisTop - axisConfigsVal.axisMargin) + context.value.lineTo(axisInnerAttr.axisOrigin.x + 5, axisInnerAttr.axisTop - axisConfigsVal.axisMargin + 10) + context.value.lineTo(axisInnerAttr.axisOrigin.x - 5, axisInnerAttr.axisTop - axisConfigsVal.axisMargin + 10) + context.value.fill() + + } + const drawXAxis = () => { + context.value.beginPath() + context.value.moveTo(axisInnerAttr.axisOrigin.x, axisInnerAttr.axisOrigin.y) + context.value.lineTo(axisInnerAttr.axisRight + axisConfigsVal.axisMargin - 10, axisInnerAttr.axisOrigin.y) + context.value.stroke() + // 绘制坐标轴三角形 + context.value.moveTo(axisInnerAttr.axisRight + axisConfigsVal.axisMargin, axisInnerAttr.axisOrigin.y) + context.value.lineTo(axisInnerAttr.axisRight + axisConfigsVal.axisMargin - 10, axisInnerAttr.axisOrigin.y + 5) + context.value.lineTo(axisInnerAttr.axisRight + axisConfigsVal.axisMargin - 10, axisInnerAttr.axisOrigin.y - 5) + context.value.fill() + } + + /** + * 绘制轴线刻度 + */ + const drawXAxisTicks = () => { + let deltaY: number + for (let i = 1; i < axisInnerAttr.xAxisTicksNum; i++) { + context.value.beginPath() + // 判断显示长刻度还是短刻度 + if (i % axisConfigsVal.xAxisRange.step === 0) { + deltaY = axisConfigsVal.tickWidth + } else { + deltaY = axisConfigsVal.tickWidth / 2 + } + context.value.moveTo(axisInnerAttr.axisOrigin.x + i * axisInnerAttr.xTickSpacing, + axisInnerAttr.axisOrigin.y - deltaY) + context.value.lineTo(axisInnerAttr.axisOrigin.x + i * axisInnerAttr.xTickSpacing, + axisInnerAttr.axisOrigin.y + deltaY) + context.value.stroke() + } + + } + const drawYAxisTicks = () => { + let deltaX: number + for (let i = 1; i < axisInnerAttr.yAxisTicksNum; i++) { + context.value.beginPath() + if (i % axisConfigsVal.yAxisRange.step === 0) { + deltaX = axisConfigsVal.tickWidth + } else { + deltaX = axisConfigsVal.tickWidth / 2 + } + context.value.moveTo(axisInnerAttr.axisOrigin.x - deltaX, + axisInnerAttr.axisOrigin.y - i * axisInnerAttr.yTickSpacing) + context.value.lineTo(axisInnerAttr.axisOrigin.x + deltaX, + axisInnerAttr.axisOrigin.y - i * axisInnerAttr.yTickSpacing) + context.value.stroke() + } + } + /** + * 绘制轴线标签 + */ + const drawAxisLabels = () => { + context.value.save() + context.value.fillStyle = AXIS_LABEL_COLOR.value + drawXTicksLabels() + drawYTicksLabels() + context.value.restore() + drawAxisTitle() + } + + const drawXTicksLabels = () => { + context.value.textAlign = 'center' + context.value.textBaseline = 'top' + for (let i = 0; i <= axisInnerAttr.xAxisTicksNum; i++) { + if (i % axisConfigsVal.xAxisRange.step === 0) { + context.value.fillText(i, axisInnerAttr.axisOrigin.x + i * axisInnerAttr.xTickSpacing, + axisInnerAttr.axisOrigin.y + axisConfigsVal.spaceBetweenLabelsAxis) + } + } + } + const drawYTicksLabels = () => { + context.value.textAlign = 'center' + context.value.textBaseline = 'middle' + for (let i = 0; i <= axisInnerAttr.yAxisTicksNum; i++) { + if (i % axisConfigsVal.yAxisRange.step === 0) { + context.value.fillText(i, axisInnerAttr.axisOrigin.x - axisConfigsVal.spaceBetweenLabelsAxis, + axisInnerAttr.axisOrigin.y - i * axisInnerAttr.yTickSpacing) + } + } + } + const drawAxisTitle = () => { + context.value.font = '12px Microsoft YaHei' + context.value.textAlign = 'left' + context.value.fillStyle = AXIS_LABEL_COLOR.value + const xLabelWidth = context.value.measureText(axisConfigsVal.xAxisLabel).width + rotateLabel(axisConfigsVal.xAxisLabel, axisInnerAttr.axisRight + axisConfigsVal.axisMargin / 2, + axisInnerAttr.axisOrigin.y - xLabelWidth - AXIS_TITLE_SPACE) + context.value.fillText(axisConfigsVal.yAxisLabel, + axisInnerAttr.axisOrigin.x + AXIS_TITLE_SPACE, axisInnerAttr.axisTop - axisConfigsVal.axisMargin / 2) + } + + const rotateLabel = (name: string, x: number, y: number) => { + for (let i = 0; i < name.length; i++) { + const str = name.slice(i, i + 1).toString() + if (str.match(/[A-Za-z0-9]/)) { + context.value.save() + context.value.translate(x, y) + context.value.rotate(Math.PI / 180 * 90) + context.value.textBaseline = 'bottom' + context.value.fillText(str, 0, 0) + context.value.restore() + y += context.value.measureText(str).width + } else if (str.match(/[\u4E00-\u9FA5]/)) { + context.value.save() + context.value.textBaseline = 'top' + context.value.fillText(str, x, y) + context.value.restore() + y += context.value.measureText(str).width + } + } + } + + + }, + render() { + const { diagramId, view } = this + return ( + <div> + <canvas id={'devui-quadrant-axis-' + diagramId} height={view.height} width={view.width}></canvas> + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/quadrant-diagram/src/components/axis/types.ts b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6c84fdd4d1ebfa8f5bd75c5cec6e3da77ec2341 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/src/components/axis/types.ts @@ -0,0 +1,16 @@ +import type { ExtractPropTypes, PropType } from 'vue' +import { IViewConfigs, IAxisConfigs } from '../../../type' + +export const quadrantDiagramAxisProps = { + diagramId: { + type: String, + }, + axisConfigs: { + type: Object as PropType<IAxisConfigs>, + }, + view: { + type: Object as PropType<IViewConfigs>, + }, +} as const + +export type QuadrantDiagramAxisProps = ExtractPropTypes<typeof quadrantDiagramAxisProps> \ No newline at end of file diff --git a/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram-types.ts b/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..26f9e8df2362547839327b3ae32aaf92ee4d45b6 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram-types.ts @@ -0,0 +1,20 @@ +import type { ExtractPropTypes, PropType } from 'vue' +import { DEFAULT_AXIS_CONFIGS, DEFAULT_VIEW_CONFIGS } from '../config' +import { IViewConfigs, IAxisConfigs } from '../type' + +export const quadrantDiagramProps = { + diagramId: { + type: String, + default: '1', + }, + axisConfigs: { + type: Object as PropType<IAxisConfigs>, + default: DEFAULT_AXIS_CONFIGS, + }, + view: { + type: Object as PropType<IViewConfigs>, + default: DEFAULT_VIEW_CONFIGS, + }, +} as const + +export type QuadrantDiagramProps = ExtractPropTypes<typeof quadrantDiagramProps> diff --git a/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram.tsx b/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8c15874ef739fc3e915e11e8a6ae1a25463e4e37 --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/src/quadrant-diagram.tsx @@ -0,0 +1,62 @@ +import { defineComponent, toRefs, reactive, watch } from 'vue' +import { quadrantDiagramProps, QuadrantDiagramProps } from './quadrant-diagram-types' +import DQuadrantDiagramAxis from './components/axis' +import { DEFAULT_AXIS_CONFIGS } from '../config' + +export default defineComponent({ + name: 'DQuadrantDiagram', + props: quadrantDiagramProps, + setup(props: QuadrantDiagramProps) { + const { diagramId, axisConfigs, view } = toRefs(props) + + const calAxisConfig = reactive({ + axisOrigin: { x: null, y: null }, + axisTop: null, + axisRight: null, + axisWidth: null, + axisHeight: null, + yAxisTicksNum: null, + xAxisTicksNum: null, + xTickSpacing: null, + yTickSpacing: null, + }) + + const initAxisData = () => { + const axisConfigKeys = Object.keys(DEFAULT_AXIS_CONFIGS) + for (let i = 0; i < axisConfigKeys.length; i++) { + if (calAxisConfig[axisConfigKeys[i]] === undefined) { + calAxisConfig[axisConfigKeys[i]] = DEFAULT_AXIS_CONFIGS[axisConfigKeys[i]] + } + } + calAxisConfig.axisOrigin = { + x: axisConfigs.value.originPosition.left, + y: view.value.height - axisConfigs.value.originPosition.bottom + } + calAxisConfig.axisTop = axisConfigs.value.axisMargin + calAxisConfig.axisRight = view.value.width - axisConfigs.value.axisMargin + calAxisConfig.axisWidth = calAxisConfig.axisRight - calAxisConfig.axisOrigin.x + calAxisConfig.axisHeight = calAxisConfig.axisOrigin.y - calAxisConfig.axisTop + calAxisConfig.yAxisTicksNum = axisConfigs.value.yAxisRange.max - axisConfigs.value.yAxisRange.min + calAxisConfig.xAxisTicksNum = axisConfigs.value.xAxisRange.max - axisConfigs.value.xAxisRange.min + calAxisConfig.xTickSpacing = calAxisConfig.axisWidth / calAxisConfig.xAxisTicksNum + calAxisConfig.yTickSpacing = calAxisConfig.axisHeight / calAxisConfig.yAxisTicksNum + } + + initAxisData() + + watch(view.value, () => { + initAxisData() + }) + + return { diagramId, calAxisConfig, } + }, + render() { + const { diagramId, calAxisConfig, view } = this + + return ( + <div class="devui-quadrant-diagram" id={diagramId}> + <DQuadrantDiagramAxis diagramId={diagramId} axisConfigs={calAxisConfig} view={view} /> + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/quadrant-diagram/type.ts b/packages/devui-vue/devui/quadrant-diagram/type.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7a13a7fcbb77078a806db72ea865a513e5fc15b --- /dev/null +++ b/packages/devui-vue/devui/quadrant-diagram/type.ts @@ -0,0 +1,44 @@ +export interface IAxisConfigs { + tickWidth?: number // 刻度的宽(高)度,默认为10 + spaceBetweenLabelsAxis?: number // 刻度值和坐标轴之间的距离,默认为20 + axisMargin?: number // 右侧留出的空白区域 + xAxisLabel?: string // X轴名称,默认值为'紧急度' + yAxisLabel?: string // Y轴名称,默认值为'重要度' + xWeight?: number // X轴权重,默认值为1 + yWeight?: number // Y轴权重,默认值为1 + xAxisRange?: IRangeConfigs // X轴的坐标值范围和间距设置,默认值为{min:0,max:100,step:10} + yAxisRange?: IRangeConfigs // Y轴的坐标值范围和间距设置,默认值为{min:0,max:100,step:10} + originPosition?: { + left: number + bottom: number + } // 原点的位置设置,默认值为{left:30,bottom:30} + [propName: string]: any +} +export interface IQuadrantConfigs { + backgroundColor?: any + color?: any + title?: string + top?: number + left?: number +} +export interface ILabelDataConfigs { + x: number // X轴坐标值 + y: number // Y轴坐标值 + title: string // 标签的名称 + content?: string // 鼠标悬浮在标签上时的提示内容 + progress?: number // 标签对应事项的进度 + [propName: string]: any // 其他数据 +} + +export interface IViewConfigs { + height: number // 象限图高度 + width: number // 象限图宽度 +} + +export interface IRangeConfigs { + min: number // 坐标轴起始值 + max: number // 坐标轴终止值 + step: number // 坐标轴刻度值的间隔 +} + +export type labelSize = 'small' | 'normal' | 'large' diff --git a/packages/devui-vue/devui/radio/__tests__/radio-group.spec.ts b/packages/devui-vue/devui/radio/__tests__/radio-group.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c28a920c2a358187d49cb1c3bdc0d2b843bb0bab --- /dev/null +++ b/packages/devui-vue/devui/radio/__tests__/radio-group.spec.ts @@ -0,0 +1,129 @@ +import { mount } from '@vue/test-utils'; +import { ref } from 'vue'; +import DRadioGroup from '../src/radio-group'; +import DRadio from '../src/radio'; + +describe('RadioGroup', () => { + it('radioGroup render work', async () => { + const onChange = jest.fn(); + const wrapper = mount({ + components: { + DRadioGroup, + DRadio + }, + template: ` + <d-radio-group v-model="radioVal" @change="onChange"> + <d-radio value="Item1">Item1</d-radio> + <d-radio value="Item2">Item2</d-radio> + </d-radio-group> + `, + setup () { + const radioVal = ref('Item1'); + return { + radioVal, + onChange + }; + } + }); + + const radioA = wrapper.findAllComponents({ name: 'DRadio' })[0]; + const radioB = wrapper.findAllComponents({ name: 'DRadio' })[1]; + const inputB = wrapper.findAll('input')[1]; + + expect(wrapper.classes()).toContain('devui-radio-group'); + expect(radioA.classes()).toContain('active'); + expect(radioB.classes()).not.toContain('active'); + + await inputB.trigger('change'); + + expect(radioA.classes()).not.toContain('active'); + expect(radioB.classes()).toContain('active'); + expect(onChange).toHaveBeenCalledTimes(1); + }); + + it('radioGroup cssStyle work', async () => { + const wrapper = mount(DRadioGroup, { + props: { + value: 'Item1' + } + }); + expect(wrapper.html()).not.toMatch('is-row'); + + await wrapper.setProps({ + value: 'Item1', + cssStyle: 'row' + }); + expect(wrapper.html()).toMatch('is-row'); + }); + + it('radioGroup beforeChange work', async () => { + const beforeChange = jest.fn(v => v !== 'Item2'); + const onChange = jest.fn(); + const wrapper = mount({ + components: { + DRadioGroup, + DRadio + }, + template: ` + <d-radio-group v-model="radioVal" @change="onChange" :before-change="beforeChange"> + <d-radio value="Item1">Item1</d-radio> + <d-radio value="Item2">Item2</d-radio> + <d-radio value="Item3">Item3</d-radio> + </d-radio-group> + `, + setup () { + const radioVal = ref('Item1'); + return { + radioVal, + onChange, + beforeChange + }; + } + }); + + const [radio1, radio2, radio3] = wrapper.findAllComponents({ name: 'DRadio' }); + expect(radio1.classes()).toContain('active'); + + await radio2.find('input').trigger('change'); + expect(radio1.classes()).toContain('active'); + expect(beforeChange).toBeCalledTimes(1); + expect(onChange).toBeCalledTimes(0); + + beforeChange.mockReset(); + await radio3.find('input').trigger('change'); + expect(radio1.classes()).not.toContain('active'); + expect(radio3.classes()).toContain('active'); + expect(beforeChange).toBeCalledTimes(1); + expect(onChange).toBeCalledTimes(1); + }); + + it('radioGroup disabled work', async () => { + const onChange = jest.fn(); + const wrapper = mount({ + components: { + DRadioGroup, + DRadio + }, + template: ` + <d-radio-group v-model="radioVal" @change="onChange"> + <d-radio value="Item1">Item1</d-radio> + <d-radio value="Item2" disabled>Item2</d-radio> + </d-radio-group> + `, + setup () { + const radioVal = ref('Item1'); + return { + radioVal, + onChange + }; + } + }); + + const radio2 = wrapper.findAllComponents({ name: 'DRadio' })[1]; + const input2 = wrapper.findAll('input')[1]; + + await input2.trigger('change'); + expect(radio2.classes()).not.toContain('active'); + expect(onChange).toHaveBeenCalledTimes(0); + }); +}); diff --git a/packages/devui-vue/devui/radio/__tests__/radio.spec.ts b/packages/devui-vue/devui/radio/__tests__/radio.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5cd8274e51403fcab8dd2b4faac208064ad6c1b7 --- /dev/null +++ b/packages/devui-vue/devui/radio/__tests__/radio.spec.ts @@ -0,0 +1,101 @@ +import { mount } from '@vue/test-utils' +import { ref } from 'vue' +import DRadio from '../src/radio' + +describe('Radio', () => { + /** 测试是否正常渲染 */ + it('radio render work', async () => { + const onChange = jest.fn() + const wrapper = mount({ + components: { DRadio }, + template: `<d-radio v-model="modelValue" value="A" @change="onChange">ItemA</d-radio>`, + setup() { + const modelValue = ref('Item1') + return { + modelValue, + onChange, + } + }, + }) + + expect(wrapper.classes()).toContain('devui-radio') + expect(wrapper.classes()).not.toContain('active') + expect(wrapper.text()).toEqual('ItemA') + + const input = wrapper.find('input') + await input.trigger('change') + expect(onChange).toBeCalledTimes(1) + }) + + /** 测试 value */ + it('radio value work', () => { + const wrapper = mount(DRadio, { + props: { + value: 'Item1', + }, + }) + const input = wrapper.find('input') + expect(input.attributes()['value']).toEqual('Item1') + }) + + /** 测试 disabled */ + it('radio disabled work', async () => { + const onChange = jest.fn() + const wrapper = mount(DRadio, { + props: { + value: 'Item1', + disabled: true, + onChange, + }, + }) + expect(wrapper.classes()).toContain('disabled') + const input = wrapper.find('input') + await input.trigger('change') + expect(onChange).toBeCalledTimes(0) + }) + + /** 测试 disabled 切换 */ + it('radio disabled change', async () => { + const onChange = jest.fn() + const wrapper = mount(DRadio, { + props: { + value: 'Item1', + disabled: true, + onChange, + }, + }) + expect(wrapper.classes()).toContain('disabled') + await wrapper.setProps({ + disabled: false, + }) + expect(wrapper.classes()).not.toContain('disabled') + }) + + /** 测试 beforeChange */ + it('radio beforeChange work', async () => { + const beforeChange = jest.fn(() => true) + const onChange = jest.fn() + const wrapper = mount(DRadio, { + props: { + value: 'Item1', + onChange, + beforeChange, + }, + }) + const input = wrapper.find('input') + await input.trigger('change') + expect(beforeChange).toHaveBeenCalledTimes(1) + expect(onChange).toHaveBeenCalledTimes(1) + + const beforeChangeFalse = jest.fn(() => false) + onChange.mockReset() + await wrapper.setProps({ + value: 'Item2', + beforeChange: beforeChangeFalse, + onChange, + }) + await input.trigger('change') + expect(beforeChangeFalse).toHaveBeenCalledTimes(1) + expect(onChange).toHaveBeenCalledTimes(0) + }) +}) diff --git a/packages/devui-vue/devui/radio/index.ts b/packages/devui-vue/devui/radio/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..154cdf1214a0e7a8490c2bbf25f8c192c9fad049 --- /dev/null +++ b/packages/devui-vue/devui/radio/index.ts @@ -0,0 +1,23 @@ +import type { App } from 'vue' +import Radio from './src/radio' +import RadioGroup from './src/radio-group' + +Radio.install = function(app: App) { + app.component(Radio.name, Radio) +} + +RadioGroup.install = function(app: App) { + app.component(RadioGroup.name, RadioGroup) +} + +export { Radio, RadioGroup } + +export default { + title: 'Radio 单选框', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(Radio as any) + app.use(RadioGroup as any) + } +} diff --git a/packages/devui-vue/devui/radio/src/radio-group.scss b/packages/devui-vue/devui/radio/src/radio-group.scss new file mode 100644 index 0000000000000000000000000000000000000000..7d86fdd7ba8f631fe5b9ba57690e6bfbc5afe46b --- /dev/null +++ b/packages/devui-vue/devui/radio/src/radio-group.scss @@ -0,0 +1,22 @@ +.devui-radio-group { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: flex-start; + + &.is-row { + flex-direction: row; + } + + &.is-column { + flex-direction: column; + } + + .devui-radio { + line-height: 28px; + + &:not(:last-child) { + padding-right: 20px; + } + } +} diff --git a/packages/devui-vue/devui/radio/src/radio-group.tsx b/packages/devui-vue/devui/radio/src/radio-group.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f636bd062f2e6379421f45675e10e6d753f7cb17 --- /dev/null +++ b/packages/devui-vue/devui/radio/src/radio-group.tsx @@ -0,0 +1,66 @@ +import { defineComponent, provide, toRef, ExtractPropTypes } from 'vue'; +import DRadio from './radio' +import { radioGroupProps, radioGroupInjectionKey } from './radio-types'; +import './radio-group.scss'; + +export default defineComponent({ + name: 'DRadioGroup', + props: radioGroupProps, + emits: ['change', 'update:modelValue'], + setup(props: ExtractPropTypes<typeof radioGroupProps>, { emit }) { + /** change 事件 */ + const emitChange = (radioValue: string) => { + emit('update:modelValue', radioValue); + emit('change', radioValue); + }; + + // 注入给子组件 + provide(radioGroupInjectionKey, { + modelValue: toRef(props, 'modelValue'), + name: toRef(props, 'name'), + disabled: toRef(props, 'disabled'), + beforeChange: props.beforeChange, + emitChange + }); + }, + render() { + const { + cssStyle, + values + } = this; + /** 获取展示内容 */ + const getContent = () => { + const defaultSlot = this.$slots.default; + // 有默认插槽则使用默认插槽 + if (defaultSlot) { + return defaultSlot() + } + // 有数据列表则使用数据列表 + else if (Array.isArray(values)) { + return values.map(item => { + return ( + <DRadio key={item} value={item}> + {item} + </DRadio> + ) + }) + } + // 什么都没有则返回空 + else { + return '' + } + } + + return ( + <div class={[ + 'devui-radio-group', + { + 'is-row': cssStyle === 'row', + 'is-column': cssStyle === 'column', + } + ]}> + {getContent()} + </div> + ); + } +}); diff --git a/packages/devui-vue/devui/radio/src/radio-types.ts b/packages/devui-vue/devui/radio/src/radio-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4aa59b76f34865db9b36dd387fd1e9ec0bf81d4 --- /dev/null +++ b/packages/devui-vue/devui/radio/src/radio-types.ts @@ -0,0 +1,63 @@ +import type { InjectionKey, PropType, Ref } from 'vue' + +/** radio、radio-group 共用 props */ +const radioCommonProps = { + /** 双向绑定的值 */ + modelValue: { + type: String, + default: null, + }, + /** 单选框的名称 */ + name: { + type: String as PropType<string | null>, + default: null, + }, + /** 值改变之前触发的事件 */ + beforeChange: { + type: Function as PropType<(value: string) => boolean | Promise<boolean>>, + default: null, + }, + /** 是否禁用 */ + disabled: { + type: Boolean, + default: false, + }, +} + +/** radio 的 props */ +export const radioProps = { + ...radioCommonProps, + /** 单选框的值 */ + value: { + type: String, + required: true, + default: null, + }, +} as const + +/** radio-group 的 props */ +export const radioGroupProps = { + ...radioCommonProps, + /** 选项列表 */ + values: { + type: Array as PropType<string[] | null>, + default: null, + }, + /** 展示方式,横向/竖向 */ + cssStyle: { + type: String as PropType<'row' | 'column'>, + default: 'column', + }, +} as const + +/** radio-group 注入字段的接口 */ +interface RadioGroupInjection { + modelValue: Ref<string> + name: Ref<string> + disabled: Ref<boolean> + beforeChange: (value: string) => boolean | Promise<boolean> + emitChange: (value: string) => void +} + +/** radio-group 注入 radio 的 key 值 */ +export const radioGroupInjectionKey: InjectionKey<RadioGroupInjection> = Symbol('DRadioGroup') diff --git a/packages/devui-vue/devui/radio/src/radio.scss b/packages/devui-vue/devui/radio/src/radio.scss new file mode 100644 index 0000000000000000000000000000000000000000..dc53fdcfbf499e8d6eccec3fc4d88413ff6caafa --- /dev/null +++ b/packages/devui-vue/devui/radio/src/radio.scss @@ -0,0 +1,109 @@ +@import '../../style/theme/color'; +@import '../../style/core/_font'; + +.devui-radio { + display: flex; + justify-content: flex-start; + align-items: center; + font-size: $devui-font-size; + line-height: 1.5; + font-weight: normal; + cursor: pointer; + color: $devui-text; + + &:hover { + .devui-radio-label { + color: $devui-primary-hover; + } + } + + &:active, + &:focus, + &:hover { + .devui-radio-material-outer { + stroke: $devui-form-control-line-active-hover; + } + + .devui-radio-material-inner { + fill: $devui-icon-fill-active-hover; + } + } + + &.active { + .devui-radio-material-inner { + opacity: 1; + transform: scale(1); + transition: + transform 200ms cubic-bezier(0.23, 1, 0.32, 1), + opacity 200ms cubic-bezier(0.23, 1, 0.32, 1); + } + } + + &.disabled { + cursor: not-allowed; + + /* 选择图标-外圈 */ + .devui-radio-material-outer { + stroke: $devui-disabled-line; + fill: $devui-disabled-bg; + } + + /* 选择图标-内圈 */ + .devui-radio-material-inner { + fill: $devui-icon-fill-active-disabled; + } + + .devui-radio-label { + color: $devui-disabled-text; + } + } + + /* 选择图标-容器 */ + &-material { + vertical-align: middle; + position: relative; + display: inline-block; + overflow: hidden; + height: 16px; + width: 16px; + line-height: 16px; + user-select: none; + } + + /* 选择图标-外圈 */ + &-material-outer { + opacity: 1; + transition: stroke 50ms cubic-bezier(0.755, 0.05, 0.855, 0.06); + stroke: $devui-line; + fill: transparent; + } + + /* 选择图标-内圈 */ + &-material-inner { + opacity: 0; + transform: scale(0); + transform-origin: 50% 50%; + transition: + transform 200ms cubic-bezier(0.755, 0.05, 0.855, 0.06), + opacity 200ms cubic-bezier(0.755, 0.05, 0.855, 0.06); + fill: $devui-icon-fill-active; + } + + /* 内容 */ + &-label { + color: $devui-text; + margin-left: 8px; + font-size: $devui-font-size; + transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); + } + + &-input { + opacity: 0; + z-index: -1; + width: 0; + height: 0; + display: none; + overflow: hidden; + pointer-events: none; + } +} diff --git a/packages/devui-vue/devui/radio/src/radio.tsx b/packages/devui-vue/devui/radio/src/radio.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1023e705d4eefa142b7be428f194a19fbdcfca20 --- /dev/null +++ b/packages/devui-vue/devui/radio/src/radio.tsx @@ -0,0 +1,103 @@ +import { defineComponent, ExtractPropTypes, inject, computed } from 'vue'; +import { radioProps, radioGroupInjectionKey } from './radio-types'; +import './radio.scss'; + +export default defineComponent({ + name: 'DRadio', + props: radioProps, + emits: ['change', 'update:modelValue'], + setup(props: ExtractPropTypes<typeof radioProps>, { emit }) { + const radioGroupConf = inject(radioGroupInjectionKey, null); + + /** 是否禁用 */ + const isDisabled = computed(() => { + return props.disabled || radioGroupConf?.disabled.value + }); + /** 判断是否勾选 */ + const isChecked = computed(() => { + const _value = radioGroupConf ? radioGroupConf.modelValue.value : props.modelValue; + + return props.value === _value; + }); + /** radio 的 name 属性 */ + const radioName = computed(() => { + return radioGroupConf ? radioGroupConf.name.value : props.name; + }); + + /** 判断是否允许切换 */ + const judgeCanChange = (_value: string) => { + const beforeChange = props.beforeChange || (radioGroupConf ? radioGroupConf.beforeChange : null); + + let flag = Promise.resolve(true); + if (beforeChange) { + const canChange = beforeChange(_value); + if (typeof canChange === 'undefined') { + return flag; + } + if (typeof canChange === 'boolean') { + flag = Promise.resolve(canChange); + } else { + flag = canChange; + } + } + return flag; + }; + + return { + isChecked, + radioName, + disabled: isDisabled, + handleChange: async (event: Event) => { + const _value = props.value; + const canChange = await judgeCanChange(_value); + + // 不可以切换 + if (!canChange) { + event.preventDefault(); + return; + } + radioGroupConf?.emitChange(_value); // 触发父组件的change + emit('update:modelValue', _value); + emit('change', _value); + } + }; + }, + render() { + const { + disabled, + radioName, + value, + isChecked, + $slots, + handleChange + } = this; + const labelCls = [ + 'devui-radio', + { + active: isChecked, + disabled + } + ]; + + return ( + <label class={labelCls}> + <input + type="radio" + name={radioName} + class="devui-radio-input" + disabled={disabled} + onChange={handleChange} + value={value} + checked={isChecked} + /> + <span class="devui-radio-material"> + <svg height="100%" width="100%" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> + <circle class="devui-radio-material-outer" cx="512" cy="512" r="486.5" stroke-width="51" /> + <circle class="devui-radio-material-inner" cx="512" fill-rule="nonzero" cy="512" r="320" /> + </svg> + </span> + <span class="devui-radio-label">{$slots.default?.()}</span> + </label> + ); + } +}); diff --git a/packages/devui-vue/devui/rate/__tests__/rate.spec.ts b/packages/devui-vue/devui/rate/__tests__/rate.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..647572d45a8f59283d7b3ffb3b7a8f2bad00da5e --- /dev/null +++ b/packages/devui-vue/devui/rate/__tests__/rate.spec.ts @@ -0,0 +1,135 @@ +import { mount } from '@vue/test-utils' +import { ref, nextTick } from 'vue' +import DRate from '../src/rate' + +describe('rate', () => { + describe('rate basic', () => { + const TestComponent = { + components: { + 'd-rate': DRate, + }, + template: ` + <div> + <d-rate v-model="value" icon="star-o" /> + </div> + `, + setup() { + const value = ref(0) + + return { + value, + } + }, + } + const wrapper = mount(TestComponent) + it('Rate demo has created successfully', async () => { + expect(wrapper).toBeTruthy() + }) + + it('Rate should have content', () => { + const container = wrapper.find('.devui-star-container') + expect(container.exists()).toBeTruthy() + }) + }) + + describe('rate change', () => { + it('Rate can be changed', async () => { + const wrapper = mount({ + components: { + 'd-rate': DRate, + }, + template: ` + <div> + <d-rate v-model="value" icon="star-o" /> + <div class="count">当前有{{ value }}颗星</div> + </div> + `, + setup() { + const value = ref(0) + + return { + value, + } + }, + }) + await nextTick() + + const starEles = wrapper.findAll('.devui-star-align') + + const container = wrapper.find('.devui-star-container') + const firstStarEle = starEles[0] + const thirdStarEle = starEles[2] + const fourthStarEle = starEles[3] + + expect(starEles.length).toBe(5) + + await fourthStarEle.trigger('mouseover') + + expect( + fourthStarEle.find('.devui-star-color-active').attributes('style') + ).toBe('width: 100%;') + + await container.trigger('mouseleave') + expect( + fourthStarEle.find('.devui-star-color-active').attributes('style') + ).toBe('width: 0px;') + expect(wrapper.find('.count').html()).toContain('0') + + await firstStarEle.trigger('click') + + expect(wrapper.find('.count').html()).toContain('1') + + await thirdStarEle.trigger('click') + expect(wrapper.find('.count').html()).toContain('3') + + await container.trigger('mouseleave') + expect( + fourthStarEle.find('.devui-star-color-active').attributes('style') + ).toBe('width: 0px;') + expect(wrapper.find('.count').html()).toContain('3') + }) + }) + + describe('read only', () => { + const TestComponent = { + components: { + 'd-rate': DRate, + }, + template: ` + <div> + <d-rate v-model="value" icon="star-o" :read="true"/> + <div class="count">当前有{{ value }}颗星</div> + </div> + `, + setup() { + const value = ref(3) + + return { + value, + } + }, + } + const wrapper = mount(TestComponent) + + it('Rate should have content', async () => { + expect(wrapper.find('.devui-star-container').exists()).toBeTruthy() + }) + + it('Rate should not be changed', async () => { + const starEles = wrapper.findAll('.devui-star-align') + + const firstStarEle = starEles[0] + const thirdStarEle = starEles[2] + const fourthStarEle = starEles[3] + + await firstStarEle.trigger('click') + expect(wrapper.find('.count').html()).toContain('3') + + await thirdStarEle.trigger('click') + expect(wrapper.find('.count').html()).toContain('3') + + await fourthStarEle.trigger('click') + expect(wrapper.find('.count').html()).toContain('3') + }) + }) +}) diff --git a/packages/devui-vue/devui/rate/index.ts b/packages/devui-vue/devui/rate/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae9d10d1c0ca1035ee2f494c73ecc8f8f7ff8783 --- /dev/null +++ b/packages/devui-vue/devui/rate/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Rate from './src/rate' + +Rate.install = function (app: App) { + app.component(Rate.name, Rate) +} + +export { Rate } + +export default { + title: 'Rate 评分', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Rate as any); + }, +} diff --git a/packages/devui-vue/devui/rate/src/rate.scss b/packages/devui-vue/devui/rate/src/rate.scss new file mode 100644 index 0000000000000000000000000000000000000000..e8790c9393c9b9b554112fd58631b7a90b1cfc1d --- /dev/null +++ b/packages/devui-vue/devui/rate/src/rate.scss @@ -0,0 +1,74 @@ +@import '../../style/theme/color'; +@import '../../style/core/_font'; + +.devui-star-align { + font-size: $devui-font-size-icon; + margin-right: 5px; + position: relative; + line-height: 1; +} + +.devui-pointer { + cursor: pointer; +} + +.devui-star-container { + display: inline-flex; +} + +.devui-star-color-active { + color: #6a81ed; + line-height: 1.5; + + svg g { + fill: #6a81ed; + } +} + +.devui-star-color-success { + color: #3dcca6; + + svg g { + fill: #3dcca6; + } +} + +.devui-star-color-warning { + color: #fac20a; + + svg g { + fill: #fac20a; + } +} + +.devui-star-color-error { + color: #f66f6a; + + svg g { + fill: #f66f6a; + } +} + +.devui-active-star { + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.devui-star-color { + color: $devui-dividing-line; + line-height: 1.5; + + .icon { + color: $devui-dividing-line !important; + } + + svg g { + fill: $devui-dividing-line; + } +} + +.devui-only-read { + cursor: not-allowed; +} diff --git a/packages/devui-vue/devui/rate/src/rate.tsx b/packages/devui-vue/devui/rate/src/rate.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d9ccd7595dfe8b3090474c5d089bd3435c11e670 --- /dev/null +++ b/packages/devui-vue/devui/rate/src/rate.tsx @@ -0,0 +1,196 @@ +import { defineComponent, onMounted, reactive, ref } from 'vue' +import { rateProps } from './use-rate' +import './rate.scss' + +export default defineComponent({ + name: 'DRate', + props: rateProps, + emits: ['change', 'update:modelValue'], + setup(props, ctx) { + const totalLevelArray = reactive<Record<string, any>[]>([]) + const chooseValue = ref(0) + + // 根据mouseMove,mouseLeave,select等操作,改变颜色与是否选中 + const setChange = (start: number, end: number, width: string) => { + for (let i = start; i < end; i++) { + totalLevelArray[i]['width'] = width + } + } + + // 初始化设置 + const initRating = () => { + if (!props.modelValue) { + return + } + chooseValue.value = props.modelValue - 1 + const halfStar = chooseValue.value % 1 + const intCurrentLevel = Math.floor(chooseValue.value) + setChange(0, intCurrentLevel + 1, '100%') + if (halfStar > 0) { + totalLevelArray[intCurrentLevel + 1]['width'] = halfStar * 100 + '%' + setChange(intCurrentLevel + 2, props.count, '0') + } else { + setChange(intCurrentLevel + 1, props.count, '0') + } + } + + onMounted(() => { + for (let i = 0; i < props.count; i++) { + totalLevelArray.push({ width: '0' }) + } + initRating() + }) + + const hoverToggle = (e, index: number, reset = false) => { + if (props.read) { + return + } + if (reset) { + if (chooseValue.value >= 0) { + setChange(0, chooseValue.value + 1, '100%') + setChange(chooseValue.value + 1, props.count, '0') + } else { + setChange(0, props.count, '0') + } + } else { + setChange(0, index + 1, '100%') + // 判断是否是半选模式并且判断鼠标所在图标区域 + if (props.allowHalf && (e.offsetX * 2 <= e.target.clientWidth)) { + setChange(index, index + 1, '50%') + } else { + setChange(index, index + 1, '100%') + } + setChange(index + 1, props.count, '0') + } + } + + const selectValue = (e, index: number) => { + if (props.read) { + return + } + setChange(0, index, '100%') + // 判断是否是半选模式 + if (props.allowHalf && (e.offsetX * 2 <= e.target.clientWidth)) { + setChange(index, index + 1, '50%') + chooseValue.value = index - 0.5 + } else { + setChange(index, index + 1, '100%') + chooseValue.value = index + } + setChange(index + 1, props.count, '0') + index = chooseValue.value + props.onChange && props.onChange(index + 1) + props.onTouched && props.onTouched() + ctx.emit('update:modelValue', index + 1) + } + return { + totalLevelArray, + chooseValue, + hoverToggle, + selectValue, + } + }, + render() { + const { + totalLevelArray, + chooseValue, + icon, + character, + read, + type, + color, + hoverToggle, + selectValue + } = this + return ( + <div + class="devui-star-container" + onMouseleave={(e) => hoverToggle(e, chooseValue, true)} + > + {totalLevelArray.map((item, index) => ( + <div + class={`devui-star-align devui-pointer ${read ? 'devui-only-read' : '' + }`} + key={index} + onMouseover={(e) => hoverToggle(e, index)} + onClick={(e) => selectValue(e, index)} + > + {icon && !character && ( + <span class="devui-star-color"> + <d-icon name={icon} /> + </span> + )} + {character && !icon && ( + <span class="devui-star-color">{character}</span> + )} + {!icon && !character && ( + <span class="devui-star-color"> + <svg + width="16px" + height="16px" + viewBox="0 0 16 16" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns-xlink="http://www.w3.org/1999/xlink" + > + <g + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + > + <g fill="#E3E5E9" id="Mask"> + <polygon points="8 12.7603585 3.67376208 14.3147912 3.81523437 9.71994835 1 6.0857977 5.41367261 4.80046131 8 1 10.5863274 4.80046131 15 6.0857977 12.1847656 9.71994835 12.3262379 14.3147912"></polygon> + </g> + </g> + </svg> + </span> + )} + {icon && !character && ( + <span + class={`devui-star-color-active devui-active-star devui-star-color-${type}`} + style={{ width: item.width }} + > + <d-icon name={icon} color={color} /> + </span> + )} + {character && !icon && ( + <span + class={`devui-star-color-active devui-active-star devui-star-color-${type}`} + style={{ color: color, width: item.width }} + > + {character} + </span> + )} + {!character && !icon && ( + <span + class={`devui-star-color-active devui-active-star devui-star-color-${type}`} + style={{ color: color, width: item.width }} + > + <svg + width="16px" + height="16px" + viewBox="0 0 16 16" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns-xlink="http://www.w3.org/1999/xlink" + > + <g + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + > + <g id="Mask"> + <polygon points="8 12.7603585 3.67376208 14.3147912 3.81523437 9.71994835 1 6.0857977 5.41367261 4.80046131 8 1 10.5863274 4.80046131 15 6.0857977 12.1847656 9.71994835 12.3262379 14.3147912"></polygon> + </g> + </g> + </svg> + </span> + )} + </div> + ))} + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/rate/src/use-rate.ts b/packages/devui-vue/devui/rate/src/use-rate.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5ced884beff9551ea942b7760666c1d1ae27a0c --- /dev/null +++ b/packages/devui-vue/devui/rate/src/use-rate.ts @@ -0,0 +1,44 @@ +import { PropType } from 'vue' + +type RateStatusType = PropType<'success' | 'warning' | 'error'> +export const rateProps = { + modelValue: { + type: Number, + }, + read: { + type: Boolean, + default: false, + }, + count: { + type: Number, + default: 5, + }, + type: { + type: String as RateStatusType, + default: '', + }, + color: { + type: String, + default: '', + }, + icon: { + type: String, + default: '', + }, + character: { + type: String, + default: '', + }, + allowHalf: { + type: Boolean, + default: false, + }, + onChange: { + type: Function as PropType<(value: number) => void>, + default: undefined, + }, + onTouched: { + type: Function as PropType<() => void>, + default: undefined, + }, +} diff --git a/packages/devui-vue/devui/read-tip/__tests__/read-tip.spec.ts b/packages/devui-vue/devui/read-tip/__tests__/read-tip.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fae43c0e63a45a3f7dca07b4e5b4a02c22c6f84c --- /dev/null +++ b/packages/devui-vue/devui/read-tip/__tests__/read-tip.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { ReadTip, ReadTipDirective } from '../index'; + +describe('read-tip test', () => { + it('read-tip init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/read-tip/index.ts b/packages/devui-vue/devui/read-tip/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..db1b532c6fda5e7fcce0288f9baa6f3d312885f1 --- /dev/null +++ b/packages/devui-vue/devui/read-tip/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import ReadTip from './src/read-tip' + +ReadTip.install = function(app: App): void { + app.component(ReadTip.name, ReadTip) +} + +export { ReadTip, } + +export default { + title: 'ReadTip 阅读提示', + category: '反馈', + status: '30%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(ReadTip as any) + } +} diff --git a/packages/devui-vue/devui/read-tip/src/read-tip-directive.ts b/packages/devui-vue/devui/read-tip/src/read-tip-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..788dde30eedb905e475ad731757230cb936f4d3a --- /dev/null +++ b/packages/devui-vue/devui/read-tip/src/read-tip-directive.ts @@ -0,0 +1,10 @@ +// can export function. +export default { + // created() { }, + // beforeMount() { }, + // mounted() { }, + // beforeUpdate() { }, + // updated() { }, + // beforeUnmount() { }, + // unmounted() { } +} diff --git a/packages/devui-vue/devui/read-tip/src/read-tip-template.tsx b/packages/devui-vue/devui/read-tip/src/read-tip-template.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9ef7afb9187703e179d1c1f64622da87df0a0db7 --- /dev/null +++ b/packages/devui-vue/devui/read-tip/src/read-tip-template.tsx @@ -0,0 +1,52 @@ +import { defineComponent, ref, onMounted, Teleport } from 'vue' +import { readTipProps, ReadTipProps, } from './read-tip-types' +import './read-tip.scss' + +export default defineComponent({ + name: 'DReadTipTemplate', + props: readTipProps, + emits: [], + setup(props: ReadTipProps, ctx) { + const query = props.defaultTemplateProps?.id ? `#${props.defaultTemplateProps.id}` : props.defaultTemplateProps.selector + + const temp = ref(null) + onMounted(() => { + // 当定位为top展示时 元素定位高度需要计算弹窗的高度 + if(props.defaultTemplateProps.position == 'top') { + temp.value.style.top = (- temp.value.offsetHeight - 10) + 'px' + } + }) + return () => { + return ( + <Teleport to={query} > + <div + ref={temp} + class={['read-tip-container', props.defaultTemplateProps.position]} + > + <span class='after' ></span> + { + props.defaultTemplateProps.contentTemplate ? ctx.slots?.default() : + ( + <> + <div class="title"> + {props.defaultTemplateProps.title} + </div> + <div class="content"> + {props.defaultTemplateProps.content} + </div> + </> + ) + } + + {/* { + ctx.slots?.default() + } */} + + </div> + </Teleport> + + + ) + } + } +}) diff --git a/packages/devui-vue/devui/read-tip/src/read-tip-types.ts b/packages/devui-vue/devui/read-tip/src/read-tip-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..422d29909a14880fc5d8dd19b8061a773d07ca69 --- /dev/null +++ b/packages/devui-vue/devui/read-tip/src/read-tip-types.ts @@ -0,0 +1,59 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export const readTipProps = { + readTipOptions: { + type: Object as PropType<ReadTipOptions> + }, + defaultTemplateProps: { + type: Object as PropType<DefaultTemplateProps> + } +} as const + +export type Position = 'top' | 'left' | 'right' | 'bottom' +export type Trigger = 'hover' | 'click' + +export type DefaultTemplateProps = { + title?: string + content?: string + top?: number + selector?: string + position?: string + id? : string + temp: string + contentTemplate: boolean +} + +export interface ReadTipOptions { + trigger?: Trigger + showAnimate?: boolean + mouseenterTime?: number + mouseleaveTime?: number + position?: Position + overlayClassName?: string + appendToBody?: boolean + rules: ReadTipRules +} + +export type ReadTipRules = ReadTipRule | ReadTipRule[]; + +export interface ReadTipRule { + key?: string + selector: string + trigger?: Trigger + title?: string + content?: string + showAnimate?: boolean + mouseenterTime?: number + mouseleaveTime?: number + position?: Position + overlayClassName?: string + appendToBody?: boolean + //customData与template搭配使用,customData为传入模板的上下文,可以自定义模板内容 + // dataFn?: ({ + // element, + // rule: ReadTipRule, + // }) => Observable<{ title?: string; content?: string; template?: TemplateRef<any>; customData?: any }> +} + + +export type ReadTipProps = ExtractPropTypes<typeof readTipProps> diff --git a/packages/devui-vue/devui/read-tip/src/read-tip.scss b/packages/devui-vue/devui/read-tip/src/read-tip.scss new file mode 100644 index 0000000000000000000000000000000000000000..e113de163cc787ef65f0dcbe8cee85c856fa6dc5 --- /dev/null +++ b/packages/devui-vue/devui/read-tip/src/read-tip.scss @@ -0,0 +1,79 @@ +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/mixins/index'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +// @import '../../style/core/z-index'; +.devui-read-tip { + position: relative; +} + +.source { + overflow: initial; +} + +.read-tip-container { + font-size: $devui-font-size; + position: absolute; + width: max-content; + height: max-content; + // top: 0; + // left: 0; + line-height: 1.5; + border: none; + border-radius: $devui-border-radius-feedback; + // z-index: $devui-z-index-pop-up; + background-color: $devui-feedback-overlay-bg; + color: $devui-feedback-overlay-text; + overflow-wrap: break-word; + padding: 10px; + z-index: 50; + + .after { + content: ''; + width: 12px; + height: 12px; + transform: rotate(45deg); + position: absolute; + background-color: $devui-feedback-overlay-bg; + } + // 定位 top + &.top { + top: -60px; + left: 0; + + .after { + bottom: -4px; + } + } + + // 定位 left + &.left { + right: calc(100% + 10px); + top: -2px; + + .after { + right: -4px; + } + } + + // 定位 right + &.right { + left: calc(100% + 10px); + top: -2px; + + .after { + left: -4px; + } + } + + // 定位 bottom + &.bottom { + top: calc(100% + 10px); + + .after { + top: -4px; + } + } +} diff --git a/packages/devui-vue/devui/read-tip/src/read-tip.tsx b/packages/devui-vue/devui/read-tip/src/read-tip.tsx new file mode 100644 index 0000000000000000000000000000000000000000..74333c4dbd8d756fb44aaf932a2a8c4ff4adfc1b --- /dev/null +++ b/packages/devui-vue/devui/read-tip/src/read-tip.tsx @@ -0,0 +1,163 @@ +import { defineComponent, ref, onMounted, reactive, Teleport, onUnmounted } from 'vue' +import { readTipProps, ReadTipProps, ReadTipOptions } from './read-tip-types' +import './read-tip.scss' +import TipsTemplate from './read-tip-template'; + +export default defineComponent({ + name: 'DReadTip', + props: readTipProps, + emits: [], + setup(props: ReadTipProps, ctx) { + // 默认配置 + const defaultOptions: ReadTipOptions = { + trigger: 'hover', + showAnimate: false, + mouseenterTime: 100, + mouseleaveTime: 100, + position: 'top', + overlayClassName: '', + appendToBody: true, + rules: { selector: null }, + }; + const tempTop = ref(0) + // 合并基础配置 + const options = { ...defaultOptions, ...props.readTipOptions } + const defaultSlot = ref(null) + const onMouseenter = (rule) => () => { + setTimeout(() => { + if (rule.id) { + const a = refRules.find(u => u.id === rule.id) + a.status = true + } + rule.status = true + }, rule.mouseenterTime || options.mouseenterTime); + } + const onMouseleave = (rule) => () => { + setTimeout(() => { + if (rule.id) { + const a = refRules.find(u => u.id === rule.id) + a.status = false + } + rule.status = false + + }, rule.mouseleaveTime || options.mouseleaveTime); + } + + const init = (rules, trigger = 'hover') => { + rules.map(rule => { + rule.status = false + trigger = rule.trigger || trigger + rule.contentTemplate = !!(ctx.slots.contentTemplate) + const doms = defaultSlot.value.querySelectorAll(rule.selector); + [...doms].map((dom, index) => { + dom.style.position = 'relative' + + let newRule = reactive({ + id: null + }) + if (index > 0) { + newRule = { ...rule } + dom.id = rule.selector.slice(1) + index + newRule.id = rule.selector.slice(1) + index + rules.push(newRule) + } + + if (trigger === 'hover') { + dom.addEventListener('mouseenter', onMouseenter(newRule.id ? newRule : rule,)) + dom.addEventListener('mouseleave', onMouseleave(newRule.id ? newRule : rule)) + } + }) + + }) + return rules + } + function show(dom, rule) { + const top = dom.offsetTop + rule.status = true + } + // 把传入的props.rules统一转为数组对象格式 + const rules = (rules) => { + if (rules === null) return + if (typeof rules === 'object' && !Array.isArray(rules)) { + rules = [rules] + } + rules = [...rules] + Array.isArray(rules) && rules.map(rule => { + rule.status = false + }) + return rules + } + const refRules = reactive(rules(options.rules)) + const clickFn = () => { + refRules.forEach(element => { + element.status = false + }) + } + onMounted(() => { + init(refRules, options.trigger) + // 点击其他位置 关闭弹框 + document.addEventListener('click', clickFn, true) + + }) + + onUnmounted(() => { + // 取消事件 + document.removeEventListener('click', clickFn) + }) + + // 添加点击事件 当前元素是click事件目标则弹框展示 + const onClick = (e: Event) => { + for (const rule of refRules) { + const doms = defaultSlot.value.querySelectorAll(rule.selector); + for (const dom of doms) { + if (doms.length > 1) { + if (dom === e.target && rule.id) { + show(dom, rule) + return + + } else if (dom === e.target && !rule.id && !dom.id) { + show(dom, rule) + return + } + + } else + + if (dom === e.target) { + show(dom, rule) + return + } else { + rule.status = false + } + } + + } + + } + return () => { + return (<div class="devui-read-tip" > + <div ref={defaultSlot} + onClick={onClick} + > + { + ctx.slots?.default() + } + </div> + + {(refRules).map(rule => ( + <div + + > + {rule.status && (<TipsTemplate defaultTemplateProps={{ ...rule, top: tempTop, }} > + { + rule.contentTemplate && ctx.slots?.contentTemplate() + } + </TipsTemplate>) + + } + </div> + ) + )} + </div>) + } + } +}) diff --git a/packages/devui-vue/devui/ripple/index.ts b/packages/devui-vue/devui/ripple/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ff7ce72a4c2385dcfa67ee10b51070f2e4b5f7e --- /dev/null +++ b/packages/devui-vue/devui/ripple/index.ts @@ -0,0 +1,13 @@ +import type { App } from 'vue' +import RippleDirective from './src/ripple-directive' + +export { RippleDirective } + +export default { + title: 'Ripple 水波纹', + category: '通用', + status: '已完成', + install(app: App): void { + app.directive('Ripple', RippleDirective) + } +} diff --git a/packages/devui-vue/devui/ripple/src/options.ts b/packages/devui-vue/devui/ripple/src/options.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a5f916878ac0cdef2b491df1159a2e11c963303 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/options.ts @@ -0,0 +1,80 @@ +interface IRippleDirectiveOptions { + /** + * + * @remarks + * Y* 你可以设置 ·currentColor· to 能够自动使用元素的文本颜色 + * + * @default + * 'currentColor' + */ + color: string + /** + * 第一次出现的透明度 + * + * @default + * 0.2 默认opacity 0.2 + */ + initialOpacity: number + /** + * 在透明度 结束的时候 stopped 的时候 我们设置透明度的大小 + * + * @default + * 0.1 + */ + finalOpacity: number + /** + * 动画持续事件 + * + * @default + * 0.4 + */ + duration: number + /** + * css 动画 从开始到结束 以相同的时间来执行动画 + * + * @default + * 'ease-out' + */ + easing: string + /** + * 取消延迟时间 + * + * @note + * 类似于 debounceTime + * @default + * 75 + */ + delayTime: number +} + +interface IRipplePluginOptions extends IRippleDirectiveOptions { + /** + * 用于覆盖指令的名称 + * + * @remarks + * + * @example + * + * @default + * 默认指令 ripple + */ + directive: string +} + +// 给可预见值 value 添加类型 + +interface IRippleDirectiveOptionWithBinding { + value: IRippleDirectiveOptions +} + +const DEFAULT_PLUGIN_OPTIONS: IRipplePluginOptions = { + directive: 'ripple', + color: 'currentColor', + initialOpacity: 0.2, + finalOpacity: 0.1, + duration: 0.8, + easing: 'ease-out', + delayTime: 75 +} + +export { DEFAULT_PLUGIN_OPTIONS, IRipplePluginOptions, IRippleDirectiveOptions, IRippleDirectiveOptionWithBinding } diff --git a/packages/devui-vue/devui/ripple/src/ripple-directive.ts b/packages/devui-vue/devui/ripple/src/ripple-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7b4730c4d82a1a3058a9407ab8d7cf5247d878d --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/ripple-directive.ts @@ -0,0 +1,31 @@ +// can export function. 解构参数类型冗余 新定义insterface IRippleDirectiveOptionWithBinding +import { + DEFAULT_PLUGIN_OPTIONS, + IRippleDirectiveOptions, + IRippleDirectiveOptionWithBinding +} from './options' +import { ripple } from './v-ripple' +const optionMap = new WeakMap< + HTMLElement, + Partial<IRippleDirectiveOptions> | false +>() +const globalOptions = { ...DEFAULT_PLUGIN_OPTIONS } +export default { + mounted(el: HTMLElement, binding: IRippleDirectiveOptionWithBinding) { + optionMap.set(el, binding.value ?? {}) + + el.addEventListener('pointerdown', (event) => { + const options = optionMap.get(el) + + if (options === false) return + + ripple(event, el, { + ...globalOptions, + ...options + }) + }) + }, + updated(el: HTMLElement, binding: IRippleDirectiveOptionWithBinding) { + optionMap.set(el, binding.value ?? {}) + } +} diff --git a/packages/devui-vue/devui/ripple/src/utils/create-container-element.ts b/packages/devui-vue/devui/ripple/src/utils/create-container-element.ts new file mode 100644 index 0000000000000000000000000000000000000000..36cfee3e6d86f9eb367ef0046f1e1ec30923b503 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/create-container-element.ts @@ -0,0 +1,21 @@ +export const createContainer = ({ + borderTopLeftRadius, + borderTopRightRadius, + borderBottomLeftRadius, + borderBottomRightRadius +}: CSSStyleDeclaration): HTMLElement => { + const rippleContainer = document.createElement('div') + rippleContainer.style.top = '0' + rippleContainer.style.left = '0' + rippleContainer.style.width = '100%' + rippleContainer.style.height = '100%' + rippleContainer.style.position = 'absolute' + rippleContainer.style.borderRadius = `${borderTopLeftRadius} ${borderTopRightRadius} ${borderBottomRightRadius} ${borderBottomLeftRadius}` + rippleContainer.style.overflow = 'hidden' + rippleContainer.style.pointerEvents = 'none' + + // 兼容 ie 苹果 + rippleContainer.style.webkitMaskImage = '-webkit-radial-gradient(white, black)' + + return rippleContainer +} diff --git a/packages/devui-vue/devui/ripple/src/utils/create-ripple-element.ts b/packages/devui-vue/devui/ripple/src/utils/create-ripple-element.ts new file mode 100644 index 0000000000000000000000000000000000000000..87a69faf51fd8def787c1056c69c68407895cdf0 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/create-ripple-element.ts @@ -0,0 +1,23 @@ +import { IRippleDirectiveOptions } from '../options' + +export const createrippleElement = ( + x: number, + y: number, + size: number, + options: IRippleDirectiveOptions +): HTMLElement => { + const rippleElement = document.createElement('div') + + rippleElement.style.position = 'absolute' + rippleElement.style.width = `${size}px` + rippleElement.style.height = `${size}px` + rippleElement.style.top = `${y}px` + rippleElement.style.left = `${x}px` + rippleElement.style.background = options.color + rippleElement.style.borderRadius = '50%' + rippleElement.style.opacity = `${options.initialOpacity}` + rippleElement.style.transform = `translate(-50%,-50%) scale(0)` + rippleElement.style.transition = `transform ${options.duration}s ${options.easing}, opacity ${options.duration}s ${options.easing}` + + return rippleElement +} diff --git a/packages/devui-vue/devui/ripple/src/utils/getdistance-tofurthestcorner.ts b/packages/devui-vue/devui/ripple/src/utils/getdistance-tofurthestcorner.ts new file mode 100644 index 0000000000000000000000000000000000000000..cadb428d91c9135c0b3af67713d1000d1199ff95 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/getdistance-tofurthestcorner.ts @@ -0,0 +1,14 @@ +import { magnitude } from './magnitude' + +export function getDistanceToFurthestCorner( + x: number, + y: number, + { width, height }: DOMRect +): number { + // 获取点击目标的位置到块级作用域边界的距离 + const topLeft = magnitude(x, y, 0, 0) + const topRight = magnitude(x, y, width, 0) + const bottomLeft = magnitude(x, y, 0, height) + const bottomRight = magnitude(x, y, width, height) + return Math.max(topLeft, topRight, bottomLeft, bottomRight) +} diff --git a/packages/devui-vue/devui/ripple/src/utils/getrelative-pointer.ts b/packages/devui-vue/devui/ripple/src/utils/getrelative-pointer.ts new file mode 100644 index 0000000000000000000000000000000000000000..44d75b8127ab8c98ac90157fb603219f369f1154 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/getrelative-pointer.ts @@ -0,0 +1,7 @@ +export const getRelativePointer = ( + { x, y }: PointerEvent, + { top, left }: DOMRect +) => ({ + x: x - left, + y: y - top +}) diff --git a/packages/devui-vue/devui/ripple/src/utils/magnitude.ts b/packages/devui-vue/devui/ripple/src/utils/magnitude.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed2202498ff9d03f3179cbc690afa9f510e2f90a --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/magnitude.ts @@ -0,0 +1,6 @@ +export function magnitude(x1: number, y1: number, x2: number, y2: number): number { + const deltaX = x1 - x2 + const deltaY = y1 - y2 + + return Math.sqrt(deltaX * deltaX + deltaY * deltaY) +} diff --git a/packages/devui-vue/devui/ripple/src/utils/ripple-count.ts b/packages/devui-vue/devui/ripple/src/utils/ripple-count.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d9720d1668bb1df058a8b019bd6ca42e6690b65 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/utils/ripple-count.ts @@ -0,0 +1,23 @@ +const RIPPLE_COUNT = 'vRippleCountInternal' + +export function incrementRippleCount(el: HTMLElement) { + const count = getRippleCount(el) + setRippleCount(el, count + 1) +} + +export function decrementRippleCount(el: HTMLElement) { + const count = getRippleCount(el) + setRippleCount(el, count - 1) +} + +function setRippleCount(el: HTMLElement, count: number) { + el.dataset[RIPPLE_COUNT] = count.toString() +} + +export function getRippleCount(el: HTMLElement): number { + return parseInt(el.dataset[RIPPLE_COUNT] ?? '0', 10) +} + +export function deleteRippleCount(el: HTMLElement) { + delete el.dataset[RIPPLE_COUNT] +} diff --git a/packages/devui-vue/devui/ripple/src/v-ripple.ts b/packages/devui-vue/devui/ripple/src/v-ripple.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d7586cc8e90ad561e6ec49f65ce2a589272ded7 --- /dev/null +++ b/packages/devui-vue/devui/ripple/src/v-ripple.ts @@ -0,0 +1,90 @@ +import { createContainer } from './utils/create-container-element' +import { createrippleElement } from './utils/create-ripple-element' +import { getDistanceToFurthestCorner } from './utils/getdistance-tofurthestcorner' +import { getRelativePointer } from './utils/getrelative-pointer' +import { + decrementRippleCount, + deleteRippleCount, + getRippleCount, + incrementRippleCount +} from './utils/ripple-count' +import { IRippleDirectiveOptions } from './options' +const MULTIPLE_NUMBER = 2.05 +const ripple = ( + event: PointerEvent, + el: HTMLElement, + options: IRippleDirectiveOptions +) => { + const rect = el.getBoundingClientRect() + const computedStyles = window.getComputedStyle(el) + const { x, y } = getRelativePointer(event, rect) + const size = MULTIPLE_NUMBER * getDistanceToFurthestCorner(x, y, rect) + + const rippleContainer = createContainer(computedStyles) + const rippleEl = createrippleElement(x, y, size, options) + + incrementRippleCount(el) + + let originalPositionValue = '' + if (computedStyles.position === 'static') { + if (el.style.position) originalPositionValue = el.style.position + el.style.position = 'relative' + } + + rippleContainer.appendChild(rippleEl) + el.appendChild(rippleContainer) + + let shouldDissolveripple = false + const releaseripple = (e?: any) => { + if (typeof e !== 'undefined') { + document.removeEventListener('pointerup', releaseripple) + document.removeEventListener('pointercancel', releaseripple) + } + + if (shouldDissolveripple) dissolveripple() + else shouldDissolveripple = true + } + + const dissolveripple = () => { + rippleEl.style.transition = 'opacity 150ms linear' + rippleEl.style.opacity = '0' + + setTimeout(() => { + rippleContainer.remove() + + decrementRippleCount(el) + + if (getRippleCount(el) === 0) { + deleteRippleCount(el) + el.style.position = originalPositionValue + } + }, 150) + } + + document.addEventListener('pointerup', releaseripple) + document.addEventListener('pointercancel', releaseripple) + + const token = setTimeout(() => { + document.removeEventListener('pointercancel', cancelripple) + + requestAnimationFrame(() => { + rippleEl.style.transform = `translate(-50%,-50%) scale(1)` + rippleEl.style.opacity = `${options.finalOpacity}` + + setTimeout(() => releaseripple(), options.duration * 1000) + }) + }, options.delayTime) + + const cancelripple = () => { + clearTimeout(token) + + rippleContainer.remove() + document.removeEventListener('pointerup', releaseripple) + document.removeEventListener('pointercancel', releaseripple) + document.removeEventListener('pointercancel', cancelripple) + } + + document.addEventListener('pointercancel', cancelripple) +} + +export { ripple } diff --git a/packages/devui-vue/devui/search/hooks/use-search-class.ts b/packages/devui-vue/devui/search/hooks/use-search-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..36b4c79ffd7209353c5203efec6ce76548fffbba --- /dev/null +++ b/packages/devui-vue/devui/search/hooks/use-search-class.ts @@ -0,0 +1,22 @@ +/** + * 定义组件class + */ +import { computed, ComputedRef } from 'vue'; +import { SearchProps } from '../src/search-types' +const SIZE_CLASS = { + lg: 'lg', + sm: 'sm', +} as const +const ICON_POSITION = { + right: 'right', + left: 'left', +} +export const getRootClass = (props: SearchProps): ComputedRef => { + return computed(() => ({ + 'devui-search': true, + 'devui-search__disbaled': props.disabled, + 'devui-search__no-border': props.noBorder, + [`devui-search__${props.size}`]: SIZE_CLASS[props.size], + [`devui-search__${props.iconPosition}`]: ICON_POSITION[props.iconPosition], + })) +} diff --git a/packages/devui-vue/devui/search/hooks/use-search-keydown.ts b/packages/devui-vue/devui/search/hooks/use-search-keydown.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e69826d50ccdd417949fffb17d3924ef013c451 --- /dev/null +++ b/packages/devui-vue/devui/search/hooks/use-search-keydown.ts @@ -0,0 +1,42 @@ +/** + * 清空按钮显示、隐藏 + */ +import { SetupContext, Ref, } from 'vue' +import { KeydownReturnTypes } from '../src/search-types' +import { debounce } from 'lodash-es' +const KEYS_MAP = { + enter: 'Enter' +} as const + +type EmitProps = 'update:modelValue' | 'searchFn' + +export const keydownHandles = (ctx: SetupContext<(EmitProps)[]>, keywords: Ref<string>, delay: number): KeydownReturnTypes => { + // 删除按钮显示 + const onInputKeydown = ($event: KeyboardEvent) => { + switch ($event.key) { + case KEYS_MAP.enter: + handleEnter($event) + break + default: + break + } + } + const handleEnter = ($event: KeyboardEvent) => { + if ($event.target instanceof HTMLInputElement) { + const value = $event.target.value + useEmitKeyword(value) + } + } + const onClickHandle = () => { + useEmitKeyword(keywords.value) + } + const useEmitKeyword = debounce((value: string) => { + ctx.emit('searchFn', value) + }, delay) + return { + onInputKeydown, + useEmitKeyword, + onClickHandle + } +} + \ No newline at end of file diff --git a/packages/devui-vue/devui/search/hooks/use-search-keywords.ts b/packages/devui-vue/devui/search/hooks/use-search-keywords.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0feccc8b40a1d622217cec8d3c0ffb3480258c5 --- /dev/null +++ b/packages/devui-vue/devui/search/hooks/use-search-keywords.ts @@ -0,0 +1,28 @@ +/** + * 输入框内容定义、删改操作 + */ +import { ref, watch, computed, SetupContext } from 'vue' +import { SearchProps, KeywordsReturnTypes } from '../src/search-types' +type EmitProps = 'update:modelValue' | 'searchFn' + +export const keywordsHandles = (ctx: SetupContext<(EmitProps)[]>, props: SearchProps): KeywordsReturnTypes => { + const keywords = ref('') // 输入框内容 + // 监听是否有双向绑定,将绑定的值传递给keyword,因为需要清除输入框 + watch(() => props.modelValue, (val)=> { + keywords.value = val + }, { immediate: true }) + // 清空输入框 + const onClearHandle = () => { + keywords.value = '' + // 清空输入框时更新modelValue为空 + ctx.emit('update:modelValue', '') + } + const clearIconShow = computed(() => { + return keywords.value.length > 0 + }) + return { + keywords, + clearIconShow, + onClearHandle + } +} diff --git a/packages/devui-vue/devui/search/index.ts b/packages/devui-vue/devui/search/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..72e9f8f7fa5e6b63b82145bcfea5d1cc9c78e03b --- /dev/null +++ b/packages/devui-vue/devui/search/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Search from './src/search' + +Search.install = function(app: App) { + app.component(Search.name, Search) +} + +export { Search } + +export default { + title: 'Search 搜索框', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(Search as any) + } +} diff --git a/packages/devui-vue/devui/search/src/search-types.ts b/packages/devui-vue/devui/search/src/search-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..05a97d6fe7197f5ee298997a5aaf49da084e6b3b --- /dev/null +++ b/packages/devui-vue/devui/search/src/search-types.ts @@ -0,0 +1,73 @@ +import type { PropType, ExtractPropTypes, Ref, ComputedRef } from 'vue' + +export type Size = 'lg' | 'sm' | '' +export type IconPosition = 'right' | 'left' + +export const searchProps = { + size: { + type: String as PropType<Size>, + default: '', + }, + placeholder: { + type: String, + default: '请输入关键字' + }, + maxLength: { + type: Number, + default: Number.MAX_SAFE_INTEGER, + }, + delay: { + type: Number, + default: 300, + }, + disabled: { + type: Boolean, + default: false + }, + autoFocus: { + type: Boolean, + default: false + }, + isKeyupSearch: { + type: Boolean, + default: false + }, + iconPosition: { + type: String as PropType<IconPosition>, + default: 'right', + }, + noBorder: { + type: Boolean, + default: false + }, + cssClass: { + type: String, + default: '' + }, + modelValue: { + type: String, + default: '', + }, + searchFn: { + type: Function as PropType<(v: string) => void>, + default: undefined + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: string) => void>, + default: undefined + }, +} as const + +export type SearchProps = ExtractPropTypes<typeof searchProps> + +export interface KeywordsReturnTypes { + keywords: Ref<string> + clearIconShow: ComputedRef<boolean> + onClearHandle: () => void +} + +export interface KeydownReturnTypes { + onInputKeydown: (e: KeyboardEvent) => void + onClickHandle: () => void + useEmitKeyword: (e: string) => void +} \ No newline at end of file diff --git a/packages/devui-vue/devui/search/src/search.scss b/packages/devui-vue/devui/search/src/search.scss new file mode 100644 index 0000000000000000000000000000000000000000..0e5c186aab2bb9501fe75f8f1f07a8d74cdf2dea --- /dev/null +++ b/packages/devui-vue/devui/search/src/search.scss @@ -0,0 +1,134 @@ +@import '../../style/mixins/size'; +@import '../../style/mixins/flex'; +@import '../../style/theme/color'; + +.devui-search { + position: relative; + @include flex; + + input { + padding: 5px 60px 5px 10px; + } + + svg.svg-icon-clear path, + svg.svg-icon-search path { + fill: $devui-icon-text; + } + + &__clear { + position: absolute; + right: 36px; + cursor: pointer; + height: 100%; + font-size: 10px; + @include size(30px, 100%); + @include flex; + + &::after { + content: ''; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 1px; + height: 46%; + border-left: 1px solid $devui-dividing-line; + } + } + + &__icon { + pointer-events: all; + cursor: pointer; + padding: 0 10px; + position: absolute; + z-index: 1; + right: 0; + top: 0; + font-size: 16px; + @include size(36px, 28px); + @include flex; + } + + &__sm { + input { + &.devui-input-sm { + padding-right: 56px; + } + } + + .devui-search__icon { + font-size: 14px; + @include size(34px, 26px); + } + + .devui-search__clear { + @include size(26px, 100%); + + right: 34px; + } + } + + &__lg { + input { + padding: 5px 36px 5px 10px; + + &.devui-input-lg { + padding-right: 71px; + } + } + + .devui-search__icon { + font-size: 18px; + @include size(46px, 46px); + } + + .devui-search__clear { + @include size(30px, 100%); + + right: 46px; + } + } + + &__disbaled { + .devui-search__icon { + cursor: not-allowed; + } + + .icon-search { + color: $devui-disabled-text !important; + } + } + + &__left { + input { + padding: 5px 26px 5px 30px; + + &.devui-input-lg { + padding-right: 30px; + padding-left: 46px; + } + + &.devui-input-sm { + padding-right: 26px; + } + } + + .devui-search__clear { + right: 0; + + &::after { + display: none; + } + } + + .devui-search__icon { + left: 0; + } + } + + &__no-border { + input { + border: none; + } + } +} diff --git a/packages/devui-vue/devui/search/src/search.tsx b/packages/devui-vue/devui/search/src/search.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6e7385279679701fde5bda0fd4d12f26cef8f43f --- /dev/null +++ b/packages/devui-vue/devui/search/src/search.tsx @@ -0,0 +1,66 @@ +import { defineComponent } from 'vue' +import { SearchProps, searchProps } from './search-types' +import { getRootClass } from '../hooks/use-search-class' +import { keywordsHandles } from '../hooks/use-search-keywords' +import { keydownHandles } from '../hooks/use-search-keydown' +import DInput from '../../input/src/input'; +import './search.scss' + +export default defineComponent({ + name: 'DSearch', + props: searchProps, + emits: ['update:modelValue', 'searchFn'], + setup(props: SearchProps, ctx) { + const rootClasses = getRootClass(props) + // 输入框内容定义、删改 + const {keywords, clearIconShow, onClearHandle} = keywordsHandles(ctx, props) + + // 键盘回车事件 + const { onInputKeydown, onClickHandle, useEmitKeyword } = keydownHandles(ctx, keywords, props.delay) + + // 双向绑定 + const onInputUpdate = (event: string) => { + if (props.isKeyupSearch) { + useEmitKeyword(event) + } + keywords.value = event + ctx.emit('update:modelValue', event) + } + + return () => { + return ( + <div class={rootClasses.value}> + {props.iconPosition === 'left' && + <div class="devui-search__icon" onClick={onClickHandle}> + <d-icon name="search" size="inherit"></d-icon> + </div> + } + <DInput + size={props.size} + disabled={props.disabled} + autoFocus={props.autoFocus} + value={keywords.value} + maxLength={props.maxLength} + placeholder={props.placeholder} + cssClass={props.cssClass} + onKeydown={onInputKeydown} + onUpdate:value={onInputUpdate} + ></DInput> + {clearIconShow.value && + <div + class="devui-search__clear" + onClick={onClearHandle} + > + <d-icon name="close" size="inherit"></d-icon> + </div> + } + {props.iconPosition === 'right' && + <div class="devui-search__icon" onClick={onClickHandle}> + <d-icon name="search" size="inherit"></d-icon> + </div> + } + </div> + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/select/__tests__/select.spec.ts b/packages/devui-vue/devui/select/__tests__/select.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d724b6fa8e9c406cc5ed0c5f2754069e79378dfe --- /dev/null +++ b/packages/devui-vue/devui/select/__tests__/select.spec.ts @@ -0,0 +1,217 @@ +import { mount } from '@vue/test-utils'; +import { ref, reactive, nextTick } from 'vue'; +import DSelect from '../src/select'; + +describe('select', () => { + it('select render work', async () => { + const value = ref(1); + const options = reactive([1, 2, 'string']); + const wrapper = mount({ + components: { DSelect }, + template: `<d-select v-model="value" :options="options" placeholder="这是默认选择框"></d-select>`, + setup() { + return { + value, + options, + }; + }, + }); + const container = wrapper.find('.devui-select'); + let dropdown = wrapper.find('.devui-select-dropdown'); + let listItems = wrapper.findAll('.devui-select-item'); + const input = wrapper.find<HTMLInputElement>('.devui-select-input'); + const arrow = wrapper.find('.devui-select-arrow'); + + expect(container.exists()).toBeTruthy(); + expect(dropdown.isVisible()).toBeFalsy(); + expect(arrow.isVisible()).toBeTruthy(); + expect(listItems.length).toBe(3); + expect(listItems[0].classes()).toContain('active'); + expect(input.attributes('placeholder')).toBe('这是默认选择框'); + expect(input.element.value).toBe('1'); + + await input.trigger('click'); + await nextTick(); + // isVisible不会自动更新需要重新获取 + dropdown = wrapper.find('.devui-select-dropdown'); + expect(dropdown.isVisible()).toBeTruthy(); + expect(container.classes()).toContain('devui-select-open'); + + await listItems[2].trigger('click'); + await nextTick(); + + // isVisible不会自动更新需要重新获取 + dropdown = wrapper.find('.devui-select-dropdown'); + expect(value.value).toBe('string'); + expect(dropdown.isVisible()).toBeFalsy(); + expect(input.element.value).toBe('string'); + // class不会自动更新需要重新获取 + listItems = wrapper.findAll('.devui-select-item'); + expect(listItems[2].classes()).toContain('active'); + }); + + it('select size and overview work', async () => { + const wrapper = mount(DSelect, { + props: { + size: 'sm', + overview: 'underlined', + }, + }); + + let container = wrapper.find('.devui-select'); + expect(container.classes()).toContain('devui-select-sm'); + expect(container.classes()).toContain('devui-select-underlined'); + + await wrapper.setProps({ + size: 'lg', + overview: 'border', + }); + + container = wrapper.find('.devui-select'); + expect(container.classes()).toContain('devui-select-lg'); + expect(container.classes()).not.toContain('devui-select-underlined'); + }); + + it('select events work', async () => { + const value = ref(2); + const options = reactive([6, 2, 'test']); + const toggleChange = jest.fn(); + const valueChange = jest.fn(); + const wrapper = mount({ + components: { DSelect }, + template: ` + <d-select + v-model="value" + :options="options" + @toggle-change="toggleChange" + @value-change="valueChange" + ></d-select> + `, + setup() { + return { + value, + options, + toggleChange, + valueChange, + }; + }, + }); + + const input = wrapper.find<HTMLInputElement>('.devui-select-input'); + await input.trigger('click'); + + expect(toggleChange).toBeCalledTimes(1); + expect(valueChange).toBeCalledTimes(0); + expect(value.value).toBe(2); + + const listItems = wrapper.findAll('.devui-select-item'); + await listItems[2].trigger('click'); + + expect(toggleChange).toBeCalledTimes(2); + expect(valueChange).toBeCalledTimes(1); + expect(value.value).toBe('test'); + }); + + it('select v-model work', async () => { + const value = ref() + const options = reactive([1,2,3]) + const wrapper = mount({ + components: { DSelect }, + template: `<d-select v-model="value" :options="options" />`, + setup() { + return { + value, + options, + }; + }, + }); + + const container = wrapper.find('.devui-select'); + const item = container.findAll('.devui-select-item'); + + await container.trigger('click') + await item[1].trigger('click') + expect(value.value).toBe(2) + value.value = 1 + await nextTick() + const input = container.find<HTMLInputElement>('.devui-select-input') + expect(input.element.value).toBe('1') + + }); + + it('select disabled work', async () => { + const wrapper = mount(DSelect, { + props: { + disabled: true, + }, + }); + + const container = wrapper.find('.devui-select'); + expect(container.classes()).toContain('devui-select-disabled'); + + const input = wrapper.find('.devui-select-input'); + expect(input.attributes()).toHaveProperty('disabled') + }); + + it('select item disabled work', async () => { + const value = ref([]) + const options = reactive([ + { + name: '多选', + value: 0 + }, { + name: '多选很重要呢', + value: 1, + disabled: true + }, { + name: '多选真的很重要呢', + value: 2, + disabled: false + } + ]) + const wrapper = mount({ + components: { DSelect }, + template: `<d-select v-model="value" :options="options" :multiple="true" option-disabled-key="disabled" />`, + setup() { + return { + value, + options, + }; + }, + }); + + const container = wrapper.find('.devui-select'); + const item = container.findAll('.devui-select-item'); + + await container.trigger('click') + await nextTick() + expect(item[1].classes()).toContain('disabled') + await item[1].trigger('click') + expect(value.value).toEqual([]) + await item[0].trigger('click') + expect(value.value).toEqual([0]) + + }); + + it('select clear work', async () => { + const value = ref(1) + const options = reactive([1,2,3]) + const wrapper = mount({ + components: { DSelect }, + template: `<d-select v-model="value" :options="options" :allow-clear="true" />`, + setup() { + return { + value, + options, + }; + }, + }); + + const container = wrapper.find('.devui-select'); + const clearIcon = container.find('.devui-select-clear'); + + expect(clearIcon.exists()).toBeTruthy() + await clearIcon.trigger('click') + expect(value.value).toBe('') + }); +}); diff --git a/packages/devui-vue/devui/select/hooks/use-cache-options.ts b/packages/devui-vue/devui/select/hooks/use-cache-options.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f27abd3a1869a028478aa58fbff61e5c7e650e3 --- /dev/null +++ b/packages/devui-vue/devui/select/hooks/use-cache-options.ts @@ -0,0 +1,18 @@ +import { ComputedRef, computed } from 'vue'; +import { OptionObjectItem } from '../src/use-select'; +import { KeyType } from '../src/utils'; + +export default function (mergeOptions: ComputedRef<OptionObjectItem[]>): any { + const cacheOptions = computed(() => { + const map = new Map<KeyType<OptionObjectItem, 'value'>, OptionObjectItem>(); + mergeOptions.value.forEach((item) => { + map.set(item.value, item); + }); + return map; + }); + + const getValuesOption = (values: KeyType<OptionObjectItem, 'value'>[]) => + values.map((value) => cacheOptions.value.get(value)); + + return getValuesOption; +} diff --git a/packages/devui-vue/devui/select/hooks/use-select-outside-click.ts b/packages/devui-vue/devui/select/hooks/use-select-outside-click.ts new file mode 100644 index 0000000000000000000000000000000000000000..463c439e6b81d4d3961e02cb1b61adc7e8d4f68b --- /dev/null +++ b/packages/devui-vue/devui/select/hooks/use-select-outside-click.ts @@ -0,0 +1,32 @@ +import { Ref, onMounted, onBeforeUnmount } from 'vue'; + +export default function ( + refs: Ref[], + isOpen: Ref<boolean>, + toggleChange: (isOpen: boolean) => void +): void { + function onGlobalMouseDown(e: MouseEvent) { + let target = e.target as HTMLElement; + + // TODO: 需要去了解下shadow DOM + if (target.shadowRoot && e.composed) { + target = (e.composedPath()[0] || target) as HTMLElement; + } + + const element = [refs[0]?.value, refs[1]?.value]; + if ( + isOpen.value && + element.every((el) => el && !el.contains(target) && el !== target) + ) { + toggleChange(false); + } + } + + onMounted(() => { + document.body.addEventListener('mousedown', onGlobalMouseDown, false); + }); + + onBeforeUnmount(() => { + document.body.addEventListener('mousedown', onGlobalMouseDown, false); + }); +} diff --git a/packages/devui-vue/devui/select/index.ts b/packages/devui-vue/devui/select/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..432604f95e9d163750153f7821550afba286b6bf --- /dev/null +++ b/packages/devui-vue/devui/select/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Select from './src/select' + +Select.install = function(app: App) { + app.component(Select.name, Select) +} + +export { Select } + +export default { + title: 'Select 下拉框', + category: '数据录入', + status: '10%', + install(app: App): void { + app.use(Select as any) + } +} diff --git a/packages/devui-vue/devui/select/src/select.scss b/packages/devui-vue/devui/select/src/select.scss new file mode 100644 index 0000000000000000000000000000000000000000..e0b0027021ef058308941f2e81bf63e8299a55e8 --- /dev/null +++ b/packages/devui-vue/devui/select/src/select.scss @@ -0,0 +1,245 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/corner'; + +$border-change-time: 300ms; +$border-change-function: cubic-bezier(0.645, 0.045, 0.355, 1); +$select-input-height-sm: 24px; +$select-input-height-md: 28px; +$select-input-height-lg: 44px; +$select-arrow-width: 28px; +$transition-base-time: 0.25s; +$select-dropdown-max-height: 300px; +$select-item-font-size: var(--devui-font-size, 12px); +$select-item-min-height: 36px; + +@mixin border-transition { + transition: border-color $border-change-time $border-change-function; +} + +.devui-select { + position: relative; + width: 100%; +} + +.devui-select-underlined { + border-bottom: 1px solid $devui-form-control-line; + @include border-transition(); + + &:not([disabled]):not(.disabled) { + &:hover { + border-color: $devui-form-control-line-hover; + } + + &.devui-select-open { + border-color: $devui-form-control-line-active; + } + } + + .devui-select-input { + border: none; + } +} + +.devui-select-disabled { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; + + .devui-select-input { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; + } + + .devui-select-arrow { + cursor: not-allowed; + color: $devui-disabled-text; + } +} + +.devui-select-open { + .devui-select-arrow { + transform: rotate3d(0, 0, 1, 180deg); + } +} + +.devui-dropdown-menu-multiple { + .devui-select-item { + &.active { + color: $devui-list-item-active-text; + background-color: transparent; + } + } +} + +.devui-select-selection { + position: relative; + cursor: pointer; +} + +.devui-select-input { + cursor: pointer; + width: 100%; + height: $select-input-height-md; + padding: 4px $select-arrow-width 4px 10px; + color: $devui-text; + vertical-align: middle; + border: 1px solid $devui-form-control-line; + border-radius: $devui-border-radius; + outline: none; + background-color: $devui-base-bg; + @include border-transition(); + + &:not([disabled]):not(.disabled) { + &:hover { + border-color: $devui-form-control-line-hover; + } + + &:focus { + border-color: $devui-form-control-line-active; + } + } + + &[disabled], + &.disabled { + &:hover { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; + } + } + + &.devui-select-input-lg { + height: $select-input-height-lg; + } + + &.devui-select-input-sm { + height: $select-input-height-sm; + } +} + +.devui-select-clearable:hover { + .devui-select-clear { + display: inline-flex; + } + + .devui-select-arrow { + display: none; + } +} + +.devui-select-clear, +.devui-select-arrow { + position: absolute; + right: 0; + height: 100%; + width: $select-arrow-width; + display: inline-flex; + justify-content: center; + align-items: center; +} + +.devui-select-clear { + display: none; + + &:hover { + color: $devui-icon-fill-active; + } +} + +.devui-select-arrow { + transform: rotate3d(0, 0, 1, 0deg); + transition: transform $transition-base-time ease-out; +} + +.devui-select-dropdown { + position: absolute; + width: calc(100% - 2px); + overflow: auto; + top: 100%; + left: 0; + margin: 5px 0; + border-radius: $devui-border-radius; + background: $devui-base-bg; + box-shadow: 0 2px 5px 0 $devui-shadow; + z-index: 999; +} + +.devui-select-dropdown-list { + max-height: $select-dropdown-max-height; + width: 100%; + overflow-y: auto; + padding: 0; + margin: 0; +} + +.devui-select-item { + font-size: $select-item-font-size; + display: block; + min-height: $select-item-min-height; + line-height: 1.5; + width: 100%; + padding: 10px; + clear: both; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + border: 0; + color: $devui-text; + cursor: pointer; + + &:hover:not(.active):not(.disabled) { + color: $devui-list-item-hover-text; + background-color: $devui-list-item-hover-bg; + } + + &.active { + color: $devui-list-item-active-text; + background-color: $devui-list-item-active-bg; + } + + &.disabled { + cursor: not-allowed; + background-color: $devui-disabled-bg; + color: $devui-disabled-text; + } +} + +.devui-scrollbar { + &::-webkit-scrollbar { + width: 8px; + height: 8px; + } + + &::-webkit-scrollbar-corner { + background-color: transparent; + } + + &::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: var(--devui-line, #adb0b8); + } + + &::-webkit-scrollbar-track { + background-color: transparent; + } +} + +.fade-enter-active, +.fade-leave-active { + transform: scale3d(0, 1, 0, 0.9999) translate3d(0, 1, 0, 0); + transform-origin: 0 0%; + opacity: 1; + transition: transform, opacity $transition-base-time ease-out; +} + +.fade-enter-from, +.fade-leave-to { + transform: scale3d(0, 1, 0, 0) translate3d(0, 1, 0, -4px); + opacity: 0; + transition: transform, opacity $transition-base-time ease-in; +} diff --git a/packages/devui-vue/devui/select/src/select.tsx b/packages/devui-vue/devui/select/src/select.tsx new file mode 100644 index 0000000000000000000000000000000000000000..008fe96ffc839c0c209e7d71e979b11e35cd3f2b --- /dev/null +++ b/packages/devui-vue/devui/select/src/select.tsx @@ -0,0 +1,210 @@ +import { defineComponent, ref, Transition, computed } from 'vue'; +import { selectProps, SelectProps, OptionObjectItem } from './use-select'; +import { Icon } from '../../icon'; +import { Checkbox } from '../../checkbox'; +import { className } from './utils'; +import useCacheOptions from '../hooks/use-cache-options'; +import useSelectOutsideClick from '../hooks/use-select-outside-click'; +import './select.scss'; + +export default defineComponent({ + name: 'DSelect', + props: selectProps, + emits: ['toggleChange', 'valueChange', 'update:modelValue'], + setup(props: SelectProps, ctx) { + const containerRef = ref(null); + const dropdownRef = ref(null); + // 控制弹窗开合 + const isOpen = ref<boolean>(false); + function toggleChange(bool: boolean) { + if (props.disabled) return; + isOpen.value = bool; + ctx.emit('toggleChange', bool); + } + useSelectOutsideClick([containerRef, dropdownRef], isOpen, toggleChange); + + // 这里对options做统一处理 + const mergeOptions = computed(() => { + const { multiple, modelValue } = props; + return props.options.map((item) => { + let option: OptionObjectItem; + if (typeof item === 'object') { + option = { + name: item.name ? item.name : item.value + '', + value: item.value, + _checked: false, + ...item, + }; + } else { + option = { + name: item + '', + value: item, + _checked: false, + }; + } + if (multiple) { + /** + * TODO: 这里mergeOptions依赖了modelValue + * 但是下面点击item更新的时候modelValue又是根据mergeOptions来算出来的 + * 因此可能会多更新一次,后续优化 + */ + if (Array.isArray(modelValue)) { + option._checked = modelValue.includes(option.value); + } else { + option._checked = false; + } + } + + return option; + }); + }); + // 缓存options,用value来获取对应的optionItem + const getValuesOption = useCacheOptions(mergeOptions); + // 控制输入框的显示内容 + const inputValue = computed<string>(() => { + if (props.multiple && Array.isArray(props.modelValue)) { + const selectedOptions = getValuesOption(props.modelValue); + return selectedOptions.map((item) => item.name).join(','); + } else if (!Array.isArray(props.modelValue)) { + return getValuesOption([props.modelValue])[0]?.name || ''; + } + return ''; + }); + // 是否可清空 + const mergeClearable = computed<boolean>(() => { + return !props.disabled && props.allowClear && inputValue.value.length > 0; + }); + + function valueChange(item: OptionObjectItem, index: number) { + const { multiple, optionDisabledKey: disabledKey } = props; + let { modelValue } = props; + if (disabledKey && !!item[disabledKey]) return; + if (multiple) { + item._checked = !item._checked; + modelValue = mergeOptions.value + .filter((item) => item._checked) + .map((item) => item.value); + ctx.emit('update:modelValue', modelValue); + } else { + ctx.emit('update:modelValue', item.value); + toggleChange(false); + } + ctx.emit('valueChange', item, index); + } + + function getItemClassName(item: OptionObjectItem) { + const { optionDisabledKey: disabledKey } = props; + return className('devui-select-item', { + active: item.value === props.modelValue, + disabled: disabledKey ? !!item[disabledKey] : false, + }); + } + + function handleClear(e: MouseEvent) { + e.preventDefault(); + e.stopPropagation(); + if (props.multiple) { + ctx.emit('update:modelValue', []); + } else { + ctx.emit('update:modelValue', ''); + } + } + + return { + isOpen, + containerRef, + dropdownRef, + inputValue, + mergeOptions, + mergeClearable, + valueChange, + toggleChange, + getItemClassName, + handleClear, + }; + }, + render() { + const { + mergeOptions, + isOpen, + inputValue, + size, + multiple, + disabled, + optionDisabledKey: disabledKey, + placeholder, + overview, + valueChange, + toggleChange, + getItemClassName, + mergeClearable, + handleClear, + } = this; + + const selectCls = className('devui-select', { + 'devui-select-open': isOpen, + 'devui-dropdown-menu-multiple': multiple, + 'devui-select-lg': size === 'lg', + 'devui-select-sm': size === 'sm', + 'devui-select-underlined': overview === 'underlined', + 'devui-select-disabled': disabled, + }); + + const inputCls = className('devui-select-input', { + 'devui-select-input-lg': size === 'lg', + 'devui-select-input-sm': size === 'sm', + }); + + const selectionCls = className('devui-select-selection', { + 'devui-select-clearable': mergeClearable, + }); + + return ( + <div class={selectCls} ref="containerRef"> + <div class={selectionCls} onClick={() => toggleChange(!isOpen)}> + <input + value={inputValue} + type="text" + class={inputCls} + placeholder={placeholder} + readonly + disabled={disabled} + /> + <span onClick={handleClear} class="devui-select-clear"> + <Icon name="close" /> + </span> + <span class="devui-select-arrow"> + <Icon name="select-arrow" /> + </span> + </div> + <Transition name="fade" ref="dropdownRef"> + <div v-show={isOpen} class="devui-select-dropdown"> + <ul class="devui-select-dropdown-list devui-scrollbar"> + {mergeOptions.map((item, i) => ( + <li + onClick={(e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + valueChange(item, i); + }} + class={getItemClassName(item)} + key={i} + > + {multiple ? ( + <Checkbox + modelValue={item._checked} + label={item.name} + disabled={disabledKey ? !!item[disabledKey] : false} + /> + ) : ( + item.name + )} + </li> + ))} + </ul> + </div> + </Transition> + </div> + ); + }, +}); diff --git a/packages/devui-vue/devui/select/src/use-select.ts b/packages/devui-vue/devui/select/src/use-select.ts new file mode 100644 index 0000000000000000000000000000000000000000..a796cab82a9838f58b9fd49dad74b8f6b516cad3 --- /dev/null +++ b/packages/devui-vue/devui/select/src/use-select.ts @@ -0,0 +1,69 @@ +import { PropType, ExtractPropTypes } from 'vue'; + +export interface OptionObjectItem { + name: string + value: string | number + _checked: boolean + [key: string]: any +} + +export type OptionItem = + | number + | string + | ({ value: string | number; } & Partial<OptionObjectItem>); +export type Options = Array<OptionItem>; + +export type ModelValue = number | string | Array<number | string>; + +export const selectProps = { + modelValue: { + type: [String, Number, Array] as PropType<ModelValue>, + default: '', + }, + 'onUpdate:modelValue': { + type: Function as PropType<(val: ModelValue) => void>, + default: undefined, + }, + options: { + type: Array as PropType<Options>, + default: () => [], + }, + size: { + type: String as PropType<'sm' | 'md' | 'lg'>, + default: 'md', + }, + overview: { + type: String as PropType<'border' | 'underlined'>, + default: 'border', + }, + placeholder: { + type: String, + default: '请选择', + }, + multiple: { + type: Boolean, + default: false, + }, + disabled: { + type: Boolean, + default: false + }, + allowClear: { + type: Boolean, + default: false + }, + optionDisabledKey: { + type: String, + default: '' + }, + onToggleChange: { + type: Function as PropType<(bool: boolean) => void>, + default: undefined, + }, + onValueChange: { + type: Function as PropType<(item: OptionItem, index: number) => void>, + default: undefined, + }, +} as const; + +export type SelectProps = ExtractPropTypes<typeof selectProps>; diff --git a/packages/devui-vue/devui/select/src/utils.ts b/packages/devui-vue/devui/select/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..1bab126858801e0c3372f6cd5ac7eb437ebebb26 --- /dev/null +++ b/packages/devui-vue/devui/select/src/utils.ts @@ -0,0 +1,21 @@ +/** + * 动态获取class字符串 + * @param classStr 是一个字符串,固定的class名 + * @param classOpt 是一个对象,key表示class名,value为布尔值,true则添加,否则不添加 + * @returns 最终的class字符串 + */ +export function className( + classStr: string, + classOpt?: { [key: string]: boolean; } +): string { + let classname = classStr; + if (typeof classOpt === 'object') { + Object.keys(classOpt).forEach((key) => { + classOpt[key] && (classname += ` ${key}`); + }); + } + + return classname; +} + +export type KeyType<T, K extends keyof T> = T[K] diff --git a/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.tsx b/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a1076a67dff32294f5d4cdbce9efeb7dab6b9339 --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.tsx @@ -0,0 +1,39 @@ +import { defineComponent } from 'vue' +import { apiTableProps, ITableColumn, ITableDataRow } from './devui-api-table.type' + +export default defineComponent({ + name: 'DevuiApiTable', + props: apiTableProps, + render() { + const { columns, data } = this + + const renderTd = (params: { col: ITableColumn; row: ITableDataRow; }) => { + const { col, row } = params + + const value = row[col.key] + + if ('type' in col) { + return <a href={`#${value}`}>{value}</a> + } + + return value + } + + return ( + <table> + <thead> + {columns.map((col) => ( + <th>{col.title}</th> + ))} + </thead> + {data.map((row) => ( + <tr> + {columns.map((col) => ( + <td>{renderTd({ col, row })}</td> + ))} + </tr> + ))} + </table> + ) + } +}) diff --git a/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.type.ts b/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..359f59df2bc155d009f895c10bad5aa9089d534e --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-api-table/devui-api-table.type.ts @@ -0,0 +1,23 @@ +import type { ExtractPropTypes, PropType } from 'vue' + +export type ITableColumn = { + key: string + title: string + type?: 'turn' +} + +export type ITableDataRow = Record<string, any> + +export const apiTableProps = { + columns: { + type: Array as PropType<ITableColumn[]>, + required: true, + default: () => [] + }, + data: { + type: Array as PropType<ITableDataRow[]>, + default: () => [] + } +} as const + +export type ApiTableProps = ExtractPropTypes<typeof apiTableProps> diff --git a/packages/devui-vue/devui/shared/devui-api-table/index.ts b/packages/devui-vue/devui/shared/devui-api-table/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb6d8d0b45dc852cf1d8399881ee635fb21327cb --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-api-table/index.ts @@ -0,0 +1 @@ +export { default } from './devui-api-table' diff --git a/devui/shared/devui-api/devui-api.tsx b/packages/devui-vue/devui/shared/devui-api/devui-api.tsx similarity index 94% rename from devui/shared/devui-api/devui-api.tsx rename to packages/devui-vue/devui/shared/devui-api/devui-api.tsx index 85749b0dc2a57fdaccfedf4e2ec60beba33e6f72..8bb1359b07420f7bb28bae939ee06dfff3c7fd44 100644 --- a/devui/shared/devui-api/devui-api.tsx +++ b/packages/devui-vue/devui/shared/devui-api/devui-api.tsx @@ -2,7 +2,7 @@ import { defineComponent } from 'vue' import { useRoute } from 'vue-router' export default defineComponent({ - name: 'd-api', + name: 'DApi', props: { }, setup(props, ctx) { diff --git a/devui/shared/devui-codebox/codebox-collapse-icon.tsx b/packages/devui-vue/devui/shared/devui-codebox/codebox-collapse-icon.tsx similarity index 100% rename from devui/shared/devui-codebox/codebox-collapse-icon.tsx rename to packages/devui-vue/devui/shared/devui-codebox/codebox-collapse-icon.tsx diff --git a/devui/shared/devui-codebox/codebox-copied-icon.tsx b/packages/devui-vue/devui/shared/devui-codebox/codebox-copied-icon.tsx similarity index 100% rename from devui/shared/devui-codebox/codebox-copied-icon.tsx rename to packages/devui-vue/devui/shared/devui-codebox/codebox-copied-icon.tsx diff --git a/devui/shared/devui-codebox/codebox-copy-icon.tsx b/packages/devui-vue/devui/shared/devui-codebox/codebox-copy-icon.tsx similarity index 100% rename from devui/shared/devui-codebox/codebox-copy-icon.tsx rename to packages/devui-vue/devui/shared/devui-codebox/codebox-copy-icon.tsx diff --git a/packages/devui-vue/devui/shared/devui-codebox/devui-codebox.scss b/packages/devui-vue/devui/shared/devui-codebox/devui-codebox.scss new file mode 100644 index 0000000000000000000000000000000000000000..757b8db57eb00e84583b204a4ee998076898d909 --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-codebox/devui-codebox.scss @@ -0,0 +1,151 @@ +@import '../../style/theme/color'; +@import '../../style/core/font'; + +.code-box { + border: 1px solid $devui-line; + border-radius: 4px; + display: inline-block; + width: 100%; + position: relative; + margin: 4px 0; + transition: all 0.2s; +} + +.devui-code-copy { + fill: $devui-text; +} + +.code-box-demo { + border-bottom: 1px solid $devui-dividing-line; + padding: 42px 20px 50px; +} + +.code-box-meta.markdown { + position: relative; + padding: 10px 40px; + border-radius: 0 0 4px 4px; + transition: background-color 0.4s; + width: 100%; + font-size: $devui-font-size; + margin-bottom: 0; + overflow-x: unset; +} + +.code-box.expand .code-box-meta { + border-radius: 0; + border-bottom: 1px dashed $devui-dividing-line; +} + +.code-box-title { + position: absolute; + top: -14px; + padding: 1px 8px; + color: #777777; + border-radius: 4px 4px 0 0; + background: $devui-base-bg; + transition: background-color 0.4s; +} + +.code-box-title > a { + color: rgba(0, 0, 0, 0.65); + font-size: $devui-font-size-card-title; + font-weight: 500; + text-decoration: none; +} + +.code-box .collapse { + display: block; /* .collapse conflick with bootstrap */ + position: absolute; + left: 15px; + // background: $devui-block; + top: -9px; + cursor: pointer; + width: 16px; + height: 16px; + line-height: 16px; + opacity: 0.55; + text-align: center; + transition: all 0.3s; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + & > svg > path { + fill: $devui-text; + } +} + +.dark-mode .code-box .collapse { + opacity: 1; +} + +.code-box .highlight-wrapper { + display: none; + overflow: auto; + border-radius: 0 0 4px 4px; +} + +.code-box .highlight-wrapper-expand { + display: block; +} + +.code-box .highlight { + padding: 5px; + position: relative; +} + +.code-box-actions { + position: absolute; + top: 10px; + right: 12px; + text-align: right; + cursor: pointer; +} + +.code-box-code-copy:hover { + color: #108ee9; + -webkit-transform: scale(1.2); + transform: scale(1.2); +} + +.code-box-code-copy { + font-size: $devui-font-size-card-title; + cursor: pointer; + color: #222222; + transition: all 0.24s; + background: $devui-base-bg; + width: 20px; + height: 20px; + line-height: 20px; + text-align: center; + border-radius: 20px; + opacity: 0; +} + +.code-box .highlight pre { + margin: 0; + padding: 0; +} + +.code-box pre { + margin: 0; + width: auto; + border: none; + margin-top: 10px; +} + +.code-box pre code { + border: none; +} + +.highlight-wrapper:hover .code-box-code-copy, +.highlight-wrapper:hover .code-box-codepen, +.highlight-wrapper:hover .code-box-riddle { + opacity: 0.66; +} + +.code-box.expand .collapse { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} diff --git a/devui/shared/devui-codebox/devui-codebox.tsx b/packages/devui-vue/devui/shared/devui-codebox/devui-codebox.tsx similarity index 95% rename from devui/shared/devui-codebox/devui-codebox.tsx rename to packages/devui-vue/devui/shared/devui-codebox/devui-codebox.tsx index 5eee21660c35c932da3c9d1763c523d2267d5fff..99237fbdd1859b8ac803b7ead68c5f99bcdd1d0d 100644 --- a/devui/shared/devui-codebox/devui-codebox.tsx +++ b/packages/devui-vue/devui/shared/devui-codebox/devui-codebox.tsx @@ -22,7 +22,7 @@ export default defineComponent({ const sourceData = props.sourceData; const expanded = ref(false); const _copied = ref(false); - let codeTabID = 'TSX'; + let codeTabID = ref('TSX'); let componentCode: Array<any>; const toggleCode = () => { @@ -75,11 +75,10 @@ export default defineComponent({ </section> <section class={{ 'highlight-wrapper': true, 'highlight-wrapper-expand': expanded.value }}> <div style="padding: 0 20px"> - {/* TODO: 待完善tabs */} - <DevuiTabs> + <DevuiTabs v-model={codeTabID.value}> {sourceData.map(item => { return ( - <DevuiTab> + <DevuiTab title={item.title} id={item.title}> <div class="highlight"> <div class="code-box-actions"> <span onClick={() => copyCode(item.code.default || item.code)}> diff --git a/devui/shared/devui-codebox/devui-source-data.ts b/packages/devui-vue/devui/shared/devui-codebox/devui-source-data.ts similarity index 54% rename from devui/shared/devui-codebox/devui-source-data.ts rename to packages/devui-vue/devui/shared/devui-codebox/devui-source-data.ts index 223b7a4c04b7aca87f770daeabb0f61288e7a41c..c243bf23590143e8947785e190ca0d45f712e926 100644 --- a/devui/shared/devui-codebox/devui-source-data.ts +++ b/packages/devui-vue/devui/shared/devui-codebox/devui-source-data.ts @@ -1,5 +1,5 @@ export interface DevuiSourceData { - title?: string; - language?: string; + title?: string + language?: string code?: any } \ No newline at end of file diff --git a/packages/devui-vue/devui/shared/devui-directive/clickoutside.ts b/packages/devui-vue/devui/shared/devui-directive/clickoutside.ts new file mode 100644 index 0000000000000000000000000000000000000000..18be40209900771d9e34b0db2d397f6654b2a1ca --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-directive/clickoutside.ts @@ -0,0 +1,69 @@ +/** + * v-clickoutside + * @desc 点击元素外面才会触发的事件 + * @example + * <div v-clickoutside="handleClose"> + */ + +import { inBrowser } from '../util/common-var' +import { on } from './utils' + +const ctx = Symbol('@@clickoutside') +const nodeList = new Map() + +let startClick +let nid = 0 +let isFirst = true; + +function createDocumentHandler(el: HTMLElement, binding: Record<string, any>, vnode: any) { + if (inBrowser && isFirst) { + isFirst = false; + on(document, 'mousedown', (e: Event) => { + startClick = e + }) + on(document, 'mouseup', (e: Event) => { + for (const [id, node] of nodeList) { + node[ctx].documentHandler(e, startClick) + } + }) + } + + return function(mouseup: Event, mousedown: Event) { + if ( + !vnode || + !binding.instance || + !mouseup.target || + !mousedown.target || + el.contains(mouseup.target as HTMLElement) || + el.contains(mousedown.target as HTMLElement) || + el === mouseup.target + ) { + return; + } + el[ctx].bindingFn && el[ctx].bindingFn() + } +} + +const clickoutsideDirective = { + beforeMount: function (el: HTMLElement, binding: Record<string, any>, vnode: any) { + nid++ + nodeList.set(nid, el) + el[ctx] = { + nid, + documentHandler: createDocumentHandler(el, binding, vnode), + bindingFn: binding.value + } + }, + + updated: function (el: HTMLElement, binding: Record<string, any>, vnode: any) { + el[ctx].documentHandler = createDocumentHandler(el, binding, vnode) + el[ctx].bindingFn = binding.value + }, + + unmounted: function (el: HTMLElement) { + nodeList.delete(el[ctx].nid) + delete el[ctx] + } +} + +export default clickoutsideDirective diff --git a/packages/devui-vue/devui/shared/devui-directive/utils.ts b/packages/devui-vue/devui/shared/devui-directive/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..5af8184df16fafd29d3eb72fd621594c2892a6b4 --- /dev/null +++ b/packages/devui-vue/devui/shared/devui-directive/utils.ts @@ -0,0 +1,23 @@ +// 事件处理 +export function on(element: HTMLElement | Document, eventName: string, handler: (this: Element, ev: Event) => any): void { + if (document.addEventListener) { + if (element && eventName && handler) { + element.addEventListener(eventName, handler, false) + } + } else { + if (element && eventName && handler) { + (element as any).attachEvent('on' + eventName, handler) + } + } +} +export function off(element: HTMLElement | Document, eventName: string, handler: (this: Element, ev: Event) => any): void { + if (document.removeEventListener) { + if (element && eventName && handler) { + element.removeEventListener(eventName, handler, false) + } + } else { + if (element && eventName && handler) { + (element as any).detachEvent('on' + eventName, handler) + } + } +} \ No newline at end of file diff --git a/devui/shared/devui-highlight/devui-highlight.tsx b/packages/devui-vue/devui/shared/devui-highlight/devui-highlight.tsx similarity index 94% rename from devui/shared/devui-highlight/devui-highlight.tsx rename to packages/devui-vue/devui/shared/devui-highlight/devui-highlight.tsx index f87ca9cf5dd50ecb3ffe6286f3289220c2689641..23ba77bebf0dfb907726c7c3695f1ec6d58694cd 100644 --- a/devui/shared/devui-highlight/devui-highlight.tsx +++ b/packages/devui-vue/devui/shared/devui-highlight/devui-highlight.tsx @@ -1,7 +1,7 @@ import { defineComponent } from 'vue' export default defineComponent({ - name: 'd-highlight', + name: 'DHighlight', props: { code: String, language: String diff --git a/packages/devui-vue/devui/shared/hooks/use-demo.tsx b/packages/devui-vue/devui/shared/hooks/use-demo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..13e094c31b190f617661b18b4424e91effe31f52 --- /dev/null +++ b/packages/devui-vue/devui/shared/hooks/use-demo.tsx @@ -0,0 +1,35 @@ +import CodeBox from '../devui-codebox/devui-codebox'; + +interface ExampleItem { + id: `${string}-${string}` + title: string + text?: string + code: string + content: JSX.Element +} + +export function useDemo (exampleList: ExampleItem[]): JSX.Element { + const resList = exampleList.map(item => { + const sourceData = [{ + title: 'TSX', + language: 'TSX', + code: item.code + }]; + + return ( + <div class="demo-example"> + <div class="demo-title" id={item.id}>{ item.title }</div> + <div class="demo-text">{ item.text }</div> + <CodeBox sourceData={sourceData}> + { item.content } + </CodeBox> + </div> + ); + }); + + return ( + <div class="demo-container"> + { resList } + </div> + ); +} diff --git a/packages/devui-vue/devui/shared/scripts/component.ts b/packages/devui-vue/devui/shared/scripts/component.ts new file mode 100644 index 0000000000000000000000000000000000000000..090fd7a3ca33f935c78595181eb4583277137fbf --- /dev/null +++ b/packages/devui-vue/devui/shared/scripts/component.ts @@ -0,0 +1,24 @@ +import { h, render } from 'vue' + +const COMPONENT_CONTAINER_SYMBOL = Symbol('dev_component_container') + +/** + * 创建组件实例对象 + * 返回的实例和调用 getCurrentComponent() 返回的一致 + * @param {*} Component + */ +export function createComponent(Component: any, props: any, children: any = null) { + const vnode: any = h(Component, { ...props }, children) + const container = document.createElement('div') + vnode[COMPONENT_CONTAINER_SYMBOL] = container + render(vnode, container) + return vnode.component +} + +/** + * 销毁组件实例对象 + * @param {*} ComponnetInstance 通过createComponent方法得到的组件实例对象 + */ +export function unmountComponent(ComponnetInstance: any) { + render(null, ComponnetInstance?.vnode[COMPONENT_CONTAINER_SYMBOL]) +} diff --git a/packages/devui-vue/devui/shared/util/class.ts b/packages/devui-vue/devui/shared/util/class.ts new file mode 100644 index 0000000000000000000000000000000000000000..046f6ce669bdd1fb103f41f94fa88a47a854be9e --- /dev/null +++ b/packages/devui-vue/devui/shared/util/class.ts @@ -0,0 +1,44 @@ +/** + * 判断 DOM 中的元素是否含有某个类 + * @param el 元素 + * @param className 类名 + * @returns + */ +export function hasClass(el: HTMLElement, className: string): boolean { + if (el.classList) { + return el.classList.contains(className); + } + const originClass = el.className; + return ` ${originClass} `.indexOf(` ${className} `) > -1; +} + +/** + * 向 DOM 中的元素添加一个类 + * @param el 元素 + * @param className 类名 + */ +export function addClass(el: HTMLElement, className: string): void { + if (el.classList) { + el.classList.add(className); + } else { + if (!hasClass(el, className)) { + el.className = `${el.className} ${className}`; + } + } +} + +/** + * 从 DOM 中的元素移除一个类 + * @param el 元素 + * @param className 类名 + */ +export function removeClass(el: HTMLElement, className: string): void { + if (el.classList) { + el.classList.remove(className); + } else { + if (hasClass(el, className)) { + const originClass = el.className; + el.className = ` ${originClass} `.replace(` ${className} `, ' '); + } + } +} diff --git a/packages/devui-vue/devui/shared/util/common-var.ts b/packages/devui-vue/devui/shared/util/common-var.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8ba4f7e34c274e4f0ebaf7b61b9ff990f7ee093 --- /dev/null +++ b/packages/devui-vue/devui/shared/util/common-var.ts @@ -0,0 +1 @@ +export const inBrowser = typeof window !== 'undefined'; \ No newline at end of file diff --git a/packages/devui-vue/devui/shared/util/debounce.ts b/packages/devui-vue/devui/shared/util/debounce.ts new file mode 100644 index 0000000000000000000000000000000000000000..b76b9c7951b4076431b321637c2eb5de430db57f --- /dev/null +++ b/packages/devui-vue/devui/shared/util/debounce.ts @@ -0,0 +1,25 @@ +/** + * + * @param func The function to debounce. + * @param wait The number of milliseconds to delay. + * @param immediate Whether to execute immediately + * @returns Returns the new debounced function. + */ +export function debounce<A extends Array<any>, R = void>(func: (...args: A) => R, wait: number, immediate: boolean): (...args: A) => R { + let timer: number, result: R; + return function (...args: A) { + if (timer) clearTimeout(timer) + if (immediate) { + const localImmediate = !timer + timer = window.setTimeout(() => { + timer = null + }, wait); + if (localImmediate) result = func.apply(this, args) + } else { + timer = window.setTimeout(() => { + func.apply(this, args) + }, wait); + } + return result + } +} diff --git a/packages/devui-vue/devui/shared/util/dom.ts b/packages/devui-vue/devui/shared/util/dom.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2cb9566889c4cd5613a7b3001ee216343c6da26 --- /dev/null +++ b/packages/devui-vue/devui/shared/util/dom.ts @@ -0,0 +1,31 @@ +import { ComponentPublicInstance } from "@vue/runtime-core"; + +/** + * + * @param {any} origin + * @returns + */ +export function isComponent(target: any): target is ComponentPublicInstance { + return !!(target?.$el); +} + +/** + * 提取 Vue Intance 中的元素,如果本身就是元素,直接返回。 + * @param {any} element + * @returns {Element | null} + */ +export function getElement( + element: Element | ComponentPublicInstance | null +): Element | null { + if (element instanceof Element) { + return element; + } + if ( + element && + typeof element === 'object' && + element.$el instanceof Element + ) { + return element.$el; + } + return null; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/shared/util/props-util.ts b/packages/devui-vue/devui/shared/util/props-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..9411ed4d2e62d09762b63e19f720c9546ef9fe3c --- /dev/null +++ b/packages/devui-vue/devui/shared/util/props-util.ts @@ -0,0 +1,8 @@ +import type { Slots, VNode } from 'vue' +export function getPropsSlot( + slots: Slots, + props: unknown, + prop = 'default' +): VNode | string | undefined { + return props[prop] ?? slots[prop]?.() +} diff --git a/packages/devui-vue/devui/shared/util/set-style.ts b/packages/devui-vue/devui/shared/util/set-style.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ce5065bc54f92085bf349b504be3c41cfa29b1c --- /dev/null +++ b/packages/devui-vue/devui/shared/util/set-style.ts @@ -0,0 +1,26 @@ +import type { CSSProperties } from 'vue'; + +/** + * 设置元素的样式,返回上一次的样式 + * @param element + * @param style + * @returns + */ +export function setStyle( + element: HTMLElement, + style: CSSProperties, +): CSSProperties { + const oldStyle: CSSProperties = {}; + + const styleKeys = Object.keys(style); + + styleKeys.forEach((key) => { + oldStyle[key] = element.style[key]; + }); + + styleKeys.forEach((key) => { + element.style[key] = style[key]; + }); + + return oldStyle; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/skeleton/__tests__/skeleton.spec.ts b/packages/devui-vue/devui/skeleton/__tests__/skeleton.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5f905040d816a9c77a294a3908affc2d64accbe --- /dev/null +++ b/packages/devui-vue/devui/skeleton/__tests__/skeleton.spec.ts @@ -0,0 +1,81 @@ +import { mount } from '@vue/test-utils'; +import { ref } from 'vue'; +import DSkeleton from '../src/skeleton'; + +describe('skeleton 组件', () => { + it('render basic skeleton', () => { + const row = ref(4) + const wrapper = mount({ + components: { DSkeleton }, + template: `<d-skeleton :row="row" />`, + setup() { + return { + row + } + }, + }) + + expect(wrapper.classes()).toContain('devui-skeleton') + expect(wrapper.classes()).toContain('devui-skeleton-animated') + expect(wrapper.element.childElementCount).toBe(2) + expect(wrapper.element.children[1].children[1].childElementCount).toBe(4) + }) + + it('render skeleton without animate', () => { + const animate = ref(false) + const wrapper = mount({ + components: { DSkeleton }, + template: `<d-skeleton :animate="animate" />`, + setup() { + return { + animate + } + }, + }) + + expect(wrapper.classes()).toEqual(['devui-skeleton']) + }) + + it('render skeleton without title and paragraph', () => { + const title = ref(false) + const paragraph = ref(false) + const wrapper = mount({ + components: { DSkeleton }, + template: `<d-skeleton :title="title" :paragraph="paragraph" />`, + setup() { + return { + title, + paragraph + } + }, + }) + + expect(wrapper.element.children[1].childElementCount).toBe(2) + }) + + it('hide skeleton and show real content', () => { + const row = ref(4) + const loading = ref(false) + const wrapper = mount({ + components: { DSkeleton }, + template: ` + <d-skeleton :row="4" :loading="loading"> + <div> + <div>content1</div> + <div>content2</div> + <div>content3</div> + <div>content4</div> + </div> + </d-skeleton>`, + setup() { + return { + row, + loading + } + }, + }) + + expect(wrapper.classes()).toContain('devui-skeleton') + expect(wrapper.element.children[0].innerHTML).toBe('<div>content1</div><div>content2</div><div>content3</div><div>content4</div>') + }) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/skeleton/index.ts b/packages/devui-vue/devui/skeleton/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6bb2132be868bfb012143b3d03069b3352fbf120 --- /dev/null +++ b/packages/devui-vue/devui/skeleton/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Skeleton from './src/skeleton' + +Skeleton.install = function(app: App): void { + app.component(Skeleton.name, Skeleton) +} + +export { Skeleton } + +export default { + title: 'Skeleton 骨架屏', + category: '数据展示', + status: '已完成', + install(app: App): void { + app.use(Skeleton as any) + } +} diff --git a/packages/devui-vue/devui/skeleton/src/skeleton-types.ts b/packages/devui-vue/devui/skeleton/src/skeleton-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5e0bae4944efe9a0708697d68f8541a20f17163 --- /dev/null +++ b/packages/devui-vue/devui/skeleton/src/skeleton-types.ts @@ -0,0 +1,52 @@ +import type { ExtractPropTypes, PropType } from 'vue' + +export type ModelValue = number | string + +export const skeletonProps = { + row: { + type: Number, + default: 0 + }, + animate: { + type: Boolean, + default: true + }, + round: { + type: Boolean, + default: false + }, + loading: { + type: Boolean, + default: true + }, + avatar: { + type: Boolean, + default: false + }, + title: { + type: Boolean, + default: true + }, + paragraph: { + type: Boolean, + default: true + }, + avatarSize: { + type: [String, Number] as PropType<ModelValue>, + default: '40px' + }, + avatarShape: { + value: String as PropType<'round' | 'square'>, + default: 'round' + }, + titleWidth: { + type: [String, Number] as PropType<ModelValue>, + default: '40%' + }, + rowWidth: { + type: [Number, String, Array] as PropType<number | string | Array<number | string>>, + default: ['100%'] + } +} as const + +export type SkeletonProps = ExtractPropTypes<typeof skeletonProps> diff --git a/packages/devui-vue/devui/skeleton/src/skeleton.scss b/packages/devui-vue/devui/skeleton/src/skeleton.scss new file mode 100644 index 0000000000000000000000000000000000000000..39c952314389e0878e7d1f06226122f5a9068c7e --- /dev/null +++ b/packages/devui-vue/devui/skeleton/src/skeleton.scss @@ -0,0 +1,73 @@ +@import '../../styles-var/devui-var.scss'; + +.devui-skeleton { + display: flex; + justify-content: space-between; + + .devui-skeleton__avatar { + display: flex; + flex: 1; + justify-content: center; + padding-right: 16px; + + .avatar { + width: 40px; + height: 40px; + background-color: #f2f2f2; + } + } + + .devui-skeleton__item__group { + flex: 11; + + .devui-skeleton__item, + .devui-skeleton__title { + width: 100%; + height: 16px; + background-color: #f2f2f2; + } + + .devui-skeleton__title { + margin-top: 24px; + } + + .devui-skeleton__paragraph { + margin-top: 12px; + } + + .devui-skeleton__item:last-child { + width: 60%; + } + } +} + +.devui-skeleton-animated > .devui-skeleton__item__group > .devui-skeleton__title, +.devui-skeleton-animated > .devui-skeleton__avatar > .avatar, +.devui-skeleton-animated > .devui-skeleton__item__group > div > .devui-skeleton__item { + @keyframes skeletonLoading { + to { + background-position-x: -20%; + } + } + + background: + linear-gradient( + 100deg, + rgba(255, 255, 255, 0) 40%, + rgba(255, 255, 255, 0.5) 50%, + rgba(255, 255, 255, 0) 60% + ) + #f2f2f2; + background-size: 200% 100%; + background-position-x: 180%; + animation: 2s skeletonLoading ease-in-out infinite; +} + +.devui-skeleton__avatar > .avatar, +.devui-skeleton__item__group > div > .devui-skeleton__item { + margin-top: 12px; +} + +.devui-skeleton-animated > .devui-skeleton__avatar > .avatar { + animation-delay: 0.1s; +} diff --git a/packages/devui-vue/devui/skeleton/src/skeleton.tsx b/packages/devui-vue/devui/skeleton/src/skeleton.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0aad34479eb64e9b13c315fe5f4fbffc53355115 --- /dev/null +++ b/packages/devui-vue/devui/skeleton/src/skeleton.tsx @@ -0,0 +1,111 @@ +import './skeleton.scss' + +import { defineComponent } from 'vue' +import { skeletonProps, SkeletonProps } from './skeleton-types' + +export default defineComponent({ + name: 'DSkeleton', + props: skeletonProps, + setup(props: SkeletonProps, ctx) { + const { slots } = ctx; + + function renderAnimate(isAnimated) { + return isAnimated ? 'devui-skeleton-animated' : '' + } + function renderBorderRadius(isRound) { + return isRound ? 'border-radius: 1em;' : '' + } + function renderParagraph(isShown, rowNum, rowWidth, round) { + const arr = [] + + function pushIntoArray(type) { + for (let index = 0; index < rowNum; index++) { + arr.push({ width: type }) + } + } + (function handleRowWidth() { + if (rowWidth instanceof Array) { + for (let index = 0; index < rowNum; index++) { + if (rowWidth[index]) { + switch (typeof rowWidth[index]) { + case 'string': + arr.push({ width: rowWidth[index] }) + break + case 'number': + arr.push({ width: `${rowWidth[index]}px` }) + } + } else { + arr.push({ width: 1 }) + } + } + } else { + switch (typeof rowWidth) { + case 'string': + pushIntoArray(rowWidth) + break + case 'number': + pushIntoArray(`${rowWidth}px`) + break + } + } + })() + + return <div class="devui-skeleton__paragraph" v-show={isShown}>{ + arr.map(item => { + return <div class="devui-skeleton__item" style={round ? 'border-radius: 1em;' : '' + `width: ${item.width}`} /> + }) + }</div> + } + function renderAvatarStyle(avatarSize, avatarShape) { + function renderAvatarSize(avatarSize) { + switch (typeof avatarSize) { + case 'string': + return `width:${avatarSize};height:${avatarSize};` + case 'number': + return `width:${avatarSize}px;height:${avatarSize}px;` + } + } + function renderAvatarShape(avatarShape) { + return avatarShape === 'square' ? '' : 'border-radius:50%;' + } + + return (renderAvatarSize(avatarSize) + renderAvatarShape(avatarShape)) + } + function renderTitle(isVisible, titleWidth, isRound) { + function renderTitleWidth(titleWidth) { + switch (typeof titleWidth) { + case 'string': + return `width: ${titleWidth};` + case 'number': + return `width: ${titleWidth}px;` + } + } + function renderTitleVisibility(isVisible) { + return isVisible ? null : 'visibility: hidden;' + } + + return (renderTitleWidth(titleWidth) + renderBorderRadius(isRound) + renderTitleVisibility(isVisible)) + } + function renderSkeleton(isLoading) { + if (isLoading) { + return <> + <div class="devui-skeleton__avatar" v-show={props.avatar}> + <div class="avatar" style={renderAvatarStyle(props.avatarSize, props.avatarShape)} /> + </div> + <div class="devui-skeleton__item__group"> + <div class="devui-skeleton__title" style={renderTitle(props.title, props.titleWidth, props.round)} /> + {renderParagraph(props.paragraph, props.row, props.rowWidth, props.round)} + </div> + </> + } + + return <>{slots.default?.()}</> + } + + return () => { + return <div class={`devui-skeleton ${renderAnimate(props.animate)}`}> + {renderSkeleton(props.loading)} + </div> + } + } +}) diff --git a/packages/devui-vue/devui/slider/__tests__/slider.spec.ts b/packages/devui-vue/devui/slider/__tests__/slider.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..146a319fc1aa214826bf92ea70ecb37621306b74 --- /dev/null +++ b/packages/devui-vue/devui/slider/__tests__/slider.spec.ts @@ -0,0 +1,56 @@ +import { mount } from '@vue/test-utils'; +import { nextTick, ref } from 'vue'; +import DSlider from '../src/slider'; + +describe('d-slider', () => { + it('slider maxValue && minValue work', () => { + const wrapper = mount(DSlider, { + props: { + max: 50, + min: 2, + }, + }); + const max = wrapper.find('.devui-max_count'); + const min = wrapper.find('.devui-min_count'); + expect(min.text()).toBe('2'); + expect(max.text()).toBe('50'); + }); + it('slider v-model work', async () => { + const value = ref(5); + const wrapper = mount({ + components: { DSlider }, + template: ` + <d-slider v-model:modelValue="modelValue" showInput /> + `, + setup() { + return { + modelValue: value, + }; + }, + }); + const input = wrapper.find('input'); + expect(input.element.value).toBe('5'); + input.setValue(10); + await nextTick(); + expect(value.value).toBe(10); + }); + it('slider showInput work', () => { + const wrapper = mount(DSlider, { + props: { + showInput: true, + }, + }); + const dInput = wrapper.find('.devui-input__out-wrap'); + expect(dInput.exists()).toBeTruthy(); + }); + + it('slider disabled work', () => { + const wrapper = mount(DSlider, { + props: { + disabled: true, + }, + }); + const slider = wrapper.find('.devui-slider__runway'); + expect(slider.classes()).toContain('disabled'); + }); +}); diff --git a/packages/devui-vue/devui/slider/index.ts b/packages/devui-vue/devui/slider/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4596b7734eec02a4e6729d10d96a3013edc3f4b --- /dev/null +++ b/packages/devui-vue/devui/slider/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Slider from './src/slider' + +Slider.install = function(app: App): void { + app.component(Slider.name, Slider) +} + +export { Slider } + +export default { + title: 'Slider 滑块', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(Slider as any) + } +} diff --git a/packages/devui-vue/devui/slider/src/slider-types.ts b/packages/devui-vue/devui/slider/src/slider-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..603897f3717d50c13301bf852b243cdd69b4078d --- /dev/null +++ b/packages/devui-vue/devui/slider/src/slider-types.ts @@ -0,0 +1,32 @@ +import type { ExtractPropTypes } from 'vue'; +export const sliderProps = { + disabled: { + type: Boolean, + default: false, + }, + max: { + type: Number, + default: 100, + }, + min: { + type: Number, + default: 0, + }, + modelValue: { + type: Number, + default: 0, + }, + showInput: { + type: Boolean, + default: false, + }, + step: { + type: Number, + default: 1, + }, + tipsRenderer:{ + type: String, + default: '', + } +} as const; +export type SliderProps = ExtractPropTypes<typeof sliderProps>; diff --git a/packages/devui-vue/devui/slider/src/slider.scss b/packages/devui-vue/devui/slider/src/slider.scss new file mode 100644 index 0000000000000000000000000000000000000000..ac66b0a21b20200ff034d947a4c7f8bf7a0b9621 --- /dev/null +++ b/packages/devui-vue/devui/slider/src/slider.scss @@ -0,0 +1,135 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/theme/font'; + +.devui-slider { + position: relative; + width: 90%; + display: block; + + &.disabled { + cursor: not-allowed; + background-color: $devui-disabled-line; + border-color: $devui-disabled-line; + } + + &__runway { + position: relative; + width: 100%; + padding: 4px 0; + margin: 4px 0; + cursor: pointer; + box-sizing: border-box; + height: 5px; + display: flex; + align-items: center; + background-color: $devui-default-bg; + + &.disabled { + cursor: not-allowed; + } + + .devui-slider__bar { + height: 6px; + background-color: $devui-default-line; + border-top-left-radius: $devui-border-radius; + border-bottom-left-radius: $devui-border-radius; + position: absolute; + + &.disabled { + background-color: $devui-disabled-line; + border-color: $devui-disabled-line; + } + + &.disabled:hover { + cursor: not-allowed; + } + } + + .devui-slider__button { + position: absolute; + width: 14px; + height: 14px; + border: 2px solid $devui-default-line; + background-color: $devui-base-bg; + border-radius: 50%; + margin-left: -7px; + transition: transform 0.2s ease-in-out; + + &:hover { + transform: scale(1.2); + } + + &.disabled { + background-color: $devui-base-bg; + border-color: $devui-disabled-line; + } + + &.disabled:hover { + cursor: not-allowed; + transform: none; + } + } + + .devui-slider_popover { + position: relative; + bottom: 26px; + transform: translate(-50%); + border-radius: $devui-border-radius-feedback; + font-size: $devui-font-size-sm; + color: $devui-feedback-overlay-text; + + .devui-slider_popover-arrow { + position: absolute; + left: 50%; + margin-left: -4px; + bottom: -4px; + width: 8px; + height: 8px; + transform: rotate(45deg); + display: block; + z-index: -1; + background-color: $devui-feedback-overlay-bg; + } + + .devui-slider_popover-content { + padding: 5px 14px; + text-align: center; + border-radius: $devui-border-radius-feedback; + background-color: $devui-feedback-overlay-bg; + } + } + } + + .devui-min_count { + position: absolute; + top: 15px; + font-size: $devui-font-size; + color: $devui-text; + } + + .devui-max_count { + position: absolute; + top: 15px; + right: 0; + font-size: $devui-font-size; + color: $devui-text; + } + + .devui-input__out-wrap { + font-size: $devui-font-size; + position: absolute; + right: -60px; + top: -12px; + padding: 5px 10px; + cursor: text; + margin-left: 20px; + + input { + width: 40px; + text-align: center; + } + } +} diff --git a/packages/devui-vue/devui/slider/src/slider.tsx b/packages/devui-vue/devui/slider/src/slider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3619794833444f51fc55bf6c2b6726a9b1b9744a --- /dev/null +++ b/packages/devui-vue/devui/slider/src/slider.tsx @@ -0,0 +1,185 @@ +import { defineComponent, ref, computed, onMounted } from 'vue'; +import { sliderProps } from './slider-types'; +import './slider.scss'; + +export default defineComponent({ + name: 'DSlider', + props: sliderProps, + emits: ['update:modelValue'], + setup(props, ctx) { + let isClick = true; + let startPosition = 0; + let startX = 0; + + const popoverShow = ref(false); + const sliderRunway = ref<HTMLDivElement>(null); + const inputValue = ref<number>(props.modelValue); + const currentPosition = ref<number>(0); + const newPostion = ref<number>(0); + //当前的位置以百分比显示 + const percentDispaly = ref<string>(''); + const renderShowInput = () => { + return props.showInput ? ( + <div class='devui-input__out-wrap'> + <input onInput={handleOnInput} value={inputValue.value + ''}></input> + </div> + ) : ( + '' + ); + }; + //当传入modelValue时用以定位button的位置 + if (props.modelValue > props.max) { + percentDispaly.value = '100%'; + } else if (props.modelValue < props.min) { + percentDispaly.value = '0%'; + } else { + percentDispaly.value = ((props.modelValue - props.min) * 100) / (props.max - props.min) + '%'; + } + //一挂载就进行当前位置的计算,以后的移动基于当前的位置移动 + onMounted(() => { + const sliderWidth = sliderRunway.value.clientWidth; + currentPosition.value = (sliderWidth * (inputValue.value - props.min)) / (props.max - props.min); + }); + function handleButtonMousedown(event: MouseEvent) { + popoverShow.value = true; + //props.disabled状态是不能点击拖拽的 + if (props.disabled) return; + //阻止默认事件 + event.preventDefault(); + dragStart(event); + //当鼠标开始移动时,进行坐标计算 + window.addEventListener('mousemove', onDragging); + //当鼠标抬起时,停止计算 + window.addEventListener('mouseup', onDragEnd); + } + function dragStart(event: MouseEvent) { + //防止mouseup触发父元素的click事件 + isClick = false; + //获取当前的x坐标值 + startX = event.clientX; + //把当前值给startPosition,以便后面再重新拖拽时,会以当前的位置计算偏移 + startPosition = currentPosition.value; + newPostion.value = startPosition; + } + /** + * + * @param event 鼠标事件 + * currentPosition:当前移动的X的坐标 + * offset:当前x坐标减去初始x坐标的偏移 + * + */ + function onDragging(event: MouseEvent) { + popoverShow.value = true; + const currentX = event.clientX; + const pxOffset = currentX - startX; + //移动的x方向上的偏移+初始位置等于新位置 + newPostion.value = startPosition + pxOffset; + setPostion(newPostion.value); + } + function onDragEnd() { + popoverShow.value = false; + //防止mouseup后立即执行click事件,mouseup后 + //会立即执行click,但是isClick=true 是100ms才出发,因此不会执行click事件,就跳出来了 + setTimeout(() => { + isClick = true; + }, 100); + window.removeEventListener('mousemove', onDragging); + window.removeEventListener('mouseup', onDragEnd); + } + function setPostion(newPosition: number) { + //获取slider的实际长度的像素 + const sliderWidth: number = Math.round(sliderRunway.value.clientWidth); + if (newPosition < 0) { + newPosition = 0; + } + //计算slider的实际像素每段的长度 + const LengthPerStep = sliderWidth / ((props.max - props.min) / props.step); + //计算实际位移的取整段数 + const steps = Math.round(newPosition / LengthPerStep); + //实际的偏移像素 + const value: number = steps * LengthPerStep; + //要是刚好划过半段切刚好超出最大长度的情况进行限定 + if (Math.round(value) >= sliderWidth) { + currentPosition.value = sliderWidth; + inputValue.value = props.max; + percentDispaly.value = '100%'; + ctx.emit('update:modelValue', props.max); + return; + } + //向左偏移百分比的值 + percentDispaly.value = Math.round((value * 100) / sliderWidth) + '%'; + //更新输入框的值 + inputValue.value = Math.round((value * (props.max - props.min)) / sliderWidth) + props.min; + //设置当前所在的位置 + currentPosition.value = newPosition; + ctx.emit('update:modelValue', inputValue.value); + } + //当在滑动条触发鼠标事件时处理, + function handleRunwayMousedown(event) { + if (!props.disabled && isClick) { + startX = event.target.getBoundingClientRect().left; + const currentX = event.clientX; + setPostion(currentX - startX); + handleButtonMousedown(event); + } else { + return; + } + } + //输入框内的值 + function handleOnInput(event) { + inputValue.value = parseInt(event.target.value); + if (!inputValue.value) { + inputValue.value = props.min; + percentDispaly.value = '0%'; + } else { + if (inputValue.value < props.min) { + inputValue.value = props.min; + } + if (inputValue.value > props.max) { + inputValue.value = props.max; + } + const re = /^(?:[1-9]?\d|100)$/; + if (re.test(`${inputValue.value}`)) { + percentDispaly.value = ((inputValue.value - props.min) * 100) / (props.max - props.min) + '%'; + ctx.emit('update:modelValue', inputValue.value); + } + } + } + //添加disabled类 + const disableClass = computed(() => { + return props.disabled ? ' disabled' : ''; + }); + const popover = () => { + return ( + <div class='devui-slider_popover' style={{ left: percentDispaly.value, opacity: popoverShow.value ? 1 : 0 }}> + <div class='devui-slider_popover-arrow'></div> + <div class='devui-slider_popover-content'>{inputValue.value + ' ' + props.tipsRenderer}</div> + </div> + ); + }; + return () => ( + <div class='devui-slider'> + {/* 整个的长度 */} + <div + ref={sliderRunway} class={'devui-slider__runway' + disableClass.value} + onMousedown={handleRunwayMousedown} + onMouseout={() => (popoverShow.value = false)} + > + {/* 滑动后左边的进度条 */} + <div class={'devui-slider__bar' + disableClass.value} style={{ width: percentDispaly.value }}></div> + <div + class={'devui-slider__button' + disableClass.value} + style={{ left: percentDispaly.value }} + onMousedown={handleButtonMousedown} + onMouseenter={() => (popoverShow.value = true)} + onMouseout={() => (popoverShow.value = false)} + ></div> + {props.tipsRenderer === 'null' ? '' : popover()} + </div> + <span class='devui-min_count'>{props.min}</span> + <span class='devui-max_count'>{props.max}</span> + {renderShowInput()} + </div> + ); + }, +}); diff --git a/packages/devui-vue/devui/splitter/__tests__/event-helper.ts b/packages/devui-vue/devui/splitter/__tests__/event-helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..4bc643c3c293db95effdb848f80154fd9ce52e25 --- /dev/null +++ b/packages/devui-vue/devui/splitter/__tests__/event-helper.ts @@ -0,0 +1,38 @@ +export function mouseMoveTrigger( + el: HTMLElement, + from: { x: number; y: number; }, + to: { x: number; y: number; } +): void { + if (typeof window === 'undefined') { + return + } + dispatchMouseEvent(el, 'mousedown', from.x, from.y) + dispatchMouseEvent(window.document, 'mousemove', to.x, to.y) + dispatchMouseEvent(window.document, 'mouseup') +} + +export function dispatchMouseEvent( + node: Node, + type: string, + x = 0, + y = 0, + event: MouseEvent = createMouseEvent(type, x, y) +): void { + node.dispatchEvent(event) +} + +export function createMouseEvent( + type: string, + x = 0, + y = 0 +): MouseEvent { + const event = new MouseEvent(type, { + bubbles: true, + cancelable: false, + clientX: x, + clientY: y, + // TODO pageX + // TODO pageY + }) + return event +} diff --git a/packages/devui-vue/devui/splitter/__tests__/splitter.spec.ts b/packages/devui-vue/devui/splitter/__tests__/splitter.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..270082acab962701d0b83e113711682e92298f14 --- /dev/null +++ b/packages/devui-vue/devui/splitter/__tests__/splitter.spec.ts @@ -0,0 +1,343 @@ +import { mount } from '@vue/test-utils' +import { wrap } from 'lodash' +import { ref } from 'vue' +import DSplitter from '../src/splitter' +import DSplitterPane from '../src/splitter-pane' +import { mouseMoveTrigger } from './event.helper' + +describe('splitter', () => { + describe('basic', () => { + const testComponent = { + components: { + DSplitter, + DSplitterPane, + }, + template: ` + <d-splitter :orientation="orientation" :splitBarSize="splitBarSize" style="height: 500px; border: 1px solid #E3E5E9;"> + <template v-slot:DSplitterPane> + <d-splitter-pane :size="size" :minSize="minSize" :maxSize="maxSize" :collapsible="collapsible" :collapsed="collapsed" @sizeChange="sizeChange"> + <div class="pane-content"> + <h2>左侧面板</h2> + <div>左侧内容区域,宽度 30%,最小宽度 20%</div> + </div> + </d-splitter-pane> + <d-splitter-pane size="50px"> + <div class="pane-content"> + <h2>中间面板</h2> + <div>中间内容区域</div> + </div> + </d-splitter-pane> + <d-splitter-pane> + <div class="pane-content"> + <h2>右侧面板</h2> + <div>右侧内容区域</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + `, + setup() { + const orientation = ref('horizontal') + const collapsible = ref(true) + const collapsed = ref(false) + const splitBarSize = ref('2px') + const size = ref('30%') + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + } + + let wrapper = null + let splitterElement: HTMLElement + beforeEach(() => { + wrapper = mount(testComponent) + splitterElement = wrapper.vm.$el + }) + it('should create testComponent', () => { + expect(wrapper.vm).toBeTruthy() + }) + + it('should create splitter container', () => { + expect(splitterElement).toBeTruthy() + expect(wrapper.classes()).toContain('devui-splitter-horizontal') + }) + + it('should render splitter-bar', () => { + const handles = wrapper.findAll('.devui-splitter-bar') + expect(handles.length).toBe(2) + }) + + it('should collapse left pane when collapseButton clicked', async () => { + // const handleButton = wrapper.find('.prev.devui-collapse') + // handleButton.trigger('click') + // await wrapper.vm.$nextTick() + // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为0 + // const pane = wrapper.find('.devui-splitter-pane').element + // expect(pane.clientWidth).toBe(0) + }) + + it('should add collapsed class when collapseButton clicked', async () => { + const handleButton = wrapper.find('.prev.devui-collapse') + handleButton.trigger('click') + await wrapper.vm.$nextTick() + expect(handleButton.classes()).toContain('collapsed') + }) + + it('should change collapse state', () => { + wrapper = mount( + Object.assign(testComponent, { + setup() { + const orientation = ref('horizontal') + const collapsible = ref(false) + const collapsed = ref(false) + const splitBarSize = ref('2px') + const size = ref('30%') + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + }) + ) + expect(wrapper.find('.prev').classes()).not.toContain('devui-collapse') + }) + + it('should be collapsed', () => { + wrapper = mount( + Object.assign(testComponent, { + setup() { + const orientation = ref('horizontal') + const collapsible = ref(true) + const collapsed = ref(true) + const splitBarSize = ref('2px') + const size = ref('30%') + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + }) + ) + expect(wrapper.find('.prev.devui-collapse').classes()).toContain( + 'collapsed' + ) + }) + + it('should change splitterBar size', async () => { + // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为0 + // 详细可以看 ReadME https://github.com/jsdom/jsdom + // README 建议: `using Object.defineProperty() to change what various layout-related getters and methods return.` 待处理 + // expect(wrapper.find('.devui-splitter-bar').element.clientWidth).toBe(2) + }) + + it('should change splitter direction', () => { + wrapper = mount( + Object.assign(testComponent, { + setup() { + const orientation = ref('vertical') + const collapsible = ref(true) + const collapsed = ref(true) + const splitBarSize = ref('2px') + const size = ref('30%') + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + }) + ) + expect(wrapper.classes()).toContain('devui-splitter-vertical') + }) + + it('should change pane size', async () => { + wrapper = mount( + Object.assign(testComponent, { + setup() { + const orientation = ref('vertical') + const collapsible = ref(true) + const collapsed = ref(true) + const splitBarSize = ref('2px') + const size = ref('40%') + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + }) + ) + await wrapper.vm.$nextTick() + const computedStyle = getComputedStyle( + wrapper.find('.devui-splitter-pane').element + ) + expect(computedStyle.flexBasis).toContain('40%') + }) + + it('should change pane size', () => { + wrapper = mount( + Object.assign(testComponent, { + setup() { + const orientation = ref('vertical') + const collapsible = ref(true) + const collapsed = ref(true) + const splitBarSize = ref('2px') + const size = ref(undefined) + const minSize = ref('20%') + const maxSize = ref('60%') + const sizeChange = (size) => { + console.log(size) + } + return { + orientation, + collapsible, + collapsed, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + } + }, + }) + ) + expect(wrapper.find('.devui-splitter-pane').classes()).not.toContain( + 'devui-splitter-pane-fixed' + ) + }) + + // 测试拖动时size最小边界 + it('should minimum size work', async () => { + const leftPaneElement: HTMLElement = wrapper.find( + '.devui-splitter-pane' + ).element + + // TODO Jest 基于 jsdom,jsdom not support getBoundingClientRect + const rect = leftPaneElement.getBoundingClientRect() + const splitterBarElement: HTMLElement = wrapper.find( + '.devui-splitter-bar' + ).element + // 模拟鼠标事件 + mouseMoveTrigger( + splitterBarElement, + { x: rect.right, y: rect.height }, + { x: rect.right - 2000, y: rect.height } + ) + + // TODO: Jest 基于 jsdom,jsdom not support `clientWidth`,clientWidth 为 0 + }) + }) + + describe('vertical', () => { + const testComponent = { + components: { + DSplitter, + DSplitterPane, + }, + template: ` + <d-splitter :orientation="orientation" style="height: 500px; border: 1px solid #E3E5E9;"> + <d-splitter-pane> + <div class="pane-content"> + <h2>上面板</h2> + <div>内容区域</div> + </div> + </d-splitter-pane> + <d-splitter-pane :size="size" :minSize="minSize" :maxSize="maxSize"> + <div class="pane-content"> + <h2>下面板</h2> + <div>内容区域</div> + </div> + </d-splitter-pane> + <d-splitter-pane [size]="'100px'" [resizable]="false"> + <div class="pane-content"> + <h2>下面板</h2> + <div>内容区域</div> + </div> + </d-splitter-pane> + </d-splitter> + `, + setup() { + const orientation = ref('vertical') + const size = ref('100px') + const minSize = ref('50px') + const maxSize = ref('200px') + return { + orientation, + size, + minSize, + maxSize, + } + }, + } + + let wrapper = null + beforeEach(() => { + wrapper = mount(testComponent) + }) + + it('should create vertical container', () => { + expect(wrapper.vm.$el).toBeTruthy() + expect(wrapper.classes()).toContain('devui-splitter-vertical') + }) + + // 测试拖动时 size 最大边界 + it('should right panel maximum size work', async () => { + // TODO Jest 基于 jsdom,jsdom not support getBoundingClientRect + }) + }) +}) diff --git a/packages/devui-vue/devui/splitter/index.ts b/packages/devui-vue/devui/splitter/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2815770bdbea9fadc8c8b4e2b0acf0b9bad6c343 --- /dev/null +++ b/packages/devui-vue/devui/splitter/index.ts @@ -0,0 +1,19 @@ +import type { App } from 'vue' +import Splitter from './src/splitter' +import SplitterPane from './src/splitter-pane' + +Splitter.install = function (app: App): void { + app.component(Splitter.name, Splitter) + app.component(SplitterPane.name, SplitterPane) +} + +export { Splitter } + +export default { + title: 'Splitter 分割器', + category: '布局', + status: '已完成', + install(app: App): void { + app.use(Splitter as any) + }, +} diff --git a/packages/devui-vue/devui/splitter/src/splitter-bar-type.tsx b/packages/devui-vue/devui/splitter/src/splitter-bar-type.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8d245b435e1bad8c32b0fe9166b1f70a971fdc59 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-bar-type.tsx @@ -0,0 +1,40 @@ +import { PropType, ExtractPropTypes } from 'vue' +import { SplitterOrientation } from './splitter-types' + +export const splitterBarProps = { + /** + * 当前 pane 的索引 + */ + index: { + type: Number, + }, + /** + * 必选,指定 SplitterBar 的方向 + */ + orientation: { + type: String as PropType<SplitterOrientation>, + required: true, + }, + /** + * 分隔条大小 + */ + splitBarSize: { + type: String, + required: true, + }, + /** + * 可选,pane 设置不可调整宽度时生效 + */ + disabledBarSize: { + type: String, + default: '1px', + }, + /** + * 是否显示展开/收缩按钮 + */ + showCollapseButton: { + type: Boolean, + }, +} as const + +export type SplitterBarProps = ExtractPropTypes<typeof splitterBarProps> diff --git a/packages/devui-vue/devui/splitter/src/splitter-bar.scss b/packages/devui-vue/devui/splitter/src/splitter-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..f78bcb91b153ddb9bd08fb2f024cb1c0e3befc86 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-bar.scss @@ -0,0 +1,242 @@ +@import '../../style/theme/color'; +@import '../../style/theme/corner'; + +.devui-splitter-bar { + background-color: $devui-dividing-line; + display: flex; + position: relative; + align-items: center; + justify-content: center; + flex-grow: 0; + flex-shrink: 0; + + .devui-collapse { + background-color: $devui-dividing-line; + position: absolute; + z-index: 15; + cursor: pointer; + + &::before, + &::after { + content: ''; + width: 10px; + height: 2px; + background: #ffffff; + display: block; + position: absolute; + } + + &:hover { + background-color: $devui-brand-hover; + } + } + + &-horizontal { + .devui-collapse { + width: 12px; + height: 30px; + + &.prev, + &.next { + &.hidden { + display: none; + } + } + + &.prev { + border-radius: + 0 $devui-border-radius-feedback + $devui-border-radius-feedback 0; + left: 100%; + + &::before, + &.collapsed::before { + top: 9px; + left: 1px; + } + + &::before { + transform: rotate(-70deg); + } + + &.collapsed::before { + transform: rotate(70deg); + } + + &::after, + &.collapsed::after { + top: 18px; + left: 1px; + } + + &::after { + transform: rotate(70deg); + } + + &.collapsed::after { + transform: rotate(-70deg); + } + } + + &.next { + border-radius: + $devui-border-radius-feedback 0 0 + $devui-border-radius-feedback; + right: 100%; + + &::before, + &.collapsed::before { + top: 9px; + right: 1px; + } + + &::before { + transform: rotate(70deg); + } + + &.collapsed::before { + transform: rotate(-70deg); + } + + &::after, + &.collapsed::after { + top: 18px; + right: 1px; + } + + &::after { + transform: rotate(-70deg); + } + + &.collapsed::after { + transform: rotate(70deg); + } + } + } + } + + &-vertical { + .devui-collapse { + height: 12px; + width: 30px; + + &.prev, + &.next { + &.hidden { + display: none; + } + } + + &.prev { + border-radius: + 0 0 $devui-border-radius-feedback + $devui-border-radius-feedback; + top: 100%; + + &::before, + &.collapsed::before { + bottom: 5px; + left: 5px; + } + + &::before { + transform: rotate(-20deg); + } + + &.collapsed::before { + transform: rotate(20deg); + } + + &::after, + &.collapsed::after { + bottom: 5px; + left: 14px; + } + + &::after { + transform: rotate(20deg); + } + + &.collapsed::after { + transform: rotate(-20deg); + } + } + + &.next { + border-radius: + $devui-border-radius-feedback + $devui-border-radius-feedback 0 0; + bottom: 100%; + + &::before, + &.collapsed::before { + top: 5px; + left: 5px; + } + + &::before { + transform: rotate(20deg); + } + + &.collapsed::before { + transform: rotate(-20deg); + top: 5px; + left: 5px; + } + + &::after, + &.collapsed::after { + top: 5px; + left: 14px; + } + + &::after { + transform: rotate(-20deg); + } + + &.collapsed::after { + transform: rotate(20deg); + } + } + } + } + + &-horizontal.resizable:not(.none-resizable), + &-vertical.resizable:not(.none-resizable) { + &:hover, + &:focus, + &:active { + background-color: $devui-brand-hover; + } + + &::after { + content: ''; + display: block; + position: absolute; + z-index: 10; + } + } + + &-horizontal.resizable { + // 修正IE浏览器,css伪元素中鼠标手型无效 + cursor: col-resize; + + &::after { + cursor: col-resize; + height: 100%; + width: 10px; + top: 0; + } + } + + &-vertical.resizable { + cursor: row-resize; + + &::after { + cursor: row-resize; + width: 100%; + height: 10px; + left: 0; + } + } +} diff --git a/packages/devui-vue/devui/splitter/src/splitter-bar.tsx b/packages/devui-vue/devui/splitter/src/splitter-bar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..949640cc016fb7acee67fb82e12cc375da5b82e4 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-bar.tsx @@ -0,0 +1,189 @@ +import { + defineComponent, + ref, + watch, + nextTick, + reactive, + computed, + withDirectives, + onMounted, + inject, +} from 'vue' +import type { SplitterStore } from './splitter-store' +import { setStyle } from '../../shared/util/set-style' +import { addClass, removeClass } from '../../shared/util/class' +import dresize, { ResizeDirectiveProp } from './util/d-resize-directive' +import './splitter-bar.scss' +import { splitterBarProps, SplitterBarProps } from './splitter-bar-type' + +export default defineComponent({ + name: 'DSplitterBar', + props: splitterBarProps, + setup(props: SplitterBarProps) { + const store: SplitterStore = inject('splitterStore') + const state = reactive({ + wrapperClass: `devui-splitter-bar devui-splitter-bar-${props.orientation}`, + }) + const domRef = ref<null | HTMLElement>() + onMounted(() => { + watch([() => props.splitBarSize, domRef], ([curSplitBarSize, ele]) => { + if (!(ele instanceof HTMLElement)) { + return; + } + setStyle(ele, { flexBasis: curSplitBarSize }) + }, { immediate: true }) + + watch([() => store.state.panes, domRef], ([panes, ele]) => { + if (!store.isStaticBar(props.index)) { + state.wrapperClass += ' resizable' + } else { + setStyle(ele, { flexBasis: props.disabledBarSize }) + } + }, { deep: true }) + }) + + // 指令输入值 + const coordinate = { pageX: 0, pageY: 0, originalX: 0, originalY: 0 } + let initState + // TODO 待优化,如何像 angular rxjs 操作一样优雅 + const resizeProp: ResizeDirectiveProp = { + enableResize: true, + onPressEvent: function ({ originalEvent }): void { + originalEvent.stopPropagation() // 按下的时候,阻止事件冒泡 + if (!store.isResizable(props.index)) return + initState = store.dragState(props.index) + coordinate.originalX = originalEvent.pageX + coordinate.originalY = originalEvent.pageY + }, + onDragEvent: function ({ originalEvent }): void { + originalEvent.stopPropagation() // 移动的时候,阻止事件冒泡 + if (!store.isResizable(props.index)) return + coordinate.pageX = originalEvent.pageX + coordinate.pageY = originalEvent.pageY + let distance + if (props.orientation === 'vertical') { + distance = coordinate.pageY - coordinate.originalY + } else { + distance = coordinate.pageX - coordinate.originalX + } + store.setSize(initState, distance) + }, + onReleaseEvent: function ({ originalEvent }): void { + originalEvent.stopPropagation() // 释放的时候,阻止事件冒泡 + if (!store.isResizable(props.index)) return + coordinate.pageX = originalEvent.pageX + coordinate.pageY = originalEvent.pageY + let distance + if (props.orientation === 'vertical') { + distance = coordinate.pageY - coordinate.originalY + } else { + distance = coordinate.pageX - coordinate.originalX + } + store.setSize(initState, distance) + }, + } + + const queryPanes = (index, nearIndex) => { + const pane = store.getPane(index) + const nearPane = store.getPane(nearIndex) + return { + pane, + nearPane, + } + } + + // 根据当前状态生成收起按钮样式 + const generateCollapseClass = (pane, nearPane, showIcon) => { + // 是否允许收起 + const isCollapsible = pane?.component?.props?.collapsible && showIcon + // 当前收起状态 + const isCollapsed = pane?.component?.props?.collapsed + // 一个 pane 收起的时候,隐藏相邻 pane 的收起按钮 + const isNearPaneCollapsed = nearPane.collapsed + return { + 'devui-collapse': isCollapsible, + collapsed: isCollapsed, + hidden: isNearPaneCollapsed, + } + } + + // 计算前面板收起操作样式 + const prevClass = computed(() => { + const { pane, nearPane } = queryPanes(props.index, props.index + 1) + // TODO 提示文字 + + // 第一个面板或者其它面板折叠方向不是向后的, 显示操作按钮 + const showIcon = + pane?.component?.props?.collapseDirection !== 'after' || + props.index === 0 + return generateCollapseClass(pane, nearPane, showIcon) + }) + + // 计算相邻面板收起操作样式 + const nextClass = computed(() => { + const { pane, nearPane } = queryPanes(props.index + 1, props.index) + // TODO 提示文字 + + // 最后一个面板或者其它面板折叠方向不是向前的显示操作按钮 + const showIcon = + pane?.component?.props?.collapseDirection !== 'before' || + props.index + 1 === store.state.paneCount - 1 + return generateCollapseClass(pane, nearPane, showIcon) + }) + + // 切换是否允许拖拽,收起时不能拖拽 + const toggleResize = () => { + const { pane, nearPane } = queryPanes(props.index, props.index + 1) + const isCollapsed = + pane?.component?.props?.collapsed || + nearPane?.component?.props?.collapsed + if (isCollapsed) { + addClass(domRef.value, 'none-resizable') + } else { + removeClass(domRef.value, 'none-resizable') + } + } + + const handleCollapsePrePane = (lockStatus?: boolean) => { + store.tooglePane(props.index, props.index + 1, lockStatus) + toggleResize() + } + + const handleCollapseNextPane = (lockStatus?: boolean) => { + store.tooglePane(props.index + 1, props.index, lockStatus) + toggleResize() + } + + const initialCollapseStatus = () => { + handleCollapsePrePane(true) + handleCollapseNextPane(true) + } + + onMounted(() => { + initialCollapseStatus() + }) + + return () => { + return withDirectives( + <div class={state.wrapperClass} ref={domRef}> + {props.showCollapseButton ? ( + <div + class={['prev', prevClass.value]} + onClick={() => { + handleCollapsePrePane() + }} + ></div> + ) : null} + <div class="devui-resize-handle"></div> + {props.showCollapseButton ? ( + <div + class={['next', nextClass.value]} + onClick={() => handleCollapseNextPane()} + ></div> + ) : null} + </div>, + [[dresize, resizeProp]] + ) + } + }, +}) diff --git a/packages/devui-vue/devui/splitter/src/splitter-pane-type.tsx b/packages/devui-vue/devui/splitter/src/splitter-pane-type.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b1773e9edcfb759963d673e0d858bce188e05fd9 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-pane-type.tsx @@ -0,0 +1,68 @@ +import { ExtractPropTypes, PropType } from 'vue'; +import { CollapseDirection } from './splitter-types'; + +export const splitterPaneProps = { + /** + * 可选,指定 pane 宽度,设置像素值或者百分比 + * pane初始化大小 + */ + size: { + type: String, + }, + /** + * 可选,指定 pane 最小宽度,设置像素值或者百分比 + */ + minSize: { + type: String, + }, + /** + * 可选,指定 pane 最大宽度,设置像素值或者百分比 + */ + maxSize: { + type: String, + }, + /** + * 可选,指定 pane 是否可调整大小,会影响相邻 pane + */ + resizable: { + type: Boolean, + default: true, + }, + /** + * 可选,指定 pane 是否可折叠收起 + */ + collapsible: { + type: Boolean, + default: false, + }, + /** + * 可选,指定 pane 初始化是否收起,配合 collapsible 使用 + */ + collapsed: { + type: Boolean, + default: false, + }, + /** + * 非边缘面板折叠方向,before 只生成向前折叠的按钮,after 生成向后折叠按钮,both 生成两个 + */ + collapseDirection: { + type: String as PropType<CollapseDirection>, + default: 'both', + }, + /** + * 可选,是否在 pane 进行折叠后收缩 pane 宽度而非收起 + */ + shrink: { + type: Boolean, + default: false, + }, + /** + * 可选,折叠后收缩的 pane 宽度 (单位:px) + */ + shrinkWidth: { + type: Number, + default: 36, + }, +} as const; + +export type SplitterPaneProps = ExtractPropTypes<typeof splitterPaneProps>; diff --git a/packages/devui-vue/devui/splitter/src/splitter-pane.scss b/packages/devui-vue/devui/splitter/src/splitter-pane.scss new file mode 100644 index 0000000000000000000000000000000000000000..c8cf77007b063cb9015713205905661aaf40bfc3 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-pane.scss @@ -0,0 +1,23 @@ +.devui-splitter-pane { + position: relative; + flex: 1 1 auto; + display: block; + min-width: 0; + max-width: 100%; + min-height: 0; + max-height: 100%; + + &-fixed { + flex-grow: 0; + flex-shrink: 0; + } + + &-hidden { + flex: 0 !important; + overflow: hidden !important; + } + + &-grow { + flex-grow: 1 !important; + } +} diff --git a/packages/devui-vue/devui/splitter/src/splitter-pane.tsx b/packages/devui-vue/devui/splitter/src/splitter-pane.tsx new file mode 100644 index 0000000000000000000000000000000000000000..55760c696a49337e9920e28f48b7fb38c07d5b83 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-pane.tsx @@ -0,0 +1,134 @@ +import { + defineComponent, + ref, + watch, + nextTick, + inject, + onMounted, + onUpdated, +} from 'vue'; +import { addClass, hasClass, removeClass } from '../../shared/util/class'; +import { setStyle } from '../../shared/util/set-style'; +import type { SplitterStore } from './splitter-store'; +import { splitterPaneProps, SplitterPaneProps } from './splitter-pane-type'; +import './splitter-pane.scss'; + +export default defineComponent({ + name: 'DSplitterPane', + props: splitterPaneProps, + emits: ['sizeChange', 'collapsedChange'], + setup(props: SplitterPaneProps, { slots, expose }) { + const store: SplitterStore = inject('splitterStore'); + const domRef = ref<null | HTMLElement>(); + const orderRef = ref(); + watch([orderRef, domRef], + ([order, ele]) => { + if (!ele) { + return; + } + setStyle(ele, { order }); + } + ); + + // pane 初始化大小 + const setSizeStyle = (curSize: string) => { + const ele = domRef.value; + if (!ele) { + return; + } + + ele.style.flexBasis = curSize; + const paneFixedClass = 'devui-splitter-pane-fixed'; + if (curSize) { + // 设置 flex-grow 和 flex-shrink + addClass(ele, paneFixedClass); + } else { + removeClass(ele, paneFixedClass); + } + }; + + watch( + () => props.size, + setSizeStyle, + { immediate: true } + ); + + const orientation = inject('orientation'); + let initialSize = ''; // 记录初始化挂载传入的大小 + onMounted(() => { + initialSize = props.size; + store.setPanes({ panes: store.state.panes }); + }); + + onUpdated(() => { + store.setPanes({ panes: store.state.panes }); + }); + + // 获取当前 pane大小 + const getPaneSize = (): number => { + const ele = domRef.value; + if (!ele) { + return; + } + if (orientation === 'vertical') { + return ele.offsetHeight; + } else { + return ele.offsetWidth; + } + }; + + + watch( + () => props.collapsed, + (collapsed: boolean) => { + const ele = domRef.value; + if (!ele) { + return; + } + const paneHiddenClass = 'devui-splitter-pane-hidden'; + if (!collapsed) { + removeClass(ele, paneHiddenClass); + } else { + addClass(ele, paneHiddenClass); + } + + if (collapsed && props.shrink) { + removeClass(ele, paneHiddenClass); + setStyle(ele, { flexBasis: `${props.shrinkWidth}px` }); + } else { + setStyle(ele, { flexBasis: initialSize }); + } + }, + { immediate: true } + ); + + // 收起时用于改变相邻 pane 的 flex-grow 属性来改变非自适应 pane 的 size + const toggleNearPaneFlexGrow = (collapsed: boolean) => { + const ele = domRef.value; + if (!(ele instanceof HTMLElement)) { + return; + } + const flexGrowClass = 'devui-splitter-pane-grow'; + if (hasClass(ele, flexGrowClass)) { + removeClass(ele, flexGrowClass); + } else if (collapsed) { + addClass(ele, flexGrowClass); + } + }; + + // 暴露给外部使用 + expose({ + order: orderRef, + getPaneSize, + toggleNearPaneFlexGrow, + }); + + return () => { + return ( + <div class="devui-splitter-pane" ref={domRef}> + {slots.default?.()} + </div> + ); + }; + }, +}); diff --git a/packages/devui-vue/devui/splitter/src/splitter-store.ts b/packages/devui-vue/devui/splitter/src/splitter-store.ts new file mode 100644 index 0000000000000000000000000000000000000000..50787194b59fa9c1b8f3ce6d7906d893a1b40300 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-store.ts @@ -0,0 +1,195 @@ +import SplitterPane from './splitter-pane' +import { reactive } from 'vue' + +export interface Pane { + getPaneSize: () => number +} + +export interface PaneState { + index: number + initialSize: number + minSize: number + maxSize: number +} + +export interface DragState { + prev: PaneState + next: PaneState +} + +type SplitterPane = typeof SplitterPane & Pane +export interface splitterState { + panes: Array<SplitterPane> // 所有 pane 对象的一些关键信息 + paneCount: number + splitterContainerSize: number +} + +export class SplitterStore { + state: splitterState + constructor() { + this.state = reactive({ + panes: [], + splitterContainerSize: 0, + paneCount: 0, + }) + } + // 配置 pane 信息,panes 列表,方便后续计算使用 + setPanes({ panes }): void { + this.state.panes = panes.map((pane: SplitterPane, index: number) => { + if (pane.component) { + pane.component.exposed.order.value = index * 2 + } + pane.getPaneSize = pane?.component?.exposed.getPaneSize + return pane + }) + this.state.paneCount = panes.length + } + setSplitter({ containerSize }: { containerSize: number; }): void { + this.state.splitterContainerSize = containerSize + } + + // 获取 pane,防止没有初始化的时候调用内部方法取值 + getPane(index: number): SplitterPane { + if (!this.state.panes || index < 0 || index >= this.state.panes.length) { + throw new Error('no pane can return.') + } + return this.state.panes[index] + } + + // 按下的时候计算 pane 的 size 信息 + dragState(splitbarIndex: number): DragState { + const prev = this.getPane(splitbarIndex) + const next = this.getPane(splitbarIndex + 1) + const total = prev.getPaneSize() + next.getPaneSize() + return { + prev: { + index: splitbarIndex, + initialSize: prev.getPaneSize(), + // 设置有最小值,直接取值,如果没有设置就用两个 pane 总和减去相邻 pane 的最大值,都没设置(NaN)再取0 + minSize: + this.toPixels(prev.component.props.minSize) || + total - this.toPixels(next.component.props.maxSize) || + 0, + // 设置最大值,直接取值,如果没有设置就用两个 pane 总和减去相邻 pane 的最小值,都没设置(NaN)再取两个 pane 总和 + maxSize: + this.toPixels(prev.component.props.maxSize) || + total - this.toPixels(next.component.props.minSize) || + total, + }, + next: { + index: splitbarIndex + 1, + initialSize: next.getPaneSize(), + minSize: + this.toPixels(next.component.props.minSize) || + total - this.toPixels(prev.component.props.maxSize) || + 0, + maxSize: + this.toPixels(next.component.props.maxSize) || + total - this.toPixels(prev.component.props.minSize) || + total, + }, + } + } + + // 大小限制函数,(max)小于最小值时取最小值,(min)大于最大值时取最大值 + clamp(minSize: number, maxSize: number, initialSize: number): number { + return Math.min(maxSize, Math.max(minSize, initialSize)) + } + + // resize pane的大小 + resize(paneState: PaneState, moveSize: number): void { + const pane = this.getPane(paneState.index) + const splitterSize = this.state.splitterContainerSize + const newSize = this.clamp( + paneState.minSize, + paneState.maxSize, + paneState.initialSize + moveSize + ) + let size = '' + if (this.isPercent(pane.component.props.size)) { + size = (newSize / splitterSize) * 100 + '%' + } else { + size = newSize + 'px' + } + pane.component.props.size = size + pane.component.emit('sizeChange', size) + } + + // 判断 pane 是否可以调整大小,只要有一边设置了不可调整或者收起,相邻 pane 调整就失效 + isResizable(splitBarIndex: number): boolean { + const prevPane = this.getPane(splitBarIndex) + const nextPane = this.getPane(splitBarIndex + 1) + const paneCollapsed = + prevPane?.component?.props?.collapsed || + nextPane?.component?.props?.collapsed + return ( + prevPane?.component?.props?.resizable && + nextPane?.component?.props?.resizable && + !paneCollapsed + ) + } + + // 判断分割条是否是固定的,只要有一边不能调整, 就是禁用状态固定 bar + isStaticBar(splitBarIndex: number): boolean { + const prevPane = this.getPane(splitBarIndex) + const nextPane = this.getPane(splitBarIndex + 1) + return !( + prevPane?.component?.props?.resizable && + nextPane?.component?.props?.resizable + ) + } + + // 判断是不是百分比设置宽度 + isPercent(size: string) { + return /%$/.test(size) + } + + // 计算时把百分比转换为像素 + toPixels(size: string): number { + // 值不满足转换时,result 为 NaN,方便计算最小、最大宽度判断 + let result = parseFloat(size) + if (this.isPercent(size)) { + result = (this.state.splitterContainerSize * result) / 100 + } + return result + } + + // 切换 pane 展开,收起 + tooglePane( + paneIndex: number, + nearPaneIndex: number, + lockStatus?: boolean + ): void { + const pane = this.getPane(paneIndex) + const nearPane = this.getPane(nearPaneIndex) + if (pane?.component?.props?.collapsible) { + pane.component.props.collapsed = lockStatus + ? pane?.component?.props?.collapsed + : !pane?.component?.props?.collapsed + nearPane?.component?.exposed?.toggleNearPaneFlexGrow( + pane?.component?.props?.collapsed + ) + pane?.component?.emit( + 'collapsedChange', + pane?.component?.props?.collapsed + ) + } + } + + // 设置 pane 大小 + setSize(state: DragState, distance: number): void { + const prev = this.getPane(state.prev.index) + const next = this.getPane(state.next.index) + if (prev.component.props.size && next.component.props.size) { + // 相邻的两个 pane 都指定了 size,需要同时修改 size + this.resize(state.prev, distance) + this.resize(state.next, -distance) + } else if (next.component.props.size) { + // 只有 next pane指定了 size,直接修改 next pane + this.resize(state.next, -distance) + } else { + // 最后都没有指定 size,直接修改 pre pane + this.resize(state.prev, distance) + } + } +} diff --git a/packages/devui-vue/devui/splitter/src/splitter-types.ts b/packages/devui-vue/devui/splitter/src/splitter-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8bf2ec19af8fd9ed6718f264599d0690aa6873df --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter-types.ts @@ -0,0 +1,36 @@ +import type { PropType, ExtractPropTypes } from 'vue' +export type SplitterOrientation = 'vertical' | 'horizontal' +export type CollapseDirection = 'before' | 'after' | 'both' + +export const splitterProps = { + /** + * 可选,指定 Splitter 分割方向,可选值'vertical'|'horizontal' + */ + orientation: { + type: String as PropType<SplitterOrientation>, + default: 'horizontal', + }, + /** + * 可选,分隔条大小,默认 2px + */ + splitBarSize: { + type: String, + default: '2px', + }, + /** + * 可选,pane 设置不可调整宽度时生效 + */ + disabledBarSize: { + type: String, + default: '1px', + }, + /** + * 是否显示展开/收缩按钮 + */ + showCollapseButton: { + type: Boolean, + default: true, + }, +} as const + +export type SplitterProps = ExtractPropTypes<typeof splitterProps> diff --git a/packages/devui-vue/devui/splitter/src/splitter.scss b/packages/devui-vue/devui/splitter/src/splitter.scss new file mode 100644 index 0000000000000000000000000000000000000000..a2f5eb8136132ec4a94d5ab93982429f5e070f68 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter.scss @@ -0,0 +1,18 @@ +@import '../../style/theme/color'; +@import '../../style/theme/corner'; + +.devui-splitter { + display: flex; + width: 100%; + height: auto; + position: relative; + border-radius: $devui-border-radius; + + &.devui-splitter-horizontal { + flex-direction: row; + } + + &.devui-splitter-vertical { + flex-direction: column; + } +} diff --git a/packages/devui-vue/devui/splitter/src/splitter.tsx b/packages/devui-vue/devui/splitter/src/splitter.tsx new file mode 100644 index 0000000000000000000000000000000000000000..49abaf38222964b18e205af6fd1253fa055adc18 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/splitter.tsx @@ -0,0 +1,65 @@ +import { defineComponent, reactive, ref, provide, nextTick, watch } from 'vue' +import { splitterProps, SplitterProps } from './splitter-types' +import DSplitterBar from './splitter-bar' +import { SplitterStore } from './splitter-store' +import './splitter.scss' + +export default defineComponent({ + name: 'DSplitter', + components: { + DSplitterBar, + }, + props: splitterProps, + emits: [], + setup(props: SplitterProps, ctx) { + const store: SplitterStore = new SplitterStore() + const state = reactive({ + panes: [], // 内嵌面板 + }) + + state.panes = ctx.slots.DSplitterPane?.() || [] + + store.setPanes({ panes: state.panes }) + provide('orientation', props.orientation) + provide('splitterStore', store) + + const domRef = ref<HTMLElement>() + watch(domRef, (ele) => { + if (!ele) { + return; + } + let containerSize = 0 + if (props.orientation === 'vertical') { + containerSize = ele.clientHeight + } else { + containerSize = ele.clientWidth + } + store.setSplitter({ containerSize }) + }) + + return () => { + const { splitBarSize, orientation, showCollapseButton } = props + const wrapperClass = ['devui-splitter', `devui-splitter-${orientation}`] + + return ( + <div class={wrapperClass} ref={domRef}> + {state.panes} + {state.panes + .filter((pane, index, arr) => index !== arr.length - 1) + .map((pane, index) => { + return ( + <d-splitter-bar + key={index} + style={`order: ${index * 2 + 1}`} + splitBarSize={splitBarSize} + orientation={orientation} + index={index} + showCollapseButton={showCollapseButton} + ></d-splitter-bar> + ) + })} + </div> + ) + } + }, +}) diff --git a/packages/devui-vue/devui/splitter/src/util/d-resize-directive.ts b/packages/devui-vue/devui/splitter/src/util/d-resize-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..69dfda5acad08be35cc44ca6dc29afc0fc473399 --- /dev/null +++ b/packages/devui-vue/devui/splitter/src/util/d-resize-directive.ts @@ -0,0 +1,85 @@ +import type { Directive, DirectiveBinding } from 'vue' +export interface OnResizeEvent { + (coordinateInfo: CoordinateInfo): void +} +export interface ResizeDirectiveProp { + enableResize: true // 是否允许拖动 + onPressEvent: OnResizeEvent + onDragEvent: OnResizeEvent + onReleaseEvent: OnResizeEvent +} + +export interface CoordinateInfo { + pageX: number + pageY: number + clientX: number + clientY: number + offsetX: number + offsetY: number + type: string + originalEvent: MouseEvent +} + +const resize: Directive = { + mounted(el, { value }: DirectiveBinding<ResizeDirectiveProp>) { + el.$value = value + // 是否允许拖动 + if (value.enableResize) { + bindEvent(el) + } + }, + unmounted(el, { value }: DirectiveBinding<ResizeDirectiveProp>) { + if (value.enableResize) { + unbind(el, 'mousedown', onMousedown) + } + }, +} + +function bindEvent(el) { + // 绑定 mousedown 事件 + bind(el, 'mousedown', onMousedown) + // TODO 绑定触屏事件 +} + +function bind(el, event, callback) { + el.addEventListener && el.addEventListener(event, callback) +} + +function unbind(el, event, callback) { + el.removeEventListener && el.removeEventListener(event, callback) +} + +function onMousedown(e) { + const $value = e?.target?.$value + if (!$value) return // 提前退出,避免 splitter-bar 子元素响应导致错误 + + bind(document, 'mousemove', onMousemove) + bind(document, 'mouseup', onMouseup) + $value.onPressEvent(normalizeEvent(e)) + + function onMousemove(e) { + $value.onDragEvent(normalizeEvent(e)) + } + + function onMouseup(e) { + unbind(document, 'mousemove', onMousemove) + unbind(document, 'mouseup', onMouseup) + $value.onReleaseEvent(normalizeEvent(e)) + } +} + +// 返回常用位置信息 +function normalizeEvent(e) { + return { + pageX: e.pageX, + pageY: e.pageY, + clientX: e.clientX, + clientY: e.clientY, + offsetX: e.offsetX, + offsetY: e.offsetY, + type: e.type, + originalEvent: e, + } +} + +export default resize diff --git a/packages/devui-vue/devui/status/__tests__/status.spec.ts b/packages/devui-vue/devui/status/__tests__/status.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bd4546d5e93c23e5a64f5db25fbec766a41d51e --- /dev/null +++ b/packages/devui-vue/devui/status/__tests__/status.spec.ts @@ -0,0 +1,46 @@ +import { mount } from '@vue/test-utils'; +import Status from '../status'; + +describe('d-status', () => { + it('type', async () => { + const wrapper = mount(Status, { + props: { type: 'success' } + }); + + expect(wrapper.classes()).toContain('devui-status-bg-success'); + + await wrapper.setProps({ type: 'error' }); + + expect(wrapper.classes()).toContain('devui-status-bg-error'); + + await wrapper.setProps({ type: 'warning' }); + + expect(wrapper.classes()).toContain('devui-status-bg-warning'); + + await wrapper.setProps({type: 'initial'}); + + expect(wrapper.classes()).toContain('devui-status-bg-initial'); + + await wrapper.setProps({type: 'waiting'}); + + expect(wrapper.classes()).toContain('devui-status-bg-waiting'); + + await wrapper.setProps({type: 'running'}); + + expect(wrapper.classes()).toContain('devui-status-bg-running'); + + await wrapper.setProps({type: 'invalid'}); + + expect(wrapper.classes()).toContain('devui-status-bg-invalid'); + }); + + it('slot', () => { + const statusText = 'vue3 devui'; + const wrapper = mount(Status, { + slots: { + default: statusText + } + }); + expect(wrapper.text()).toEqual(statusText); + }); +}); diff --git a/packages/devui-vue/devui/status/index.ts b/packages/devui-vue/devui/status/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..89c0743741475edd7f9f8434844fd522bd500b46 --- /dev/null +++ b/packages/devui-vue/devui/status/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Status from './src/status' + +Status.install = function(app: App) { + app.component(Status.name, Status) +} + +export { Status } + +export default { + title: 'Status 状态', + category: '通用', + status: '已完成', + install(app: App): void { + app.use(Status as any) + } +} diff --git a/packages/devui-vue/devui/status/src/status.scss b/packages/devui-vue/devui/status/src/status.scss new file mode 100644 index 0000000000000000000000000000000000000000..28dd4725ce5c1aad937d811eab20ef71bd04d52c --- /dev/null +++ b/packages/devui-vue/devui/status/src/status.scss @@ -0,0 +1,65 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/theme/font'; +@import '../../style/theme/corner'; + +.devui-status { + line-height: 20px; + height: 20px; + display: flex; + align-items: center; + + &::before { + display: inline-block; + content: ''; + width: 10px; + height: 10px; + margin-right: 5px; + border-radius: 100%; + } +} + +.devui-status.devui-status-bg { + &-success { + &::before { + background-color: $devui-success; + } + } + + &-error { + &::before { + background-color: $devui-danger; + } + } + + &-warning { + &::before { + background-color: $devui-warning; + } + } + + &-initial { + &::before { + background-color: $devui-initial; + } + } + + &-waiting { + &::before { + background-color: $devui-waiting; + } + } + + &-running { + &::before { + background-color: $devui-info; + } + } + + &-invalid { + &::before { + background-color: $devui-dividing-line; + } + } +} diff --git a/packages/devui-vue/devui/status/src/status.tsx b/packages/devui-vue/devui/status/src/status.tsx new file mode 100644 index 0000000000000000000000000000000000000000..40e8645c05e993f06f0091d94cd520a70388e208 --- /dev/null +++ b/packages/devui-vue/devui/status/src/status.tsx @@ -0,0 +1,30 @@ + +import { defineComponent, computed } from 'vue'; +export type IStatusType = 'success' | 'error' | 'initial' | 'warning' | 'waiting' | 'running' | 'invalid'; +import './status.scss'; + +export default defineComponent({ + name: 'DStatus', + props: { + type:{ + default: 'initial', + type: String as () => IStatusType + } + }, + setup(props, ctx) { + const typeClass = computed(() => { + const { type } = props; + const typeStatus = ['success' , 'error' , 'initial' , 'warning' , 'waiting' , 'running' , 'invalid']; + let typeClassStr = `devui-status devui-status-bg-invalid`; + if(typeStatus.includes(type)){ + typeClassStr = `devui-status devui-status-bg-${type}`; + } + return typeClassStr; + }); + return () => { + return <span class={typeClass.value}> + {ctx.slots.default?.()} + </span> + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/steps-guide/hooks/index.ts b/packages/devui-vue/devui/steps-guide/hooks/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cc49d128a46584ea6d750d4943fae3abe12d769 --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './use-steps-guide-position' +export * from './use-steps-guide-ctrl' \ No newline at end of file diff --git a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c1b13a906e7d05082915e363a21dacddd82d9bc --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts @@ -0,0 +1,25 @@ +import { ref, nextTick } from 'vue' + +export function useStepsGuideCtrl(stepsCount, stepIndex, updateGuidePosition) { + const showSteps = ref<boolean>(true) + const closeSteps = ():void => { + showSteps.value = false + } + const setCurrentIndex = (index:number):void => { + if (index > stepsCount.value || index < 0) index = 0 + stepIndex.value = index + if (!showSteps.value) { + showSteps.value = true + nextTick(() => { + updateGuidePosition() + }) + } else { + updateGuidePosition() + } + } + return { + showSteps, + closeSteps, + setCurrentIndex + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts new file mode 100644 index 0000000000000000000000000000000000000000..6120300ee6ee1e5ec239de11419aa95a81c50f17 --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts @@ -0,0 +1,78 @@ +import { Ref, ref, reactive, computed, nextTick } from 'vue' +import { Step, positionConf } from '../src/steps-guide-types' + +export function useStepsGuideNav(steps: Step[], stepIndex:Ref<number>) { + + const currentStep = computed<Step>(() => { + const _step = steps[stepIndex.value] + _step.position = _step.position || 'top' + return _step + }) + const guideClassList = ['devui-steps-guide'] + const stepsRef = ref(null) + const guidePosition = reactive({ + left: '', + top: '', + zIndex: 1100 + }) + const updateGuidePosition = () => { + const baseTop = window.pageYOffset - document.documentElement.clientTop + const baseLeft = window.pageXOffset - document.documentElement.clientLeft + const currentStepPosition:positionConf = currentStep.value.position + const stepGuideElement = stepsRef.value + let _left, _top + // 自定义 position位置 + if (typeof currentStepPosition !== 'string') { + const { top = 0, left = 0, type = 'top' } = currentStepPosition + guideClassList.splice(1, 1, type) + _left = left + _top = top + } else { + guideClassList.splice(1, 1, currentStepPosition) + const triggerSelector = currentStep.value.target || currentStep.value.trigger + const triggerElement = document.querySelector(triggerSelector) + const targetRect = triggerElement.getBoundingClientRect() + _left = targetRect.left + triggerElement.clientWidth / 2 - stepGuideElement.clientWidth / 2 + baseLeft + _top = targetRect.top + triggerElement.clientHeight / 2 - stepGuideElement.clientHeight / 2 + baseTop + + const positionTypes = currentStepPosition.split('-') + switch (positionTypes[0]) { + case 'top': + _top += (-stepGuideElement.clientHeight / 2 - triggerElement.clientHeight) + break + case 'bottom': + _top += (stepGuideElement.clientHeight / 2 + triggerElement.clientHeight) + break + case 'left': + _top += (stepGuideElement.clientHeight / 2 - triggerElement.clientHeight) + _left += (-stepGuideElement.clientWidth / 2 - triggerElement.clientWidth / 2) + break + case 'right': + _top += (stepGuideElement.clientHeight / 2 - triggerElement.clientHeight) + _left += (stepGuideElement.clientWidth / 2 + triggerElement.clientWidth / 2) + break + } + switch (positionTypes[1]) { + case 'left': + _left += (stepGuideElement.clientWidth / 2 - triggerElement.clientWidth / 2) + break + case 'right': + _left += (-stepGuideElement.clientWidth / 2 + triggerElement.clientWidth / 2) + break + } + } + guidePosition.left = _left + 'px' + guidePosition.top = _top + 'px' + nextTick(() => { + // 位置更新后滚动视图 + stepGuideElement.scrollIntoView({behavior: "smooth", block: "nearest", inline: "nearest"}) + }) + } + return { + currentStep, + stepsRef, + guidePosition, + guideClassList, + updateGuidePosition + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/steps-guide/index.ts b/packages/devui-vue/devui/steps-guide/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e41d4912f03cb0733cabf48331284f71b49e903 --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import StepsGuide from './src/steps-guide' + +StepsGuide.install = function(app: App): void { + app.component(StepsGuide.name, StepsGuide) +} + +export { StepsGuide } + +export default { + title: 'StepsGuide 操作指引', + category: '导航', + status: '50%', + install(app: App): void { + app.use(StepsGuide as any) + } +} diff --git a/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts b/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c712312b44318ff434c7a147053621fcb008516 --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts @@ -0,0 +1,27 @@ +import type { ExtractPropTypes, PropType } from 'vue' +type positionType = 'top-left' | 'top' | 'top-right' | 'left' | 'right' | 'bottom-left' | 'bottom' | 'bottom-right' +export type positionConf = { + left: number + top: number + type: string +} | positionType +export type Step = { + title: string + content: string + trigger: string + target?: string + position?: positionConf +} +export const stepsGuideProps = { + steps: Array as PropType<Step[]>, + showClose: { + type: Boolean, + default: true + }, + showDots: { + type: Boolean, + default: true + } +} as const + +export type StepsGuideProps = ExtractPropTypes<typeof stepsGuideProps> diff --git a/packages/devui-vue/devui/steps-guide/src/steps-guide.scss b/packages/devui-vue/devui/steps-guide/src/steps-guide.scss new file mode 100644 index 0000000000000000000000000000000000000000..a3d28a7684dfa7ab1bfc4d0de3ec2f136020725e --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/src/steps-guide.scss @@ -0,0 +1,249 @@ +$devui-font-size: 12px; +$devui-border-radius: 4px; +$devui-light-text: #ffffff; +$devui-brand:#5e7ce0; +$devui-shadow-length-feedback-overlay: var(--devui-shadow-length-feedback-overlay, 0 4px 16px 0); +$devui-border-radius-feedback: var(--devui-border-radius-feedback, 4px); +$devui-font-size-page-title: 12px; + +.devui-steps-guide { + width: 400px; + min-height: 160px; + background: $devui-brand; + box-shadow: $devui-shadow-length-feedback-overlay rgba(81, 112, 255, 0.3); + border-radius: $devui-border-radius-feedback; + font-size: $devui-font-size; + color: $devui-light-text; + padding: 20px; + position: absolute; + + .devui-title { + font-size: $devui-font-size-page-title; + opacity: 1; + margin: 0 0 20px 0; + padding: 0; + } + + > .devui-arrow, + > .devui-arrow::after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } + + > .devui-arrow { + border-width: 8px; + } + + &.left > .devui-arrow { + top: 23px; + right: -6px; + margin-top: -3px; + border-right-width: 0; + transform: rotate(-135deg); + border-left-color: $devui-brand; + } + + &.top > .devui-arrow, + &.top-left > .devui-arrow, + &.top-right > .devui-arrow { + bottom: -6px; + border-bottom-width: 0; + border-top-color: $devui-brand; + transform: rotate(135deg); + } + + &.top > .devui-arrow { + left: calc(50% - 4px); + } + + &.top-left > .devui-arrow { + left: 23px; + } + + &.top-right > .devui-arrow { + right: 23px; + transform: rotate(-135deg); + } + + &.right > .devui-arrow { + top: 23px; + left: -6px; + margin-top: -3px; + border-left-width: 0; + transform: rotate(135deg); + border-right-color: $devui-brand; + } + + &.bottom > .devui-arrow, + &.bottom-left > .devui-arrow, + &.bottom-right > .devui-arrow { + top: -6px; + margin-left: 3px; + border-top-width: 0; + border-bottom-color: $devui-brand; + } + + &.bottom > .devui-arrow { + left: calc(50% - 4px); + transform: rotate(-135deg); + } + + &.bottom-right > .devui-arrow { + right: 23px; + transform: rotate(135deg); + } + + &.bottom-left > .devui-arrow { + left: 23px; + transform: rotate(-135deg); + } + + > .devui-shining-dot, + .devui-shining-plus { + position: absolute; + background: $devui-brand; + width: 6px; + height: 6px; + border-radius: $devui-border-radius-feedback; + } + + &.left > .devui-shining-dot, + &.left > .devui-shining-plus { + top: 21px; + right: -30px; + } + + &.right > .devui-shining-dot, + &.right > .devui-shining-plus { + top: 21px; + left: -30px; + } + + &.top > .devui-shining-dot, + &.top > .devui-shining-plus { + left: calc(50% - 3px); + bottom: -30px; + } + + &.top-left > .devui-shining-dot, + &.top-left > .devui-shining-plus { + left: 21px; + bottom: -30px; + } + + &.top-right > .devui-shining-dot, + &.top-right > .devui-shining-plus { + right: 21px; + bottom: -30px; + } + + &.bottom > .devui-shining-dot, + &.bottom > .devui-shining-plus { + left: calc(50% - 3px); + top: -30px; + } + + &.bottom-right > .devui-shining-dot, + &.bottom-right > .devui-shining-plus { + top: -30px; + right: 21px; + } + + &.bottom-left > .devui-shining-dot, + &.bottom-left > .devui-shining-plus { + top: -30px; + left: 21px; + } + + .devui-shining-plus { + animation: devui-glow 2s 0s infinite; + } + + .devui-guide-container { + position: relative; + + > .icon-close { + position: absolute; + top: 0; + right: 0; + cursor: pointer; + } + + .devui-ctrl { + display: flex; + flex-wrap: wrap; + + .devui-dots { + color: $devui-light-text; + position: relative; + top: 25px; + font-size: $devui-font-size; + height: 30px; + + > em { + opacity: 0.2; + margin: 0 5px 0 2px; + + &.devui-active { + opacity: 1; + } + } + } + + .devui-guide-btn { + display: flex; + flex-flow: row nowrap; + flex-grow: 1; + justify-content: flex-end; + padding: 20px 0 0 0; + white-space: nowrap; + + > div { + color: $devui-light-text; + background: rgba(255, 255, 255, 0.1); + border-radius: $devui-border-radius; + padding: 5px 15px; + cursor: pointer; + margin-left: 10px; + + &.devui-prev-step { + background: none; + border: solid 1px rgba(255, 255, 255, 0.1); + } + } + } + } + } +} + +/* 以下定义动画帧 */ +@keyframes devui-glow { + 0% { + transform: scale(1); + opacity: 0.5; + } + + 25% { + transform: scale(2); + opacity: 0.3; + } + + 50% { + transform: scale(3); + opacity: 0.1; + } + + 75% { + transform: scale(2); + opacity: 0.3; + } + + 100% { + transform: scale(1); + opacity: 0.5; + } +} diff --git a/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx b/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx new file mode 100644 index 0000000000000000000000000000000000000000..93cf84bde5af5c8d04b8d810404c949f10fdd881 --- /dev/null +++ b/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx @@ -0,0 +1,81 @@ +import './steps-guide.scss' + +import { defineComponent, Teleport, ref, onMounted, computed } from 'vue' +import { stepsGuideProps, StepsGuideProps } from './steps-guide-types' +import { useStepsGuideNav, useStepsGuideCtrl } from '../hooks' +export default defineComponent({ + name: 'DStepsGuide', + props: stepsGuideProps, + emits: [], + setup(props: StepsGuideProps, ctx) { + const stepsCount = computed<number>(() => props.steps.length - 1) + const stepIndex = ref<number>(0) + const { + currentStep, + stepsRef, + guidePosition, + guideClassList, + updateGuidePosition } = useStepsGuideNav(props.steps, stepIndex) + const { showSteps, + closeSteps, + setCurrentIndex } = useStepsGuideCtrl(stepsCount, stepIndex, updateGuidePosition) + + onMounted(() => { + updateGuidePosition() + }) + + return { + stepsCount, + stepIndex, + showSteps, + guidePosition, + guideClassList, + stepsRef, + currentStep, + setCurrentIndex, + closeSteps + } + }, + render(props) { + const { showSteps, + guidePosition, + guideClassList, + currentStep, + stepIndex, + stepsCount, + setCurrentIndex, + closeSteps, + showClose, + showDots } = props + + return showSteps ? + (<Teleport to="body"> + <div style={guidePosition} class={guideClassList} ref="stepsRef"> + <div class="devui-shining-dot"></div> + <div class="devui-shining-plus"></div> + <div class="devui-arrow"></div> + <div class="devui-guide-container"> + <p class="devui-title">{currentStep.title}</p> + {showClose ? <div class="icon icon-close" onClick={closeSteps}></div> : null} + <div class="devui-content">{currentStep.content}</div> + <div class="devui-ctrl"> + { + showDots ? + <div class="devui-dots"> + {props.steps.map((step, index) => { + return <em class={ ['icon icon-dot-status', currentStep === step ? 'devui-active' : ''] } key={ index }></em> + })} + </div> : null + } + <div class="devui-guide-btn"> + {stepIndex > 0 ? <div class="devui-prev-step" onClick={() => setCurrentIndex(--props.stepIndex)}>{'上一步'}</div> : null} + {stepIndex === stepsCount ? + <div onClick={closeSteps}>{'我知道啦'}</div> : + <div class="devui-next-step" onClick={() => { setCurrentIndex(++props.stepIndex) }}>{'我知道啦,继续'}</div>} + </div> + </div> + </div> + </div> + </Teleport>) : null + } +}) diff --git a/packages/devui-vue/devui/sticky/index.ts b/packages/devui-vue/devui/sticky/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6e10417ce102291222b63adffe0163577a20656 --- /dev/null +++ b/packages/devui-vue/devui/sticky/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Sticky from './src/sticky' + +Sticky.install = function(app: App): void { + app.component(Sticky.name, Sticky) +} + +export { Sticky } + +export default { + title: 'Sticky 便贴', + category: '通用', + status: '50%', + install(app: App): void { + app.use(Sticky as any) + } +} diff --git a/packages/devui-vue/devui/sticky/src/sticky.tsx b/packages/devui-vue/devui/sticky/src/sticky.tsx new file mode 100644 index 0000000000000000000000000000000000000000..95d733e7cdaa01f041b2d3ab456c02efd502e628 --- /dev/null +++ b/packages/devui-vue/devui/sticky/src/sticky.tsx @@ -0,0 +1,252 @@ +import { defineComponent, onMounted, reactive, ref, watch, PropType } from 'vue' + + +export default defineComponent({ + name: 'DSticky', + props: { + zIndex: { + type: Number, + }, + container: { + type: Object as PropType<Element> + }, + view: { + type: Object, + default: () => { return { top: 0, bottom: 0 } }, + }, + scrollTarget: { + type: Object as PropType<Element> + }, + }, + emits: ['statusChange'], + setup(props, ctx) { + const { slots } = ctx + let container: Element + let scrollTarget: Element | Window + + let scrollTimer: any + let scrollPreStart: number | null + + const THROTTLE_DELAY = 16; + const THROTTLE_TRIGGER = 100; + + let parentNode: Element + let containerLeft = 0 + + const state = reactive({ + status: 'normal' + }) + + watch( + () => props.zIndex, + () => { + init() + } + ); + watch( + () => props.container, + () => { + init() + } + ); + watch( + () => props.scrollTarget, + () => { + init() + } + ); + watch( + () => state.status, + () => { + ctx.emit('statusChange', state.status) + }, + { immediate: true } + ); + + const init = () => { + parentNode = stickyRef.value.parentElement + if (!props.container) { + container = parentNode; + } else { + container = props.container + } + + stickyRef.value.style.zIndex = props.zIndex + + scrollTarget = props.scrollTarget || window; + scrollTarget.addEventListener('scroll', throttle); + + initScrollStatus(scrollTarget); + } + + // 初始化,判断位置,如果有滚用动则用handler处理 + const initScrollStatus = (target: any) => { + const scrollTargets = target === window ? + [document.documentElement, document.body] : [target]; + let flag = false; + scrollTargets.forEach((scrollTarget) => { + if (scrollTarget.scrollTop && scrollTarget.scrollTop > 0) { + flag = true; + } + }); + if (flag) { + setTimeout(scrollHandler); + } + } + + + const statusProcess = (status: any) => { + const wrapper = stickyRef.value || document.createElement('div') + switch (status) { + case 'normal': + wrapper.style.top = 'auto'; + wrapper.style.left = 'auto'; + wrapper.style.position = 'static'; + break; + case 'follow': + const scrollTargetElement: any = scrollTarget + const viewOffset = scrollTarget && scrollTarget !== window ? + scrollTargetElement.getBoundingClientRect().top : 0; + wrapper.style.top = +viewOffset + ((props.view && props.view.top) || 0) + 'px'; + wrapper.style.left = wrapper.getBoundingClientRect().left + 'px'; + wrapper.style.position = 'fixed'; + break; + case 'stay': + wrapper.style.top = calculateRelativePosition(wrapper, parentNode, 'top') + 'px'; + wrapper.style.left = 'auto'; + wrapper.style.position = 'relative'; + break; + case 'remain': + if (wrapper.style.position !== 'fixed' && wrapper.style.position !== 'absolute') { + wrapper.style.top = calculateRelativePosition(wrapper, parentNode, 'top') + 'px'; + wrapper.style.left = 'auto'; + wrapper.style.position = 'absolute'; + } + wrapper.style.top = + calculateRemainPosition(wrapper, parentNode, container) + 'px'; + wrapper.style.left = calculateRelativePosition(wrapper, parentNode, 'left') + 'px'; + wrapper.style.position = 'relative'; + break; + default: + break; + } + } + + const throttle = () => { + const fn = scrollAndResizeHock; + const time = Date.now(); + if (scrollTimer) { + clearTimeout(scrollTimer); + } + if (!scrollPreStart) { + scrollPreStart = time; + } + if (time - scrollPreStart > THROTTLE_TRIGGER) { + fn(); + scrollPreStart = null; + scrollTimer = null; + } else { + scrollTimer = setTimeout(() => { + fn(); + scrollPreStart = null; + scrollTimer = null; + }, THROTTLE_DELAY); + } + } + + const scrollAndResizeHock = () => { + if (container.getBoundingClientRect().left - (containerLeft || 0) !== 0) { + state.status = 'stay'; + containerLeft = container.getBoundingClientRect().left; + } else { + scrollHandler(); + } + } + + const scrollHandler = () => { + const scrollTargetElement: any = scrollTarget + const wrapper = stickyRef.value || document.createElement('div') + const viewOffsetTop = scrollTarget && scrollTarget !== window ? + scrollTargetElement.getBoundingClientRect().top : 0; + const computedStyle = window.getComputedStyle(container); + if (parentNode.getBoundingClientRect().top - viewOffsetTop > ((props.view && props.view.top) || 0)) { + state.status = 'normal'; + statusProcess(state.status); + } else if ( + container.getBoundingClientRect().top + + parseInt(computedStyle.paddingTop, 10) + + parseInt(computedStyle.borderTopWidth, 10) - + viewOffsetTop >= + ((props.view && props.view.top) || 0) + ) { + state.status = 'normal'; + statusProcess(state.status); + } else if ( + container.getBoundingClientRect().bottom - + parseInt(computedStyle.paddingBottom, 10) - + parseInt(computedStyle.borderBottomWidth, 10) < + viewOffsetTop + + ((props.view && props.view.top) || 0) + + wrapper.getBoundingClientRect().height + + ((props.view && props.view.bottom) || 0) + ) { + state.status = 'remain'; + statusProcess(state.status); + } else if ( + container.getBoundingClientRect().top + parseInt(computedStyle.paddingTop, 10) - viewOffsetTop < + ((props.view && props.view.top) || 0) + ) { + state.status = 'follow'; + statusProcess(state.status); + } + } + + + const calculateRelativePosition = (element: any, relativeElement: any, direction: 'left' | 'top') => { + const key = { + left: ['left', 'Left'], + top: ['top', 'Top'], + }; + if (window && window.getComputedStyle) { + const computedStyle = window.getComputedStyle(relativeElement); + return ( + element.getBoundingClientRect()[key[direction][0]] - + relativeElement.getBoundingClientRect()[key[direction][0]] - + parseInt(computedStyle[direction === 'left' ? 'paddingLeft' : 'paddingTop'], 10) - + parseInt(computedStyle[direction === 'left' ? 'borderLeftWidth' : 'borderTopWidth'], 10) + ); + } + } + + const calculateRemainPosition = (element: any, relativeElement: any, container: any) => { + if (window && window.getComputedStyle) { + const computedStyle = window.getComputedStyle(container); + const result = + container.getBoundingClientRect().height - + element.getBoundingClientRect().height + + container.getBoundingClientRect().top - + relativeElement.getBoundingClientRect().top - + parseInt(computedStyle['paddingTop'], 10) - + parseInt(computedStyle['borderTopWidth'], 10) - + parseInt(computedStyle['paddingBottom'], 10) - + parseInt(computedStyle['borderBottomWidth'], 10); + return result < 0 ? 0 : result; + } + } + + onMounted(() => { + init() + }) + + const stickyRef = ref() + + + return () => { + return ( + <div ref={stickyRef}> + {slots.default ? slots.default() : ''} + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/style/core/_animation.scss b/packages/devui-vue/devui/style/core/_animation.scss new file mode 100644 index 0000000000000000000000000000000000000000..0dda3d1d0c81e6368f141aa2f18b661587d73621 --- /dev/null +++ b/packages/devui-vue/devui/style/core/_animation.scss @@ -0,0 +1 @@ +@import '../../style/theme/animation' diff --git a/devui/style/core/_cdk.scss b/packages/devui-vue/devui/style/core/_cdk.scss similarity index 99% rename from devui/style/core/_cdk.scss rename to packages/devui-vue/devui/style/core/_cdk.scss index 9876b4992d9f62ec0d3123b892dd9c51b422ca16..773f9abc632869eedfe8564699bec86b2843df4d 100755 --- a/devui/style/core/_cdk.scss +++ b/packages/devui-vue/devui/style/core/_cdk.scss @@ -1,5 +1,4 @@ // @import '~@angular/cdk/overlay-prebuilt'; - .cdk-overlay-container { z-index: 1051; // 比modal z-index:1050;高 } diff --git a/devui/style/core/_common.scss b/packages/devui-vue/devui/style/core/_common.scss similarity index 100% rename from devui/style/core/_common.scss rename to packages/devui-vue/devui/style/core/_common.scss diff --git a/devui/style/core/_dropdown.scss b/packages/devui-vue/devui/style/core/_dropdown.scss similarity index 98% rename from devui/style/core/_dropdown.scss rename to packages/devui-vue/devui/style/core/_dropdown.scss index a4332380bda053d9e8dd811cd61188618ad5fb85..f6e6defa90af4388ee0952f12c7d45e0c345b40a 100755 --- a/devui/style/core/_dropdown.scss +++ b/packages/devui-vue/devui/style/core/_dropdown.scss @@ -46,8 +46,8 @@ top: calc(100% - 1px); left: 0; z-index: 1000; - display: none; min-width: calc(min(100%, 102px)); + margin: 4px 0; padding-bottom: 5px; background-clip: padding-box; border-radius: 2px; @@ -66,9 +66,9 @@ margin-bottom: -1px; } - .open > & { - display: block; - } + // .open > & { + // display: block; + // } > li { position: relative; diff --git a/devui/style/core/_font.scss b/packages/devui-vue/devui/style/core/_font.scss similarity index 100% rename from devui/style/core/_font.scss rename to packages/devui-vue/devui/style/core/_font.scss diff --git a/devui/style/core/_form.scss b/packages/devui-vue/devui/style/core/_form.scss similarity index 72% rename from devui/style/core/_form.scss rename to packages/devui-vue/devui/style/core/_form.scss index 191408c86ae7e83c66fdc1fda2dd0b772b367928..1be1406bad56c6cd39c281a64aa885d43225b41c 100755 --- a/devui/style/core/_form.scss +++ b/packages/devui-vue/devui/style/core/_form.scss @@ -1,16 +1,35 @@ @import '../theme/color.scss'; -@import './font'; +@import '../theme/shadow'; +@import '../theme/corner'; +@import '../theme/font'; @mixin border-position-radius($position: left) { border-top-#{$position}-radius: 0; border-bottom-#{$position}-radius: 0; } +$border-change-time: 300ms; +$border-change-function: cubic-bezier(0.645, 0.045, 0.355, 1); + +@mixin border-transition { + transition: border-color $border-change-time $border-change-function; +} .devui-form-controls input[type='text'], .devui-form-controls input[type='password'], -[dTextInput] { +[dInput] { width: 100%; height: 28px; + font-size: $devui-font-size; + + &.devui-input-sm { + font-size: $devui-font-size-sm; + height: 26px; + } + + &.devui-input-lg { + font-size: $devui-font-size-lg; + height: 46px; + } } [dTextArea] { @@ -18,16 +37,17 @@ } .devui-form-controls textarea, -[dTextInput], +[dInput], [dTextarea] { box-sizing: border-box; padding: 4px 10px; color: $devui-text; vertical-align: middle; border: 1px solid $devui-form-control-line; - border-radius: 2px; + border-radius: $devui-border-radius; outline: none; background-color: $devui-base-bg; + @include border-transition(); &:not([disabled]):not(.disabled):not(.devui-disabled):not(.error):not(.devui-error) { &:hover { @@ -66,7 +86,7 @@ .devui-input-group-addon { border: 1px solid $devui-form-control-line; - border-radius: 2px; + border-radius: $devui-border-radius; display: table-cell; padding: 0 10px; text-align: center; @@ -88,7 +108,7 @@ outline: none; background-color: $devui-base-bg; border: 1px solid $devui-form-control-line; - border-radius: 2px; + border-radius: $devui-border-radius; padding: 5px 10px; line-height: 16px; // 解决ie中文字不居中,由于height28px,有10px的padding和2px的border,剩余16px,使用其他的会使文字不居中 font-size: $devui-font-size; @@ -97,6 +117,7 @@ display: block; cursor: text; height: 28px; + @include border-transition; &:hover { border-color: $devui-form-control-line-hover; @@ -187,8 +208,9 @@ display: block; width: 100%; height: 28px; - border-radius: 2px; + border-radius: $devui-border-radius; outline: 0; + @include border-transition; &[disabled], &.disabled, @@ -216,92 +238,46 @@ } } -:not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled) { - > .devui-dropdown-origin { - position: relative; - z-index: 1; - } - - > .devui-dropdown-origin:hover:not([disabled]):not(.disabled):not(.devui-disabled):not(:focus):not(.devui-dropdown-origin-open) { - border-color: $devui-form-control-line-hover; - } +:not(.multiple-label-auto-complete-disabled):not(.devui-error) { + > .devui-dropdown-origin:not(d-button):not(.icon):not([class^='icon-']):not([disabled]):not(.disabled):not(.devui-disabled) { + &:not(.devui-dropdown-no-border):not(.devui-no-border) { + border-color: $devui-form-control-line; + @include border-transition; - > .devui-dropdown-origin:focus:not([disabled]):not(.disabled):not(.devui-disabled) { - outline: none; - border-color: $devui-form-control-line-active; - - &:not(.devui-select-underlined-border):not(.devui-dropdown-no-border) { - box-shadow: 0 2px 5px 0 $devui-shadow; - } - } - - > .devui-dropdown-origin.devui-dropdown-origin-open:not([disabled]):not(.disabled):not(.devui-disabled) { - outline: none; - border-color: $devui-connected-overlay-line; - border-radius: 2px 2px 0 0; - - &:not(.devui-select-underlined-border):not(.devui-dropdown-no-border) { - box-shadow: 0 2px 5px 0 $devui-shadow; - } - } - - > .devui-dropdown-origin.devui-dropdown-origin-open:not(.devui-no-border):not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-dropdown-no-border) { - z-index: 1052; // 为了让dividing边框覆盖cdk边框颜色 - - & ~ .devui-form-control-feedback { - z-index: 1052; - } - - &.devui-dropdown-origin-bottom { - border-bottom-color: $devui-dividing-line; - box-shadow: none; - - &::after { - content: ''; - width: 100%; - height: 1px; - background-color: $devui-dividing-line; - position: absolute; - z-index: 1001; - left: 0; - top: 100%; + &:hover:not(:focus):not(.devui-dropdown-origin-open) { + border-color: $devui-form-control-line-hover; } - } - - &.devui-dropdown-origin-top { - border-top-color: $devui-dividing-line; - &:not(.devui-select-underlined-border) { - box-shadow: 0 2px 5px 0 $devui-shadow; + &:focus, + &:focus-within { + outline: none; + border-color: $devui-form-control-line-active; } - &::after { - content: ''; - width: 100%; - height: 1px; - background-color: $devui-dividing-line; - position: absolute; - z-index: 1001; - left: 0; - top: -1px; + &.devui-dropdown-origin-open { + outline: none; + border-color: $devui-connected-overlay-line; } } } } -.devui-dropdown-origin-wrapper { - color: $devui-text; - background-color: $devui-base-bg; +.devui-dropdown-origin:not(d-button):not(.icon):not([class^='icon-']) { min-height: 28px; + &:not([disabled]):not(.disabled):not(.devui-disabled) { + color: $devui-text; + } + & > .devui-input, & > .devui-form-control { height: 26px; } - &:not(.devui-select-underlined-border) { - border: 1px solid $devui-form-control-line; - border-radius: 2px; + &:not(.devui-select-underlined-border):not(.devui-dropdown-no-border):not(.devui-no-border) { + border-radius: $devui-border-radius; + border-width: 1px; + border-style: solid; } .devui-form-control, @@ -315,8 +291,6 @@ > .devui-dropdown-default:hover, > .devui-dropdown-default:active, > .devui-dropdown-default:focus { - position: relative; - z-index: 1001; border-color: transparent; } @@ -335,20 +309,6 @@ background-color: $devui-disabled-bg; } } - - &:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-error) { - .devui-form-control:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-error), - .devui-form-control:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-error):hover, - .devui-form-control:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-error):focus, - .devui-form-control:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-error):focus:hover, - .devui-input-group-addon, - > .devui-dropdown-default, - > .devui-dropdown-default:hover, - > .devui-dropdown-default:active, - > .devui-dropdown-default:focus { - background-color: $devui-base-bg; - } - } } // css选择器不可合并,否则css解析器总是会失败 @@ -367,9 +327,9 @@ input::-webkit-input-placeholder { /* status style start */ /* border color and background */ -[dTextInput]:not([disabled]):not(.disabled):not(.devui-disabled).error, +[dInput]:not([disabled]):not(.disabled):not(.devui-disabled).error, [dTextarea]:not([disabled]):not(.disabled):not(.devui-disabled).error, -[dTextInput]:not([disabled]):not(.disabled):not(.devui-disabled).devui-error, +[dInput]:not([disabled]):not(.disabled):not(.devui-disabled).devui-error, [dTextarea]:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { border-color: $devui-danger-line; background-color: $devui-danger-bg; @@ -379,9 +339,9 @@ input::-webkit-input-placeholder { background-color: $devui-danger-bg; } -d-select:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled).devui-error { - div.devui-dropdown-origin.devui-dropdown-origin-wrapper.devui-dropup, - div.devui-dropdown-origin.devui-dropdown-origin-wrapper.devui-dropdown { +d-select:not([disabled]):not(.disabled):not(.devui-disabled):not(.multiple-label-auto-complete-disabled).devui-error { + div.devui-dropdown-origin.devui-dropup, + div.devui-dropdown-origin.devui-dropdown { border-color: $devui-danger-line; .devui-form-group .devui-input.devui-form-control.devui-select-input:not(.devui-select-search), @@ -392,7 +352,7 @@ d-select:not([disabled]):not(.disabled):not(.devui-disabled):not(.devui-dropdown } d-editable-select:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { - .devui-form-group:not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled) { + .devui-form-group:not(.multiple-label-auto-complete-disabled) { input.devui-form-control.devui-dropdown-origin { border-color: $devui-danger-line; background-color: $devui-danger-bg; /* TODO: open时,下边框颜色 */ @@ -400,6 +360,28 @@ d-editable-select:not([disabled]):not(.disabled):not(.devui-disabled).devui-erro } } +d-datepicker-pro:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { + .devui-datepicker-pro-wrapper:not([disabled]):not(.disabled):not(.devui-disabled) .devui-dropdown-toggle .devui-single-picker { + border-color: $devui-danger-line; + background-color: $devui-danger-bg; + + .devui-input:not(.devui-disabled) { + background-color: $devui-danger-bg; + } + } +} + +d-range-datepicker-pro:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { + .devui-datepicker-pro-wrapper:not([disabled]):not(.disabled):not(.devui-disabled) .devui-dropdown-toggle .devui-range-picker { + border-color: $devui-danger-line; + background-color: $devui-danger-bg; + + .devui-input:not(.devui-disabled) { + background-color: $devui-danger-bg; + } + } +} + d-input-number:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { .input-box:not(:disabled) { border-color: $devui-danger-line; @@ -408,7 +390,7 @@ d-input-number:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { } d-multi-auto-complete:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { - :not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled) { + :not(.multiple-label-auto-complete-disabled) { &.multiple-label-auto-complete.multiple-label-auto-complete-border ul.devui-dropdown-origin { border-color: $devui-danger-line; background-color: $devui-danger-bg; @@ -421,7 +403,7 @@ d-multi-auto-complete:not([disabled]):not(.disabled):not(.devui-disabled).devui- } d-tags-input:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { - :not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled) { + :not(.multiple-label-auto-complete-disabled) { div.devui-tags.devui-form-control { border-color: $devui-danger-line; background-color: $devui-danger-bg; @@ -434,7 +416,7 @@ d-tags-input:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { } d-tree-select:not([disabled]):not(.disabled):not(.devui-disabled).devui-error { - :not(.devui-dropdown-origin-wrapper):not(.multiple-label-auto-complete-disabled) { + :not(.multiple-label-auto-complete-disabled) { & > div.devui-select-input.devui-dropdown-origin.devui-tree-select-input { border-color: $devui-danger-line; background-color: $devui-danger-bg; /* TODO: open时,下边框颜色 */ @@ -467,8 +449,22 @@ d-form-control { } } +.devui-form-controls.devui-form-control-has-suffix { + [dInput], + [dTextArea] { + padding-right: 28px; + } +} + +.devui-form-controls.devui-form-control-has-suffix.devui-form-control-has-feedback { + [dInput], + [dTextArea] { + padding-right: 56px; + } +} + .devui-form-controls.devui-form-control-has-feedback { - [dTextInput], + [dInput], [dTextarea] { padding-right: 28px; } diff --git a/devui/style/core/_imagePreview.scss b/packages/devui-vue/devui/style/core/_imagePreview.scss similarity index 100% rename from devui/style/core/_imagePreview.scss rename to packages/devui-vue/devui/style/core/_imagePreview.scss diff --git a/devui/style/core/_index.scss b/packages/devui-vue/devui/style/core/_index.scss similarity index 100% rename from devui/style/core/_index.scss rename to packages/devui-vue/devui/style/core/_index.scss diff --git a/devui/style/core/_layout.scss b/packages/devui-vue/devui/style/core/_layout.scss similarity index 100% rename from devui/style/core/_layout.scss rename to packages/devui-vue/devui/style/core/_layout.scss diff --git a/devui/style/core/_normalize.scss b/packages/devui-vue/devui/style/core/_normalize.scss similarity index 100% rename from devui/style/core/_normalize.scss rename to packages/devui-vue/devui/style/core/_normalize.scss diff --git a/devui/style/core/_reset.scss b/packages/devui-vue/devui/style/core/_reset.scss similarity index 100% rename from devui/style/core/_reset.scss rename to packages/devui-vue/devui/style/core/_reset.scss diff --git a/devui/style/devui.scss b/packages/devui-vue/devui/style/devui.scss similarity index 100% rename from devui/style/devui.scss rename to packages/devui-vue/devui/style/devui.scss diff --git a/devui/style/layout/_config.scss b/packages/devui-vue/devui/style/layout/_config.scss similarity index 100% rename from devui/style/layout/_config.scss rename to packages/devui-vue/devui/style/layout/_config.scss diff --git a/devui/style/layout/devui-layout.scss b/packages/devui-vue/devui/style/layout/devui-layout.scss similarity index 100% rename from devui/style/layout/devui-layout.scss rename to packages/devui-vue/devui/style/layout/devui-layout.scss diff --git a/devui/style/mixins/_clearfix.scss b/packages/devui-vue/devui/style/mixins/_clearfix.scss similarity index 100% rename from devui/style/mixins/_clearfix.scss rename to packages/devui-vue/devui/style/mixins/_clearfix.scss diff --git a/packages/devui-vue/devui/style/mixins/_flex.scss b/packages/devui-vue/devui/style/mixins/_flex.scss new file mode 100644 index 0000000000000000000000000000000000000000..506eac1d8340a08cb50d556c120023e55fb57b0b --- /dev/null +++ b/packages/devui-vue/devui/style/mixins/_flex.scss @@ -0,0 +1,9 @@ +@mixin flex($justifyContent: center, $alignItem: center,) { + display: flex; + justify-content: $justifyContent; + align-items: $alignItem; +} + +@mixin flex-direction($direction: column) { + flex-direction: $direction; +} diff --git a/devui/style/mixins/_hover.scss b/packages/devui-vue/devui/style/mixins/_hover.scss similarity index 100% rename from devui/style/mixins/_hover.scss rename to packages/devui-vue/devui/style/mixins/_hover.scss diff --git a/devui/style/mixins/_index.scss b/packages/devui-vue/devui/style/mixins/_index.scss similarity index 100% rename from devui/style/mixins/_index.scss rename to packages/devui-vue/devui/style/mixins/_index.scss diff --git a/devui/style/mixins/_size.scss b/packages/devui-vue/devui/style/mixins/_size.scss similarity index 100% rename from devui/style/mixins/_size.scss rename to packages/devui-vue/devui/style/mixins/_size.scss diff --git a/packages/devui-vue/devui/style/theme/_animation.scss b/packages/devui-vue/devui/style/theme/_animation.scss new file mode 100644 index 0000000000000000000000000000000000000000..33d65e180d566145edc0bce6e1ab5a6f36f21d35 --- /dev/null +++ b/packages/devui-vue/devui/style/theme/_animation.scss @@ -0,0 +1,29 @@ +$devui-animation-duration-slow: var(--devui-animation-duration-slow, 300ms); +$devui-animation-duration-base: var(--devui-animation-duration-base, 200ms); +$devui-animation-duration-fast: var(--devui-animation-duration-fast, 100ms); + +$devui-animation-ease-in: var( + --devui-animation-ease-in, + cubic-bezier(0.5, 0, 0.84, 0.25) +); +$devui-animation-ease-out: var( + --devui-animation-ease-out, + cubic-bezier(0.16, 0.75, 0.5, 1) +); +$devui-animation-ease-in-out: var( + --devui-animation-ease-in-out, + cubic-bezier(0.5, 0.05, 0.5, 0.95) +); +$devui-animation-ease-in-smooth: var( + --devui-animation-ease-in-smooth, + cubic-bezier(0.645, 0.045, 0.355, 1) +); +// ng库中中把 $devui-animation-ease-in-smooth 重命名为了 $devui-animation-ease-in-out-smooth +$devui-animation-ease-in-out-smooth: var( + --devui-animation-ease-in-out-smooth, + cubic-bezier(0.645, 0.045, 0.355, 1) +); +$devui-animation-linear: var( + --devui-animation-linear, + cubic-bezier(0, 0, 1, 1) +); diff --git a/devui/style/theme/_color.scss b/packages/devui-vue/devui/style/theme/_color.scss similarity index 100% rename from devui/style/theme/_color.scss rename to packages/devui-vue/devui/style/theme/_color.scss diff --git a/devui/style/theme/_corner.scss b/packages/devui-vue/devui/style/theme/_corner.scss similarity index 100% rename from devui/style/theme/_corner.scss rename to packages/devui-vue/devui/style/theme/_corner.scss diff --git a/devui/style/theme/_font.scss b/packages/devui-vue/devui/style/theme/_font.scss similarity index 100% rename from devui/style/theme/_font.scss rename to packages/devui-vue/devui/style/theme/_font.scss diff --git a/devui/style/theme/_shadow.scss b/packages/devui-vue/devui/style/theme/_shadow.scss similarity index 82% rename from devui/style/theme/_shadow.scss rename to packages/devui-vue/devui/style/theme/_shadow.scss index a86b13c331a7dba9aaed874df0e7cb35f9bda5e9..313b2e33a44e6197d8a873a60c6134724a65e706 100644 --- a/devui/style/theme/_shadow.scss +++ b/packages/devui-vue/devui/style/theme/_shadow.scss @@ -4,7 +4,7 @@ $devui-shadow-length-base: var(--devui-shadow-length-base, 0 1px 4px 0); //直 $devui-shadow-length-slide-left: var(--devui-shadow-length-slide-left, -2px 0 8px 0); //向左滑动时出现在右侧边缘的阴影 (dataTable固定右侧列向左滑动) $devui-shadow-length-slide-right: var(--devui-shadow-length-slide-right, 2px 0 8px 0); //向右滑动时出现在左侧边缘的阴影 (dataTable固定左侧列向右滑动) -$devui-shadow-length-connected-overlay : var(--devui-shadow-connected-overlay, 0 2px 8px 0); //有连接点的弹出(覆盖)层 (DatePicker Cascader Select TagsInput Pagination的下拉菜单等) +$devui-shadow-length-connected-overlay: var(--devui-shadow-connected-overlay, 0 2px 8px 0); //有连接点的弹出(覆盖)层 (DatePicker Cascader Select TagsInput Pagination的下拉菜单等) $devui-shadow-length-hover : var(--devui-shadow-length-hover, 0 4px 16px 0); //涉及到hover的地方 $devui-shadow-length-feedback-overlay : var(--devui-shadow-length-feedback-overlay, 0 4px 16px 0); //信息提示反馈类 (PopOver Tooltip Toast StepsGuide等) diff --git a/devui/style/theme/_variables.scss b/packages/devui-vue/devui/style/theme/_variables.scss similarity index 100% rename from devui/style/theme/_variables.scss rename to packages/devui-vue/devui/style/theme/_variables.scss diff --git a/packages/devui-vue/devui/style/theme/_z-index.scss b/packages/devui-vue/devui/style/theme/_z-index.scss new file mode 100644 index 0000000000000000000000000000000000000000..7846b41414ae87c544e46862f137a13b798ca240 --- /dev/null +++ b/packages/devui-vue/devui/style/theme/_z-index.scss @@ -0,0 +1,12 @@ +// 临时层 +// 若存在遮罩,则遮罩基于对应z-index值-1 +$devui-z-index-full-page-overlay: var(--devui-z-index-full-page-overlay, 1080); // 全屏覆盖类元素 +$devui-z-index-dropdown: var(--devui-z-index-dropdown, 1052); // 下拉菜单,dropdown等 +$devui-z-index-pop-up: var(--devui-z-index-pop-up, 1060); // 提示类信息,popover,tooltip等 +$devui-z-index-modal: var(--devui-z-index-modal, 1050);// 弹窗, +$devui-z-index-drawer: var(--devui-z-index-drawer, 1040);// 抽屉板 +$devui-z-index-framework: var(--devui-z-index-framework, 1000);// 框架类元素,header,sideMenu等 + +// 内容层,根据需要设置,zIndex需小于临时层 + +// 背景层,根据需要设置,zIndex需小于内容层 diff --git a/packages/devui-vue/devui/styles-var/devui-var.scss b/packages/devui-vue/devui/styles-var/devui-var.scss new file mode 100644 index 0000000000000000000000000000000000000000..32fd62bc0ae3f1bb15327044f2f09fc9856b5e0d --- /dev/null +++ b/packages/devui-vue/devui/styles-var/devui-var.scss @@ -0,0 +1,6 @@ +@import '../style/theme/color'; +@import '../style/theme/font'; +@import '../style/theme/shadow'; +@import '../style/theme/corner'; +@import '../style/theme/animation'; +@import '../style/theme/z-index'; diff --git a/packages/devui-vue/devui/switch/__tests__/switch.spec.ts b/packages/devui-vue/devui/switch/__tests__/switch.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0871b575d067c61d732d71e27c4e2703f935618b --- /dev/null +++ b/packages/devui-vue/devui/switch/__tests__/switch.spec.ts @@ -0,0 +1,112 @@ +import { mount } from '@vue/test-utils'; +import { ref, nextTick } from 'vue'; +import DSwitch from '../src/switch'; + +describe('d-switch', () => { + it('switch render work', async () => { + const checked = ref(false); + const wrapper = mount({ + components: { DSwitch }, + template: ` + <d-switch v-model:checked="checked"></d-switch> + `, + setup () { + return { + checked + }; + } + }); + + expect(wrapper.classes()).toContain('devui-switch'); + expect(wrapper.classes()).not.toContain('devui-checked'); + + checked.value = true; + await nextTick(); + + expect(wrapper.classes()).toContain('devui-checked'); + }); + + it('switch disabled work', async () => { + const onChange = jest.fn(); + const wrapper = mount(DSwitch, { + props: { + disabled: true, + onChange + } + }); + + expect(wrapper.classes()).toContain('devui-disabled'); + + await wrapper.trigger('click'); + expect(onChange).toBeCalledTimes(0); + + await wrapper.setProps({ + disabled: false + }); + await wrapper.trigger('click'); + + expect(wrapper.classes()).not.toContain('devui-disabled'); + expect(onChange).toBeCalledTimes(1); + }); + + it('switch size work', async () => { + const wrapper = mount(DSwitch, { + props: { + size: 'small' + } + }); + + expect(wrapper.classes()).toContain('devui-switch-sm'); + + await wrapper.setProps({ + size: 'large' + }); + expect(wrapper.classes()).not.toContain('devui-switch-sm'); + expect(wrapper.classes()).toContain('devui-switch-lg'); + }); + + it('switch beforeChange work', async () => { + const beforeChange = jest.fn(() => false); + const onChange = jest.fn(); + const wrapper = mount(DSwitch, { + props: { + beforeChange, + onChange + } + }); + + await wrapper.trigger('click'); + expect(beforeChange).toBeCalledTimes(1); + expect(onChange).toBeCalledTimes(0); + + beforeChange.mockReturnValue(true); + await wrapper.trigger('click'); + expect(beforeChange).toBeCalledTimes(2); + expect(onChange).toBeCalledTimes(1); + }); + + it('switch slot work', async () => { + const isChecked = ref(false); + const wrapper = mount({ + components: { DSwitch }, + template: ` + <d-switch :checked="isChecked"> + <template v-slot:checkedContent>开</template> + <template v-slot:uncheckedContent>关</template> + </d-switch> + `, + setup () { + return { + isChecked + }; + } + }); + + expect(wrapper.text()).toBe('关'); + + isChecked.value = true; + await nextTick(); + + expect(wrapper.text()).toBe('开'); + }); +}); diff --git a/packages/devui-vue/devui/switch/index.ts b/packages/devui-vue/devui/switch/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f220103c1398dc5816aa631dd815804adc17259d --- /dev/null +++ b/packages/devui-vue/devui/switch/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Switch from './src/switch' + +Switch.install = function(app: App) { + app.component(Switch.name, Switch) +} + +export { Switch } + +export default { + title: 'Switch 开关', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(Switch as any) + } +} diff --git a/packages/devui-vue/devui/switch/src/switch.scss b/packages/devui-vue/devui/switch/src/switch.scss new file mode 100644 index 0000000000000000000000000000000000000000..c1c22ae1f1f5ea801a9d9c68aaf343407e848bd0 --- /dev/null +++ b/packages/devui-vue/devui/switch/src/switch.scss @@ -0,0 +1,178 @@ +@use 'sass:math'; + +@import '../../style/theme/color'; +@import '../../style/theme/font'; +@import '../../style/core/animation'; + +:host { + display: inline-block; + font-size: 0; + vertical-align: middle; +} + +.devui-switch { + width: 36px; + height: 18px; + border-radius: math.div(20px, 2); + background: $devui-line; + border: 1px solid $devui-line; + position: relative; + display: inline-block; + box-sizing: content-box; + overflow: visible; + padding: 0; + margin: 0; + margin-right: 5px; + cursor: pointer; + transition: $devui-animation-duration-slow $devui-animation-ease-in-smooth all; + + &:not(.devui-checked):hover { + border-color: $devui-line; + } + + &:active { + border-color: $devui-brand-active-focus; + } + + &.devui-checked:hover { + border-color: $devui-brand-active; + } + + .devui-switch-inner-wrapper { + display: inline-block; + width: 100%; + height: 100%; + padding-left: 16px; + font-size: $devui-font-size; + color: $devui-global-bg; + + .devui-switch-inner { + color: #ffffff; + font-weight: 700; + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + float: right; + } + } + + &.devui-checked .devui-switch-inner-wrapper { + padding-left: unset; + padding-right: 16px; + } + + small { + width: 16px; + height: 16px; + background: $devui-light-text; + border-radius: 100%; + position: absolute; + top: 1px; + left: 1px; + transition: $devui-animation-duration-slow $devui-animation-ease-in-smooth all; + } + + &.devui-checked small { + left: 19px; + } + + &.devui-switch-large { + width: 58px; + height: 30px; + border-radius: math.div(32px, 2); + + .devui-switch-inner-wrapper { + padding-left: 28px; + font-size: $devui-font-size-modal-title; + } + + &.devui-checked .devui-switch-inner-wrapper { + padding-left: unset; + padding-right: 28px; + } + + & small { + width: 28px; + height: 28px; + top: 1px; + left: 1px; + } + + &.devui-checked small { + background: $devui-light-text; + left: 29px; + } + } + + &.devui-switch-small { + width: 30px; + height: 14px; + border-radius: math.div(16px, 2); + + .devui-switch-inner-wrapper { + padding-left: 12px; + font-size: $devui-font-size; + } + + &.devui-checked .devui-switch-inner-wrapper { + padding-left: unset; + padding-right: 12px; + } + + & small { + width: 12px; + height: 12px; + position: absolute; + } + + &.devui-checked small { + left: 17px; + } + } + + &.devui-checked { + background: $devui-brand; + border-color: $devui-brand; + + &:hover { + background: $devui-brand-active; + border-color: $devui-brand-active; + } + + &:active { + background: $devui-brand-active-focus; + border-color: $devui-brand-active-focus; + } + } + + &.devui-disabled { + &, + &:hover, + &:active, + &.devui-checked { + cursor: not-allowed; + } + + &, + &:hover, + &:active { + background-color: $devui-disabled-line; + border-color: $devui-disabled-line; + + small { + background-color: $devui-unavailable; + } + } + + &.devui-checked { + background-color: $devui-icon-fill-active-disabled; + border-color: $devui-icon-fill-active-disabled; + + small { + background-color: $devui-light-text; + } + } + } +} diff --git a/packages/devui-vue/devui/switch/src/switch.tsx b/packages/devui-vue/devui/switch/src/switch.tsx new file mode 100644 index 0000000000000000000000000000000000000000..95e6902f15ccfd28265403f811b892d179ec71b8 --- /dev/null +++ b/packages/devui-vue/devui/switch/src/switch.tsx @@ -0,0 +1,98 @@ +import { defineComponent, PropType, renderSlot, useSlots } from 'vue'; +import './switch.scss'; + +const switchProps = { + size: { + type: String as PropType<'small' | 'middle' | 'large'>, + default: 'middle' + }, + color: { + type: String, + default: undefined + }, + checked: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + beforeChange: { + type: Function as PropType<(v: boolean) => boolean | Promise<boolean>>, + default: undefined + }, + change: { + type: Function as PropType<(v: boolean) => void>, + default: undefined + }, + 'onUpdate:checked': { + type: Function as PropType<(v: boolean) => void>, + default: undefined + } +} as const; + +export default defineComponent({ + name: 'DSwitch', + props: switchProps, + emits: ['change', 'update:checked'], + setup(props, ctx) { + const canChange = () => { + if (props.disabled) { + return Promise.resolve(false); + } + if (props.beforeChange) { + const res = props.beforeChange(!props.checked); + return typeof res === 'boolean' ? Promise.resolve(res) : res; + } + + return Promise.resolve(true); + }; + const toggle = () => { + canChange().then(res => { + if (!res) { + return; + } + ctx.emit('update:checked', !props.checked); + ctx.emit('change', !props.checked); + }); + }; + + return { + toggle + }; + }, + + render() { + const { + size, + checked, + disabled, + color, + toggle + } = this; + const outerCls = { + 'devui-switch': true, + [`devui-switch-${size}`]: size !== '', + 'devui-checked': checked, + 'devui-disabled': disabled + }; + const outerStyle = [ + `background: ${checked && !disabled ? color : ''}`, + `border-color: ${checked && !disabled ? color : ''}` + ]; + + const checkedContent = renderSlot(useSlots(), 'checkedContent') + const uncheckedContent = renderSlot(useSlots(), 'uncheckedContent') + return ( + <span class={outerCls} style={outerStyle} onClick={toggle}> + <span class="devui-switch-inner-wrapper"> + <div class="devui-switch-inner"> + {checked ? checkedContent : uncheckedContent} + </div> + </span> + <small></small> + </span> + ); + } +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/__tests__/table.spec.ts b/packages/devui-vue/devui/table/__tests__/table.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..35e37e75c5b4de5a4f51b7262d1b64e5eef3a8dc --- /dev/null +++ b/packages/devui-vue/devui/table/__tests__/table.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Table } from '../index'; + +describe('table test', () => { + it('table init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/table/index.ts b/packages/devui-vue/devui/table/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..30393dd6cdccd906504ec9a42a31def0f6b4d6ef --- /dev/null +++ b/packages/devui-vue/devui/table/index.ts @@ -0,0 +1,19 @@ +import type { App } from 'vue' +import Table from './src/table' +import Column from './src/column/column' + +Table.install = function(app: App): void { + app.component(Table.name, Table) + app.component(Column.name, Column) +} + +export { Table, Column } + +export default { + title: 'Table 表格', + category: '数据展示', + status: '10%', + install(app: App): void { + app.use(Table as any) + } +} diff --git a/packages/devui-vue/devui/table/src/body/body.scss b/packages/devui-vue/devui/table/src/body/body.scss new file mode 100644 index 0000000000000000000000000000000000000000..ea2657279dfcdaccd4f275b9704afe884975afe3 --- /dev/null +++ b/packages/devui-vue/devui/table/src/body/body.scss @@ -0,0 +1,20 @@ +@import '../../../styles-var/devui-var.scss'; + +.devui-tbody { + tr { + font-size: $devui-font-size-card-title; + color: $devui-text; + border: none; + border-bottom: 1px solid $devui-dividing-line; + background-color: $devui-global-bg-normal; + + &:hover { + background-color: $devui-list-item-hover-bg; + } + + td { + padding: 10px; + border: none; + } + } +} diff --git a/packages/devui-vue/devui/table/src/body/body.tsx b/packages/devui-vue/devui/table/src/body/body.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9b02b8679897d1deb3d3347c868d72b6e5ad4934 --- /dev/null +++ b/packages/devui-vue/devui/table/src/body/body.tsx @@ -0,0 +1,33 @@ +import { defineComponent } from 'vue'; +import { TableBodyProps, TableBodyPropsTypes } from './body.type' +import { useTableBody } from './use-body'; +import './body.scss'; + +export default defineComponent({ + name: 'DTableBody', + props: TableBodyProps, + setup(props: TableBodyPropsTypes) { + const { rowColumns } = useTableBody(props); + + return { rowColumns }; + }, + render() { + const { rowColumns } = this; + + return ( + <tbody class="devui-tbody"> + {rowColumns.map((row, rowIndex) => { + return ( + <tr key={rowIndex}> + {row.columns.map((column, index) => { + return ( + <td key={index}>{column.renderCell({ row, column, $index: index })}</td> + ); + })} + </tr> + ); + })} + </tbody> + ); + }, +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/body/body.type.ts b/packages/devui-vue/devui/table/src/body/body.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1febde00fb051c2b818c58fde03ba5004b0a021 --- /dev/null +++ b/packages/devui-vue/devui/table/src/body/body.type.ts @@ -0,0 +1,10 @@ +import { ExtractPropTypes } from 'vue'; + +export const TableBodyProps = { + store: { + type: Object, + default: {}, + }, +}; + +export type TableBodyPropsTypes = ExtractPropTypes<typeof TableBodyProps>; diff --git a/packages/devui-vue/devui/table/src/body/use-body.ts b/packages/devui-vue/devui/table/src/body/use-body.ts new file mode 100644 index 0000000000000000000000000000000000000000..1657a06b50646cc594957432254062c6035cd1a2 --- /dev/null +++ b/packages/devui-vue/devui/table/src/body/use-body.ts @@ -0,0 +1,15 @@ +import { computed } from 'vue'; +import { TableBodyPropsTypes } from './body.type' + +export function useTableBody(props: TableBodyPropsTypes): any { + const storeData = props.store.states; + const rowColumns = computed(() => { + return storeData._data.value.map((row) => { + const obj = Object.assign({}, row); + obj.columns = storeData._columns.value; + return obj; + }); + }); + + return { rowColumns }; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx b/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx new file mode 100644 index 0000000000000000000000000000000000000000..93e7197d8466045978538007fbb68379a8a8992b --- /dev/null +++ b/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx @@ -0,0 +1,23 @@ +import { inject, defineComponent } from 'vue'; +import { Table } from '../table.type'; +import { Column } from '../column/column.type'; + +export default defineComponent({ + name: 'DColGroup', + setup() { + const parent: Table = inject('table'); + const columns: Column[] = parent.store.states._columns; + + return { columns }; + }, + render() { + const { columns } = this; + return ( + <colgroup> + {columns.map((column, index) => { + return <col key={index} width={column.realWidth}></col>; + })} + </colgroup> + ); + }, +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/column/column.tsx b/packages/devui-vue/devui/table/src/column/column.tsx new file mode 100644 index 0000000000000000000000000000000000000000..60ef5e04cf8e85ae459d43673fd1ce60219978ab --- /dev/null +++ b/packages/devui-vue/devui/table/src/column/column.tsx @@ -0,0 +1,33 @@ +import { inject, defineComponent, onBeforeMount, onMounted } from 'vue'; +import { + Column, + TableColumnProps, + TableColumnPropsTypes, +} from './column.type' +import { Table } from '../table.type'; +import { useRender } from './use-column'; + +export default defineComponent({ + name: 'DColumn', + props: TableColumnProps, + setup(props: TableColumnPropsTypes) { + const column: Column = { + field: props.field, + header: props.header, + }; + const parent: Table = inject('table'); + const { setColumnWidth, setColumnRender } = useRender(props); + + onBeforeMount(() => { + setColumnWidth(column); + setColumnRender(column); + }); + + onMounted(() => { + parent.store.insertColumn(column); + }); + }, + render() { + return null; + }, +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/column/column.type.ts b/packages/devui-vue/devui/table/src/column/column.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..cdab04098202602701a11228536e6d9339695253 --- /dev/null +++ b/packages/devui-vue/devui/table/src/column/column.type.ts @@ -0,0 +1,38 @@ +import { PropType, ExtractPropTypes, VNode } from 'vue'; + +export const TableColumnProps = { + header: { + type: String, + default: '', + }, + field: { + type: String, + default: '', + }, + width: { + type: [String, Number], + default: '', + }, + minWidth: { + type: [String, Number], + default: 80, + }, + formatter: { + type: Function as PropType< + (row: any, column: Column, cellValue, index: number) => VNode + >, + }, +}; + +export type TableColumnPropsTypes = ExtractPropTypes<typeof TableColumnProps>; + +export interface Column { + field?: string + width?: number + minWidth?: number + realWidth?: number + header?: string + renderHeader?: () => void + renderCell?: (data: any) => void + formatter?: (row: any, column: Column, cellValue, index: number) => VNode +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/column/use-column.ts b/packages/devui-vue/devui/table/src/column/use-column.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c5fc4ce546f06d6694a7e4f318cb9b0309565bb --- /dev/null +++ b/packages/devui-vue/devui/table/src/column/use-column.ts @@ -0,0 +1,45 @@ +import { ref } from 'vue'; +import { Column, TableColumnPropsTypes } from './column.type' +import { formatWidth, formatMinWidth } from '../utils'; + +export function useRender(props: TableColumnPropsTypes): any { + const formatedWidth = ref(formatWidth(props.width)); + const formatedMinWidth = ref(formatMinWidth(props.minWidth)); + const setColumnWidth = (column: Column) => { + column.width = formatedWidth.value; + column.minWidth = formatedMinWidth.value; + column.realWidth = column.width || column.minWidth; + return column; + }; + + const setColumnRender = (column: Column) => { + column.renderHeader = () => { + return defaultRenderHeader(column); + }; + column.renderCell = (data) => { + return defaultRenderCell(data); + }; + }; + + return { setColumnWidth, setColumnRender }; +} + +function defaultRenderHeader(column: Column) { + return column.header; +} + +function defaultRenderCell({ + row, + column, + $index, +}: { + row: any + column: Column + $index: number +}) { + const value = row[column.field]; + if (column.formatter) { + return column.formatter(row, column, value, $index); + } + return value?.toString?.() || ''; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/header/header.scss b/packages/devui-vue/devui/table/src/header/header.scss new file mode 100644 index 0000000000000000000000000000000000000000..21e88bf495006c749a79c1782c1d840f70b134b0 --- /dev/null +++ b/packages/devui-vue/devui/table/src/header/header.scss @@ -0,0 +1,26 @@ +@import '../../../styles-var/devui-var.scss'; + +.devui-thead { + tr { + font-size: $devui-font-size-card-title; + color: $devui-text; + font-weight: 700; + border: none; + border-bottom: 1px solid $devui-line; + background-color: $devui-global-bg-normal; + + th { + text-align: left; + padding: 12px 10px; + border: none; + } + } +} + +.header-bg { + thead.devui-thead { + tr { + background: var(--devui-list-item-hover-bg, #f2f5fc); + } + } +} diff --git a/packages/devui-vue/devui/table/src/header/header.tsx b/packages/devui-vue/devui/table/src/header/header.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a05a80b7ae6f8189134368ea1d71f4a2cb582f9f --- /dev/null +++ b/packages/devui-vue/devui/table/src/header/header.tsx @@ -0,0 +1,28 @@ +import { defineComponent, toRefs } from 'vue'; +import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' +import './header.scss'; + +export default defineComponent({ + name: 'DTableHeader', + props: TableHeaderProps, + setup(props: TableHeaderPropsTypes) { + const { store } = toRefs(props) + const columns = store.value.states._columns.value; + + return { + columns, + } + }, + render() { + const { columns } = this + return ( + <thead class="devui-thead"> + <tr> + {columns.map((column, index) => { + return <th key={index}>{column.renderHeader()}</th>; + })} + </tr> + </thead> + ) + } +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/header/header.type.ts b/packages/devui-vue/devui/table/src/header/header.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..3369aa9d76063355dcfc33c108438a50279b2226 --- /dev/null +++ b/packages/devui-vue/devui/table/src/header/header.type.ts @@ -0,0 +1,10 @@ +import { ExtractPropTypes } from 'vue'; + +export const TableHeaderProps = { + store: { + type: Object, + default: {}, + }, +}; + +export type TableHeaderPropsTypes = ExtractPropTypes<typeof TableHeaderProps>; diff --git a/packages/devui-vue/devui/table/src/store/index.ts b/packages/devui-vue/devui/table/src/store/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7138064c7b394b6ba8e68e79d6a4c5c1cd194c2 --- /dev/null +++ b/packages/devui-vue/devui/table/src/store/index.ts @@ -0,0 +1,30 @@ +import { ref, watch } from 'vue'; +import { TablePropsTypes } from '../table.type'; +import { Column } from '../column/column.type'; + +export function createStore(props: TablePropsTypes): any { + const _data = ref([]); + const _columns = ref([]); + updateData(); + + watch(() => props.data, updateData, { deep: true }); + + function updateData() { + _data.value = []; + props.data.forEach((item) => { + _data.value.push(item); + }); + } + + const insertColumn = (column: Column) => { + _columns.value.push(column); + }; + + return { + insertColumn, + states: { + _data, + _columns, + }, + }; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/table-types.ts b/packages/devui-vue/devui/table/src/table-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f9cbcf673a594df6b5455b103d11e8783f27593 --- /dev/null +++ b/packages/devui-vue/devui/table/src/table-types.ts @@ -0,0 +1,14 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +type TableData = Array<{ + [key: string]: any +}> + +export const tableProps = { + data: { + type: Array as PropType<TableData>, + required: true, + } +} as const + +export type TableProps = ExtractPropTypes<typeof tableProps> diff --git a/packages/devui-vue/devui/table/src/table.scss b/packages/devui-vue/devui/table/src/table.scss new file mode 100644 index 0000000000000000000000000000000000000000..48d9e7cf3180dea7646f67175ebe7ba3268b574f --- /dev/null +++ b/packages/devui-vue/devui/table/src/table.scss @@ -0,0 +1,30 @@ +@import '../../styles-var/devui-var.scss'; + +.devui-table { + display: table; + table-layout: fixed; + width: 100%; + border-spacing: 0; + border: none; + + &-wrapper { + width: 100%; + overflow-x: auto; + } + + &-striped { + tbody tr:nth-child(even) { + background-color: $devui-list-item-strip-bg; + } + } + + &-empty { + width: 100%; + font-size: $devui-font-size; + text-align: center; + } +} + +.table-layout-auto { + table-layout: auto; +} diff --git a/packages/devui-vue/devui/table/src/table.tsx b/packages/devui-vue/devui/table/src/table.tsx new file mode 100644 index 0000000000000000000000000000000000000000..83146778b7d6595233b33ac52a0b792113a2ab9f --- /dev/null +++ b/packages/devui-vue/devui/table/src/table.tsx @@ -0,0 +1,36 @@ +import { provide, defineComponent, getCurrentInstance } from 'vue'; +import { Table, TableProps, TablePropsTypes } from './table.type'; +import { useTable } from './use-table'; +import { createStore } from './store'; +import ColGroup from './colgroup/colgroup'; +import TableHeader from './header/header'; +import TableBody from './body/body'; +import './table.scss'; + +export default defineComponent({ + name: 'DTable', + props: TableProps, + setup(props: TablePropsTypes) { + const table = getCurrentInstance() as Table; + const store = createStore(props); + table.store = store; + const { classes } = useTable(props); + provide('table', table); + + return { classes, store }; + }, + render() { + const { classes, data, store, $slots } = this; + return ( + <div class="devui-table-wrapper"> + {$slots.default()} + <table class={classes} cellpadding="0" cellspacing="0"> + <ColGroup /> + <TableHeader store={store} /> + {!!data.length && <TableBody store={store} />} + </table> + {!data.length && <div class="devui-table-empty">No Data</div>} + </div> + ); + }, +}); diff --git a/packages/devui-vue/devui/table/src/table.type.ts b/packages/devui-vue/devui/table/src/table.type.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9132f45ec9a57251db60d09b475cab66b56bf1c --- /dev/null +++ b/packages/devui-vue/devui/table/src/table.type.ts @@ -0,0 +1,26 @@ +import { PropType, ExtractPropTypes, ComponentInternalInstance } from 'vue'; + +export const TableProps = { + data: { + type: Array as PropType<any[]>, + default: [], + }, + striped: { + type: Boolean, + default: false, + }, + headerBg:{ + type: Boolean, + default: false + }, + tableLayout:{ + type: String as PropType<'fixed' | 'auto'>, + default: 'fixed' + } +}; + +export type TablePropsTypes = ExtractPropTypes<typeof TableProps>; + +export interface Table extends ComponentInternalInstance { + store: any +} diff --git a/packages/devui-vue/devui/table/src/use-table.ts b/packages/devui-vue/devui/table/src/use-table.ts new file mode 100644 index 0000000000000000000000000000000000000000..e375cbbb4ca06fb68921d87c421407cb381883f2 --- /dev/null +++ b/packages/devui-vue/devui/table/src/use-table.ts @@ -0,0 +1,13 @@ +import { computed } from 'vue'; +import { TablePropsTypes } from './table.type'; + +export function useTable(props: TablePropsTypes): any { + const classes = computed(() => ({ + 'devui-table': true, + 'devui-table-striped': props.striped, + 'header-bg': props.headerBg, + 'table-layout-auto': props.tableLayout === 'auto' + })); + + return { classes }; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/utils.ts b/packages/devui-vue/devui/table/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..9043fe1a3f676a500a0ef664a033b131c1bb12a3 --- /dev/null +++ b/packages/devui-vue/devui/table/src/utils.ts @@ -0,0 +1,11 @@ +export function formatWidth(width: number | string): number { + if (typeof width === 'number') { + return width; + } + + return parseInt(width, 10) || 0; +} + +export function formatMinWidth(minWidth: number | string): number { + return formatWidth(minWidth) || 80; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/tabs/index.ts b/packages/devui-vue/devui/tabs/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..7eb180a645b0bee15d7fd2cec0b2e2038725b280 --- /dev/null +++ b/packages/devui-vue/devui/tabs/index.ts @@ -0,0 +1,20 @@ +import { App } from 'vue'; +// import type { App } from 'vue'; +import Tabs from './src/tabs'; +import Tab from './src/tab'; + +Tabs.install = function (app: App) { + app.component(Tabs.name, Tabs); + app.component(Tab.name, Tab); +}; + +export { Tabs }; + +export default { + title: 'Tabs 选项卡', + category: '导航', + status: '60%', + install(app: App): void { + app.use(Tabs as any); + } +}; diff --git a/devui/tabs/tab.tsx b/packages/devui-vue/devui/tabs/src/tab.tsx similarity index 34% rename from devui/tabs/tab.tsx rename to packages/devui-vue/devui/tabs/src/tab.tsx index bf31071cc9cd125fc3911fc42f4353c702eb8823..bb03cc35345eb84ad37331e221ca384b4282e513 100644 --- a/devui/tabs/tab.tsx +++ b/packages/devui-vue/devui/tabs/src/tab.tsx @@ -1,8 +1,8 @@ -import { computed, defineComponent, getCurrentInstance, inject, reactive } from 'vue' -import { Tabs } from './tabs'; +import { defineComponent, inject } from 'vue' +import { Tabs } from './tabs' export default defineComponent({ - name: 'd-tab', + name: 'DTab', props: { title: { default: null, @@ -17,19 +17,21 @@ export default defineComponent({ default: false } }, - setup(props, {slots}) { - const tabs = inject<Tabs>( - 'tabs' - ); - tabs.state.data.push(props); + setup(props, { slots }) { + const tabs = inject<Tabs>('tabs') + tabs.state.slots.push(slots.dTabTitle) + tabs.state.data.push(props) return () => { - const content = tabs.state.showContent && tabs.state.active === props.id ? ( - <div class="devui-tab-content"> - <div role="tabpanel" class="devui-tab-pane in active"> - {slots.default()} - </div> - </div>): null; + const { id } = props + const content = + tabs.state.showContent && tabs.state.active === id ? ( + <div class='devui-tab-content'> + <div role='tabpanel' class='devui-tab-pane in active'> + {slots.default()} + </div> + </div> + ) : null return content } } -}) \ No newline at end of file +}) diff --git a/devui/tabs/tabs.scss b/packages/devui-vue/devui/tabs/src/tabs.scss similarity index 93% rename from devui/tabs/tabs.scss rename to packages/devui-vue/devui/tabs/src/tabs.scss index 95c8dc13c604ef8f07fac3ac4689b0b203130847..92a19b169e95f98be3d6e097c1bb67bc04e4735c 100644 --- a/devui/tabs/tabs.scss +++ b/packages/devui-vue/devui/tabs/src/tabs.scss @@ -1,8 +1,5 @@ -@import '../style/theme/color'; -@import '../style/theme/variables'; -@import '../style/mixins/index'; -@import '../style/theme/font'; -@import '../style/theme/corner'; +@import '../../style/mixins/index'; +@import '../../styles-var/devui-var.scss'; $devui-tab-options-bg: $devui-list-item-hover-bg; @@ -15,6 +12,7 @@ $devui-tab-options-bg: $devui-list-item-hover-bg; font-size: $devui-font-size; background: transparent; font-weight: bold; + list-style: none; li { cursor: pointer; @@ -26,6 +24,7 @@ $devui-tab-options-bg: $devui-list-item-hover-bg; line-height: 30px; background-color: transparent; padding: 0; + text-decoration: none; color: $devui-text; } @@ -297,11 +296,18 @@ $devui-tab-options-bg: $devui-list-item-hover-bg; } .devui-nav { + list-style: none; + padding-left: 0; + li { - a.custom-width { - display: inline-block; - padding: 0; - text-align: center; + a { + text-decoration: none; + + &.custom-width { + display: inline-block; + padding: 0; + text-align: center; + } } } } @@ -353,5 +359,7 @@ $devui-tab-options-bg: $devui-list-item-hover-bg; box-shadow: 0 2px 4px 0 $devui-light-shadow; top: 1px; height: 30px; - transition: left 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); + transition: + left 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), + width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); } diff --git a/packages/devui-vue/devui/tabs/src/tabs.tsx b/packages/devui-vue/devui/tabs/src/tabs.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ef50017f8d8f0dd8a92c4bc926a7191809732fb0 --- /dev/null +++ b/packages/devui-vue/devui/tabs/src/tabs.tsx @@ -0,0 +1,192 @@ +import { + defineComponent, + onBeforeMount, + onMounted, + onUpdated, + PropType, + provide, + reactive, + ref, + Slot +} from 'vue' +import './tabs.scss' + +export type Active = string | number | null +export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider' +export interface Tabs { + state: TabsState +} +interface TabsState { + data?: any[] + showContent: boolean + active: string + slots: Slot[] +} +export default defineComponent({ + name: 'DTabs', + props: { + modelValue: { + type: [String, Number], + default: null + }, + + type: { + type: String as () => TabsType, + default: 'tabs' + }, + showContent: { + type: Boolean, + default: true + }, + vertical: { + type: Boolean, + default: false + }, + reactivable: { + type: Boolean, + default: true + }, + customWidth: { + type: String, + default: '' + }, + cssClass: { + type: String, + default: '' + }, + beforeChange: { + type: Function as PropType<(id: Active) => boolean>, + default: null + } + }, + + emits: ['update:modelValue', 'activeTabChange'], + setup(props, { emit, slots }) { + const tabsEle = ref(null) + const data = reactive({ offsetLeft: 0, offsetWidth: 0, id: null }) + const state: TabsState = reactive({ + data: [], + active: props.modelValue, + showContent: props.showContent, + slots: [] + }) + provide<Tabs>('tabs', { + state + }) + + const canChange = function (currentTab: Active) { + let changeResult = Promise.resolve(true) + if (typeof props.beforeChange === 'function') { + const result: any = props.beforeChange(currentTab) + if (typeof result !== 'undefined') { + if (result.then) { + changeResult = result + } else { + console.log(result) + changeResult = Promise.resolve(result) + } + } + } + + return changeResult + } + const activeClick = function (item, tabEl?) { + if (!props.reactivable && props.modelValue === item.id) { + return + } + canChange(item.id).then((change) => { + if (!change) { + return + } + const tab = state.data.find((itemOption) => itemOption.id === item.id) + if (tab && !tab.disabled) { + state.active = item.id + emit('update:modelValue', tab.id) + if (props.type === 'slider' && tabEl && tabsEle) { + this.offsetLeft = + tabEl.getBoundingClientRect().left - + this.tabsEle.nativeElement.getBoundingClientRect().left + this.offsetWidth = tabEl.getBoundingClientRect().width + } + emit('activeTabChange', tab.id) + } + }) + } + const ulClass: string[] = [props.type] + props.cssClass && ulClass.push(props.cssClass) + props.vertical && ulClass.push('devui-nav-stacked') + onUpdated(() => { + if (props.type === 'slider') { + // 延时等待active样式切换至正确的tab + setTimeout(() => { + const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active') + if (tabEle) { + data.offsetLeft = + tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left + data.offsetWidth = tabEle.getBoundingClientRect().width + } + }) + } + }) + onBeforeMount(() => { + if (props.type !== 'slider' && props.modelValue === undefined && state.data.length > 0) { + activeClick(state.data[0]) + } + }) + onMounted(() => { + if ( + props.type === 'slider' && + props.modelValue === undefined && + state.data.length > 0 && + state.data[0] + ) { + activeClick(state.data[0].tabsEle.value.getElementById(state.data[0].tabId)) + } + }) + return () => { + return ( + <div> + <ul + ref={tabsEle} + role='tablist' + class={`devui-nav devui-nav-${ulClass.join(' ')}`} + id='devuiTabs11' + > + {state.data.map((item, i) => { + return ( + <li + role='presentation' + onClick={() => { + activeClick(item) + }} + class={ + (props.modelValue === (item.id || item.tabId) ? 'active' : '') + + ' ' + + (item.disabled ? 'disabled' : '') + } + id={item.id || item.tabId} + > + <a + role='tab' + data-toggle={item.id} + aria-expanded={props.modelValue === (item.id || item.tabId)} + > + {state.slots[i] ? state.slots[i]() : <span>{item.title}</span>} + </a> + </li> + ) + })} + <div + class={`devui-nav-${props.type}-animation`} + style={{ + left: data.offsetLeft + 'px', + width: data.offsetWidth + 'px' + }} + ></div> + </ul> + {slots.default()} + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/tag-input/__tests__/tag-input.spec.ts b/packages/devui-vue/devui/tag-input/__tests__/tag-input.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b3d644f76152ba60db1afe2dc0de36b3a04932f --- /dev/null +++ b/packages/devui-vue/devui/tag-input/__tests__/tag-input.spec.ts @@ -0,0 +1,233 @@ +import { mount } from '@vue/test-utils'; +import { reactive, nextTick } from 'vue'; +import DTagInput from '../src/tag-input'; + +const customMount = (state) => mount({ + components: { DTagInput }, + template: ` + <d-tag-input + v-model:tags="state.tags" + v-model:suggestionList="state.suggestionList" + displayProperty="cname"></d-tag-input> + `, + setup () { + return { + state + }; + } +}); + +describe('DTagInput', () => { + it('tag-input render work', async () => { + const state = reactive({ + tags: [ + { cname: 'Y.Chen' }, + { cname: 'b' }, + { cname: 'c' } + ], + suggestionList: [ + { cname: 'd' }, + { cname: 'e' }, + { cname: 'f' }, + ] + }); + const wrapper = customMount(state); + + expect(wrapper.find('.devui-tags-host').exists()).toBe(true); + expect(wrapper.find('.devui-tags').exists()).toBe(true); + expect(wrapper.find('.devui-tag-list').exists()).toBe(true); + expect(wrapper.find('.devui-input').exists()).toBe(true); + + const itemA = wrapper.find('.devui-tag-item'); + expect(itemA.exists()).toBe(true); + expect(itemA.text()).toBe('Y.Chen'); + + state.tags[0] = { cname: 'X.Zhang' }; + await nextTick(); + expect(itemA.text()).toBe('X.Zhang'); + }); + + it('tag-input show suggestion work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + ], + suggestionList: [ + { cname: 'b' }, + ] + }); + const wrapper = customMount(state); + const input = wrapper.find('input.devui-input'); + + expect(wrapper.find('.devui-suggestion-list').exists()).toBe(false); + await input.trigger('focus'); + expect(wrapper.find('.devui-suggestion-list').exists()).toBe(true); + }); + + it('tag-input disabled work', async () => { + const tags = reactive([ + { cname: 'a' }, + ]); + const suggestionList = reactive([ + { cname: 'b' }, + ]); + const wrapper = mount(DTagInput, { + props: { + tags, + suggestionList, + disabled: false + } + }); + + expect(wrapper.find('.devui-disabled').exists()).toBe(false); + expect(wrapper.find('.devui-input').isVisible()).toBe(true); + + await wrapper.setProps({ + disabled: true + }); + expect(wrapper.find('.devui-disabled').exists()).toBe(true); + expect(wrapper.find('.devui-input').isVisible()).toBe(false); + expect(wrapper.find('.remove-button').exists()).toBe(false); + }); + + it('tag-input maxTags work', () => { + const tags = reactive([ + { cname: 'a' }, + { cname: 'b' }, + ]); + const suggestionList = reactive([ + { cname: 'c' }, + ]); + const wrapper = mount(DTagInput, { + props: { + tags, + suggestionList, + maxTags: 1 + } + }); + + expect(wrapper.find('input').attributes('disabled')).toBe(''); + }); + + it('tag-input removeTag work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + { cname: 'b' }, + ], + suggestionList: [ + { cname: 'c' }, + ] + }); + const wrapper = customMount(state); + const removeSvg = wrapper.find('.remove-button'); + await removeSvg.trigger('mousedown'); + expect(wrapper.findAll('.devui-tag-item').length).toBe(1); + expect(state.tags.length).toBe(1); + expect(state.suggestionList.length).toBe(2); + }); + + it('tag-input keydown work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + { cname: 'b' }, + ], + suggestionList: [ + { cname: 'c' }, + { cname: 'xyz' } + ] + }); + const wrapper = customMount(state); + const input = wrapper.find('input'); + await input.setValue('dfg'); + await input.trigger('keydown', { key: 'Enter' }); + expect(state.tags.length).toBe(3); + expect(state.suggestionList.length).toBe(2); + + await input.setValue('yz'); + await input.trigger('keydown', { key: 'Enter' }); + expect(state.tags.length).toBe(4); + expect(state.tags[3].cname).toBe('xyz'); + expect(state.suggestionList.length).toBe(1); + }); + + it('tag-input filter suggestion work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + { cname: 'b' }, + ], + suggestionList: [ + { cname: 'x' }, + { cname: 'xy' }, + { cname: 'xyz' } + ] + }); + const wrapper = customMount(state); + const input = wrapper.find('input'); + + await input.trigger('focus'); + expect(wrapper.findAll('.devui-suggestion-item').length).toBe(3); + + await input.setValue('xy'); + await input.trigger('input'); + expect(wrapper.findAll('.devui-suggestion-item').length).toBe(2); + + await input.setValue('xxx'); + await input.trigger('input'); + expect(wrapper.findAll('.devui-suggestion-item.devui-disabled').length).toBe(1); + }); + + it('tag-input click suggestion work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + { cname: 'b' }, + ], + suggestionList: [ + { cname: 'x' }, + { cname: 'yyy' }, + { cname: 'xyz' } + ] + }); + const wrapper = customMount(state); + await wrapper.find('input').trigger('focus'); + const yyy = wrapper.findAll('.devui-suggestion-item')[1]; + + await yyy.trigger('mousedown'); + expect(state.tags.length).toBe(3); + expect(state.tags[2].cname).toBe('yyy'); + expect(state.suggestionList.length).toBe(2); + }); + + it('tag-input arrow work', async () => { + const state = reactive({ + tags: [ + { cname: 'a' }, + { cname: 'b' }, + ], + suggestionList: [ + { cname: 'x' }, + { cname: 'yyy' }, + { cname: 'xyz' } + ] + }); + const wrapper = customMount(state); + const input = wrapper.find('input'); + await input.trigger('focus'); + + expect(wrapper.findAll('.devui-suggestion-item')[0].classes()).toContain('selected'); + + await input.trigger('keydown', { key: 'ArrowDown' }); + expect(wrapper.findAll('.devui-suggestion-item')[1].classes()).toContain('selected'); + + await input.trigger('keydown', { key: 'ArrowUp' }); + await input.trigger('keydown', { key: 'ArrowUp' }); + expect(wrapper.findAll('.devui-suggestion-item')[2].classes()).toContain('selected'); + + await input.trigger('keydown', { key: 'Enter' }); + expect(state.tags[2].cname).toBe('xyz'); + expect(state.suggestionList.length).toBe(2); + }); +}); diff --git a/packages/devui-vue/devui/tag-input/index.ts b/packages/devui-vue/devui/tag-input/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..414add7d0417c370cab4b8cb71ad50f668b6ae9a --- /dev/null +++ b/packages/devui-vue/devui/tag-input/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import TagInput from './src/tag-input' + +TagInput.install = function (app: App) { + app.component(TagInput.name, TagInput) +} + +export { TagInput } + +export default { + title: 'TagInput 标签输入框', + category: '数据录入', + status: '已完成', + install(app: App): void { + app.use(TagInput as any) + } +} diff --git a/packages/devui-vue/devui/tag-input/src/remove-btn.tsx b/packages/devui-vue/devui/tag-input/src/remove-btn.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f58580b8025e2b329ba257e366b5697b5b1db2c2 --- /dev/null +++ b/packages/devui-vue/devui/tag-input/src/remove-btn.tsx @@ -0,0 +1,16 @@ +export default ( + <svg + width="12px" + height="12px" + viewBox="0 0 12 12" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + {...{'xmlns:xlink': 'http://www.w3.org/1999/xlink'}}> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path + d="M8.86785321,3.13214679 C9.02624037,3.29053395 9.02624037,3.54733027 8.86785321,3.70571743 L6.573,6 L8.86785321,8.29428257 C9.02624037,8.45266973 9.02624037,8.70946605 8.86785321,8.86785321 C8.70946605,9.02624037 8.45266973,9.02624037 8.29428257,8.86785321 L6,6.573 L3.70571743,8.86785321 C3.54733027,9.02624037 3.29053395,9.02624037 3.13214679,8.86785321 C2.97375963,8.70946605 2.97375963,8.45266973 3.13214679,8.29428257 L5.427,6 L3.13214679,3.70571743 C2.97375963,3.54733027 2.97375963,3.29053395 3.13214679,3.13214679 C3.29053395,2.97375963 3.54733027,2.97375963 3.70571743,3.13214679 L6,5.427 L8.29428257,3.13214679 C8.45266973,2.97375963 8.70946605,2.97375963 8.86785321,3.13214679 Z" + fill-rule="nonzero" + ></path> + </g> + </svg> +); diff --git a/packages/devui-vue/devui/tag-input/src/tag-input.scss b/packages/devui-vue/devui/tag-input/src/tag-input.scss new file mode 100644 index 0000000000000000000000000000000000000000..5bc6a29520ec6f8c7199c7df73c3d0540a7e8466 --- /dev/null +++ b/packages/devui-vue/devui/tag-input/src/tag-input.scss @@ -0,0 +1,212 @@ +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; +@import '../../style/theme/z-index'; + +:host { + display: block; + outline: none; +} + +.devui-tags-host { + position: relative; + height: 100%; + outline: none; + + &:active { + outline: 0; + } +} + +.devui-form-control.devui-tags { + -moz-appearance: textfield; + -webkit-appearance: textfield; + padding: 2px 4px; + overflow: hidden; + word-wrap: break-word; + cursor: text; + background-color: $devui-base-bg; + border: 1px solid $devui-line; + border-radius: $devui-border-radius; + height: 100%; + transition: border-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); + + &:hover { + border-color: $devui-list-item-hover-bg; + } + + &.focused { + outline: 0; + } + + &.devui-dropdown-origin:focus-within { + border-color: $devui-brand; + } + + .devui-tag-list { + margin: 0; + padding: 0; + list-style-type: none; + } + + .devui-tag-item { + margin: 1px; + padding: 0 10px; + display: inline-block; + min-height: 18px; + line-height: 18px; + border-radius: $devui-border-radius; + color: $devui-text; + background-color: $devui-label-bg; + position: relative; + border: 1px solid $devui-label-bg; + + span { + line-height: 1.5; + margin-right: 25px; + } + + .remove-button { + margin: 0 0 0 12px; + padding: 0; + border: none; + vertical-align: top; + font-size: $devui-font-size-page-title; + border-radius: 50%; + background-color: $devui-line; + width: 12px; + height: 12px; + display: inline-block; + line-height: 12px; + text-align: center; + transform: translateY(-50%); + position: absolute; + top: 50%; + right: 10px; + + svg path { + fill: $devui-light-text; //TODO: Color-Question + } + + &:hover { + text-decoration: none; + } + } + } + + &:not(.devui-disabled) { + .devui-tag-item { + cursor: pointer; + + span { + &:hover { + color: $devui-list-item-hover-text; + } + } + + .remove-button { + &:hover { + background-color: $devui-list-item-hover-text; + } + } + } + } + + &.devui-disabled { + border-color: $devui-disabled-line; + background-color: $devui-disabled-bg; + cursor: not-allowed; + + .devui-tag-item { + color: $devui-disabled-text; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + + span { + margin-right: 0; + } + + .remove-button { + background-color: $devui-disabled-line; + + svg path { + fill: $devui-light-text; + } + } + } + + .devui-tag-list { + min-height: 22px; + } + } + + input.devui-input { + border: 0; + outline: 0; + float: left; + width: 100%; + height: 22px; + font-size: $devui-font-size; + padding-left: 5px; + + &::-ms-clear { + display: none; + } + } +} + +.devui-tags-autocomplete { + position: absolute; + padding-bottom: 5px; + z-index: $devui-z-index-dropdown; + width: 100%; + background-color: $devui-connected-overlay-bg; + box-shadow: $devui-shadow-length-connected-overlay $devui-shadow; + + &.devui-dropdown-menu { + display: block; + margin: 4px 0; + } + + .devui-suggestion-list { + margin: 0; + padding: 0; + list-style-type: none; + max-height: 280px; + overflow-y: auto; + position: relative; + + .devui-suggestion-item { + padding: 5px 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: $devui-font-size; + line-height: 20px; + + &:not(.devui-disabled) { + cursor: pointer; + color: $devui-text; + // background-color: $devui-base-bg; + &:hover { + background-color: $devui-list-item-hover-bg; + } + + &.selected { + color: $devui-brand; + background-color: $devui-list-item-hover-bg; + } + } + } + } +} + +.devui-tags-autocomplete { + .devui-suggestion-list { + .devui-suggestion-item { + transition: color $devui-animation-duration-fast $devui-animation-ease-in-smooth, background-color $devui-animation-duration-fast $devui-animation-ease-in-smooth; + } + } +} diff --git a/packages/devui-vue/devui/tag-input/src/tag-input.tsx b/packages/devui-vue/devui/tag-input/src/tag-input.tsx new file mode 100644 index 0000000000000000000000000000000000000000..375bc0a83e8a62d04d152073417b177f25c6bcdd --- /dev/null +++ b/packages/devui-vue/devui/tag-input/src/tag-input.tsx @@ -0,0 +1,334 @@ +import { defineComponent, ref, computed, nextTick, watch, PropType } from 'vue'; +import removeBtnSvg from './remove-btn'; +import './tag-input.scss'; + +interface Suggestion { + __index: number + [x: string]: any +} + +const tagInputProps = { + tags: { + type: Array as PropType<any[]>, + default: (): [] => [] + }, + displayProperty: { + type: String, + default: 'name' + }, + placeholder: { + type: String, + default: '' + }, + minLength: { + type: Number, + default: 3 + }, + maxLength: { + type: Number, + default: Number.MAX_SAFE_INTEGER + }, + maxTags: { + type: Number, + default: Number.MAX_SAFE_INTEGER + }, + maxTagsText: { + type: String, + default: '已达到最大个数:' + }, + spellcheck: { + type: Boolean, + default: true + }, + suggestionList: { + type: Array as PropType<any[]>, + default: (): [] => [] + }, + disabled: { + type: Boolean, + default: false + }, + isAddBySpace: { + type: Boolean, + default: true + }, + disabledText: { + type: String, + default: '' + }, + noData: { + type: String, + default: '' + }, + caseSensitivity: { + type: Boolean, + default: false + }, + onValueChange: { + type: Function as PropType<(oldTags: any[], newTags: any[]) => void>, + default: undefined + }, + 'onUpdate:tags': { + type: Function as PropType<(v: any[]) => void>, + default: undefined + }, + 'onUpdate:suggestionList': { + type: Function as PropType<(v: any[]) => void>, + default: undefined + } +} as const; + +const KEYS_MAP = { + tab: 'Tab', + down: 'ArrowDown', + up: 'ArrowUp', + enter: 'Enter', + space: ' ', +} as const; + +export default defineComponent({ + name: 'DTagInput', + props: tagInputProps, + emits: ['update:tags', 'update:suggestionList', 'valueChange'], + setup(props, ctx) { + const add = (arr: any[], target: any) => { + const res = Object.assign({}, target); + delete res.__index; + return arr.concat(res); + }; + const remove = (arr: any[], targetIdx: number) => { + const newArr = arr.slice(); + newArr.splice(targetIdx, 1); + return newArr; + }; + + const tagInputVal = ref(''); + const onInput = ($event: InputEvent) => { + const v = ($event.target as HTMLInputElement).value || ''; + tagInputVal.value = v.trim(); + }; + const mergedSuggestions = computed<Suggestion[]>(() => { + let suggestions = props.suggestionList.map((item, index: number) => { + return { + __index: index, + ...item + }; + }); + if (tagInputVal.value === '') { + return suggestions; + } + return suggestions = props.caseSensitivity + ? suggestions.filter(item => item[props.displayProperty].indexOf(tagInputVal.value) !== -1) + : suggestions.filter(item => item[props.displayProperty].toLowerCase().indexOf(tagInputVal.value.toLowerCase()) !== -1) + }); + + const selectIndex = ref(0); + watch(mergedSuggestions, () => { + selectIndex.value = 0; + }); + const onSelectIndexChange = (isUp = false) => { + if (isUp) { + selectIndex.value < mergedSuggestions.value.length - 1 ? selectIndex.value++ : selectIndex.value = 0; + return; + } + selectIndex.value > 0 ? selectIndex.value-- : selectIndex.value = mergedSuggestions.value.length - 1; + }; + + const tagInputRef = ref<HTMLInputElement | null>(null); + const isInputBoxFocus = ref(false); + const onInputFocus = () => { + isInputBoxFocus.value = true; + }; + const onInputBlur = () => { + isInputBoxFocus.value = false; + }; + const handleEnter = () => { + let res = { [props.displayProperty]: tagInputVal.value }; + if (tagInputVal.value === '' && mergedSuggestions.value.length === 0) return false + if (props.tags.findIndex((item) => item[props.displayProperty] === tagInputVal.value) > -1) { + tagInputVal.value = '' + return false + } + if (mergedSuggestions.value.length === 0 && + (tagInputVal.value.length < props.minLength || tagInputVal.value.length > props.maxLength)) { + tagInputVal.value = '' + return false + } + if (mergedSuggestions.value.length) { + const target = mergedSuggestions.value[selectIndex.value]; + res = target; + ctx.emit('update:suggestionList', remove(props.suggestionList, target.__index)); + } + + const newTags = add(props.tags, res); + ctx.emit('valueChange', props.tags, newTags); + ctx.emit('update:tags', newTags); + mergedSuggestions.value.length === 0 && (tagInputVal.value = ''); + }; + const onInputKeydown = ($event: KeyboardEvent) => { + switch ($event.key) { + case KEYS_MAP.tab: + case KEYS_MAP.enter: + case KEYS_MAP.space: + if (!props.isAddBySpace && KEYS_MAP.space) return + handleEnter(); + break; + case KEYS_MAP.down: + onSelectIndexChange(true); + break; + case KEYS_MAP.up: + onSelectIndexChange(); + break; + default: + break; + } + }; + + const removeTag = ($event: MouseEvent, tagIdx: number) => { + $event.preventDefault(); + ctx.emit('update:suggestionList', add(props.suggestionList, props.tags[tagIdx])); + const newTags = remove(props.tags, tagIdx); + ctx.emit('valueChange', props.tags, newTags); + ctx.emit('update:tags', newTags); + nextTick(() => { + tagInputRef.value?.focus(); + }); + }; + const onSuggestionItemClick = ($event: MouseEvent, itemIndex: number) => { + $event.preventDefault(); + const target = mergedSuggestions.value[itemIndex]; + const newTags = add(props.tags, target); + const newSuggestions = remove(props.suggestionList, target.__index); + ctx.emit('valueChange', props.tags, newTags); + ctx.emit('update:tags', newTags); + ctx.emit('update:suggestionList', newSuggestions); + }; + + const isTagsLimit = computed(() => props.maxTags <= props.tags.length); + const isShowSuggestion = computed(() => { + return !props.disabled && !isTagsLimit.value && isInputBoxFocus.value; + }); + + return { + tagInputRef, + tagInputVal, + isInputBoxFocus, + onInput, + onInputFocus, + onInputBlur, + removeTag, + onSuggestionItemClick, + onInputKeydown, + isShowSuggestion, + mergedSuggestions, + selectIndex, + isTagsLimit + }; + }, + render() { + const { + tagInputVal, + isInputBoxFocus, + disabled, + disabledText, + isTagsLimit, + maxTagsText, + displayProperty, + tags, + onInputKeydown, + onInputFocus, + onInputBlur, + onInput, + onSuggestionItemClick, + removeTag, + placeholder, + spellcheck, + isShowSuggestion, + noData, + mergedSuggestions, + selectIndex, + maxTags + } = this; + + const inputBoxCls = { + 'devui-tags': true, + 'devui-form-control': true, + 'devui-dropdown-origin': true, + 'devui-dropdown-origin-open': isInputBoxFocus, + 'devui-disabled': disabled, + }; + const tagInputCls = { + input: true, + 'devui-input': true, + 'invalid-tag': false + }; + const tagInputStyle = [ + `display:${disabled ? 'none' : 'block'};` + ]; + + const noDataTpl = <li class="devui-suggestion-item devui-disabled"> + {noData} + </li>; + + return ( + <div class="devui-tags-host" tabindex="-1"> + <div class={inputBoxCls} style={['box-shadow: none;']}> + <ul class="devui-tag-list" title={disabled ? disabledText : ''}> + { + tags.map((tag, tagIdx) => { + return ( + <li class="devui-tag-item"> + <span>{tag[displayProperty]}</span> + { + !disabled && + <a class="remove-button" onMousedown={($event) => removeTag($event, tagIdx)}> + {removeBtnSvg} + </a> + } + </li> + ); + }) + } + </ul> + <input + type="text" + ref="tagInputRef" + value={tagInputVal} + class={tagInputCls} + style={tagInputStyle} + onKeydown={onInputKeydown} + onFocus={onInputFocus} + onBlur={onInputBlur} + onInput={($event: any) => onInput($event)} + placeholder={isTagsLimit ? `${maxTagsText} ${maxTags}` : placeholder} + spellcheck={spellcheck} + disabled={isTagsLimit} + /> + </div> + { + !isShowSuggestion ? '' : ( + <div class="devui-tags-autocomplete devui-dropdown-menu"> + <ul class="devui-suggestion-list"> + { + mergedSuggestions.length === 0 ? + noDataTpl : + mergedSuggestions.map((item: any, index: number) => { + return ( + <li + class={{ 'devui-suggestion-item': true, selected: index === selectIndex }} + onMousedown={($event) => { + onSuggestionItemClick($event, index); + }}> + {item[displayProperty]} + </li> + ); + }) + } + </ul> + </div> + ) + } + </div> + ); + } +}); diff --git a/packages/devui-vue/devui/tag/__tests__/tag.spec.ts b/packages/devui-vue/devui/tag/__tests__/tag.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..9db389e4d2fa8c9e9040fc451832c6ddb99a3f26 --- /dev/null +++ b/packages/devui-vue/devui/tag/__tests__/tag.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils' +import { Tag } from '../index' + +describe('tag test', () => { + it('tag init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/tag/index.ts b/packages/devui-vue/devui/tag/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..43310285f5c37a45fdbee30011f4ca0b4bb64b92 --- /dev/null +++ b/packages/devui-vue/devui/tag/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Tag from './src/tag' + +Tag.install = function (app: App): void { + app.component(Tag.name, Tag) +} + +export { Tag } + +export default { + title: 'Tag 标签', + category: '数据展示', + status: '20%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Tag as any) + } +} diff --git a/packages/devui-vue/devui/tag/src/hooks/index.ts b/packages/devui-vue/devui/tag/src/hooks/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8931ccc412a0f807e375da1330bdb8b66af15299 --- /dev/null +++ b/packages/devui-vue/devui/tag/src/hooks/index.ts @@ -0,0 +1,3 @@ +import useStyle from './useStyle' + +export { useStyle } diff --git a/packages/devui-vue/devui/tag/src/hooks/useStyle.ts b/packages/devui-vue/devui/tag/src/hooks/useStyle.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dbb29d72cc7711ee2481484387b90a5ae9d0a01 --- /dev/null +++ b/packages/devui-vue/devui/tag/src/hooks/useStyle.ts @@ -0,0 +1,10 @@ +import { computed } from 'vue' +import { tagProps, TagProps } from '../tag-types' + +export default function (props: TagProps) { + return computed(() => { + const { type } = props + + return `devui-tag devui-tag-${type || 'default'}` + }) +} diff --git a/packages/devui-vue/devui/tag/src/tag-types.ts b/packages/devui-vue/devui/tag/src/tag-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8fd95a57f4f119dcc6f936a55362e4121b9a462 --- /dev/null +++ b/packages/devui-vue/devui/tag/src/tag-types.ts @@ -0,0 +1,16 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export type tagType = 'primary' | 'success' | 'warning' | 'danger' + +export const tagProps = { + type: { + type: String as PropType<tagType>, + default: '' + }, + color: { + type: String as PropType<string>, + default: '' + } +} as const + +export type TagProps = ExtractPropTypes<typeof tagProps> diff --git a/packages/devui-vue/devui/tag/src/tag.scss b/packages/devui-vue/devui/tag/src/tag.scss new file mode 100644 index 0000000000000000000000000000000000000000..8c4fab2446c573f8a75ca71c8f6f9721c5eef1fc --- /dev/null +++ b/packages/devui-vue/devui/tag/src/tag.scss @@ -0,0 +1,56 @@ +@import '../../styles-var/devui-var'; + +$devui-tag-normal-config: ( + default: ( + border: 0, + color: $devui-text, + background-color: $devui-default-bg + ), + primary: ( + color: $devui-primary, + background-color: $devui-primary-bg, + border-color: $devui-primary-line + ), + success: ( + color: $devui-success, + background-color: $devui-success-bg, + border-color: $devui-success-line + ), + warning: ( + color: $devui-warning, + background-color: $devui-warning-bg, + border-color: $devui-warning-line + ), + danger: ( + color: $devui-danger, + background-color: $devui-danger-bg, + border-color: $devui-danger-line + ) +); + +.devui-tag { + display: inline-block; + margin: 4px; + + .devui-tag { + padding: 0 8px; + min-height: 20px; + font-size: 12px; + font-size: var(--devui-font-size, 12px); + line-height: 20px; + border: 1px solid; + border-radius: $devui-border-radius; + display: block; + align-items: center; + position: relative; + cursor: default; + + @each $type in default, primary, success, warning, danger { + &.devui-tag-#{$type} { + @each $key, $value in map-get($devui-tag-normal-config, $type) { + #{$key}: $value; + } + } + } + } +} diff --git a/packages/devui-vue/devui/tag/src/tag.tsx b/packages/devui-vue/devui/tag/src/tag.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a04ac737d1eb5f53d3084b739b3f55ef58f28d6b --- /dev/null +++ b/packages/devui-vue/devui/tag/src/tag.tsx @@ -0,0 +1,23 @@ +import { defineComponent, ref, toRefs, computed } from 'vue' +import { tagProps, TagProps } from './tag-types' +import { useStyle } from './hooks' +import './tag.scss' +// 类型声明 + +export default defineComponent({ + name: 'DTag', + props: tagProps, + emits: [], + setup(props: TagProps, { slots }) { + //获取type对应样式 + const tagClass = useStyle(props) + + return () => ( + <div class="devui-tag"> + <span class={tagClass.value} style="display: block;"> + {slots.default?.()} + </span> + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/textarea/__tests__/textarea.spec.ts b/packages/devui-vue/devui/textarea/__tests__/textarea.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d064cdf1ccf9b3be1ab6441e992962376667ae28 --- /dev/null +++ b/packages/devui-vue/devui/textarea/__tests__/textarea.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Textarea } from '../index'; + +describe('textarea test', () => { + it('textarea init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/textarea/index.ts b/packages/devui-vue/devui/textarea/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..03e83245a0c71c9c6c29e274dbd948d1b7663085 --- /dev/null +++ b/packages/devui-vue/devui/textarea/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Textarea from './src/textarea' + +Textarea.install = function(app: App): void { + app.component(Textarea.name, Textarea) +} + +export { Textarea } + +export default { + title: 'Textarea 多行文本框', + category: '数据录入', + status: '已完成', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Textarea as any) + } +} diff --git a/packages/devui-vue/devui/textarea/src/textarea-types.ts b/packages/devui-vue/devui/textarea/src/textarea-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..57acdbb2df3a0d9020db7d3495ac03f53449eac2 --- /dev/null +++ b/packages/devui-vue/devui/textarea/src/textarea-types.ts @@ -0,0 +1,48 @@ +import type { PropType, ExtractPropTypes } from 'vue'; + +export const textareaProps = { + id: { + type: String, + default: undefined, + }, + autofocus: { + type: Boolean, + default: false, + }, + showCount: { + type: Boolean, + default: false, + }, + placeholder: { + type: String, + default: undefined, + }, + value: { + type: String, + default: '', + }, + maxLength: { + type: [String, Number] as PropType<number | string>, + default: undefined, + }, + disabled: { + type: Boolean, + default: false, + }, + error: { + type: Boolean, + default: false, + }, + cssClass: { + type: String, + default: '', + }, + resize: { + type: String as PropType< + 'none' | 'vertical' | 'horizontal' | 'both' | 'inherit' + >, + default: 'none', + }, +} as const; + +export type TextareaProps = ExtractPropTypes<typeof textareaProps>; diff --git a/packages/devui-vue/devui/textarea/src/textarea.scss b/packages/devui-vue/devui/textarea/src/textarea.scss new file mode 100644 index 0000000000000000000000000000000000000000..248db7309b1d239993d312c47666bf9c1ccbdf55 --- /dev/null +++ b/packages/devui-vue/devui/textarea/src/textarea.scss @@ -0,0 +1,11 @@ +@import '../../style/core/form'; + +.devui-textarea-wrap { + .devui-textarea-show-count { + text-align: right; + color: inherit; + white-space: nowrap; + pointer-events: none; + font-size: $devui-font-size; + } +} diff --git a/packages/devui-vue/devui/textarea/src/textarea.tsx b/packages/devui-vue/devui/textarea/src/textarea.tsx new file mode 100644 index 0000000000000000000000000000000000000000..52c3f77ae594bc645c47aee6c066df8325eafe1c --- /dev/null +++ b/packages/devui-vue/devui/textarea/src/textarea.tsx @@ -0,0 +1,89 @@ +import { defineComponent, ref } from "vue"; +import { textareaProps, TextareaProps } from "./textarea-types"; +import "./textarea.scss"; + +export default defineComponent({ + name: "DTextarea", + props: textareaProps, + emits: ["update:value", "focus", "blur", "change", "keydown"], + setup(props: TextareaProps, ctx) { + const textareaCls = { + error: props.error, + [props.cssClass]: true, + }; + + const curValueRef = ref<string>(props.value); + const onInput = ($event: Event) => { + const inputValue = ($event.target as HTMLInputElement).value; + curValueRef.value = inputValue; + ctx.emit("update:value", inputValue); + }, + onFocus = ($event: Event) => { + ctx.emit("focus", $event); + }, + onBlur = ($event: Event) => { + ctx.emit("blur", $event); + }, + onChange = ($event: Event) => { + ctx.emit("change", ($event.target as HTMLInputElement).value); + }, + onKeydown = ($event: KeyboardEvent) => { + ctx.emit("keydown", $event); + }; + + return { + textareaCls, + onInput, + onFocus, + onBlur, + onChange, + onKeydown, + curValueRef, + autofocus: props.autofocus, + }; + }, + render() { + const { + id, + placeholder, + disabled, + maxLength, + resize, + textareaCls, + onInput, + onFocus, + onBlur, + onChange, + onKeydown, + showCount, + autofocus, + curValueRef, + } = this; + return ( + <div class="devui-textarea-wrap"> + <textarea + {...{ DTextarea: true }} + id={id} + value={curValueRef} + autofocus={autofocus} + placeholder={placeholder} + disabled={disabled} + maxlength={maxLength} + style={{ resize: resize }} + class={textareaCls} + onInput={onInput} + onFocus={onFocus} + onBlur={onBlur} + onChange={onChange} + onKeydown={onKeydown} + ></textarea> + {showCount && ( + <div class="devui-textarea-show-count"> + {curValueRef.length} + {!(maxLength ?? false) ? "" : " / " + maxLength} + </div> + )} + </div> + ); + }, +}); diff --git a/packages/devui-vue/devui/theme/core/theme.ts b/packages/devui-vue/devui/theme/core/theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..a21bfd182c219617ceb9883b6d325fc8223a9c57 --- /dev/null +++ b/packages/devui-vue/devui/theme/core/theme.ts @@ -0,0 +1,49 @@ +import { inBrowser } from '../../shared/util/common-var' + +class Theme { + static imports: any = {} + + static import(name: string): any { + return this.imports[name] + } + + static register(name: string, target: any): void { + this.imports[name] = target + } + + constructor(theme: string) { + this.applyTheme(theme) + } + + applyTheme(name: string): void { + const theme = Theme.imports[name] + if (!inBrowser) { + return; + } + + if (!theme) { + console.error(`主题 ${theme} 未注册!`) + return + } + + const id = 'devui-theme-variable' + const themeVariable = `:root { ${stringify(theme)} }` + let styleElement = document.getElementById(id) + if (styleElement) { + styleElement.innerText = themeVariable + } else { + styleElement = document.createElement('style') + styleElement.id = id + styleElement.innerText = themeVariable + document.head.appendChild(styleElement) + } + } +} + +function stringify(theme: any) { + return Object.entries(theme) + .map(([key, value]) => `--${key}:${value}`) + .join(';') +} + +export default Theme diff --git a/packages/devui-vue/devui/theme/theme.ts b/packages/devui-vue/devui/theme/theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..95be1ea38613a3fb93af485237c5a438ccebe530 --- /dev/null +++ b/packages/devui-vue/devui/theme/theme.ts @@ -0,0 +1,8 @@ +import Theme from './core/theme' +import dark from './themes/dark' +import light from './themes/light' + +Theme.register('dark', dark) +Theme.register('light', light) + +export default Theme diff --git a/packages/devui-vue/devui/theme/themes/dark.ts b/packages/devui-vue/devui/theme/themes/dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..f21377b65ffefa34e4ee92ac6d4521c7d796c311 --- /dev/null +++ b/packages/devui-vue/devui/theme/themes/dark.ts @@ -0,0 +1,92 @@ +export default { + 'devui-global-bg': '#202124', + 'devui-global-bg-normal': '#202124', + 'devui-base-bg': '#2E2F31', + 'devui-base-bg-dark': '#2e2f31', + 'devui-brand': '#5e7ce0', + 'devui-brand-foil': '#313a61', + 'devui-brand-hover': '#425288', + 'devui-brand-active': '#526ecc', + 'devui-brand-active-focus': '#344899', + 'devui-contrast': '#C7000B', + 'devui-text': '#E8E8E8', + 'devui-text-weak': '#A0A0A0', + 'devui-aide-text': '#909090', + 'devui-aide-text-stress': '#A0A0A0', + 'devui-placeholder': '#8A8A8A', + 'devui-light-text': '#ffffff', + 'devui-dark-text': '#252b3a', + 'devui-link': '#526ECC', + 'devui-link-active': '#344899', + 'devui-link-light': '#96adfa', + 'devui-link-light-active': '#beccfa', + 'devui-line': '#505153', + 'devui-dividing-line': '#3D3E40', + 'devui-block': '#606061', + 'devui-area': '#34363A', + 'devui-danger': '#f66f6a', + 'devui-warning': '#fac20a', + 'devui-waiting': '#5e6580', + 'devui-success': '#50d4ab', + 'devui-info': '#5e7ce0', + 'devui-initial': '#64676e', + 'devui-unavailable': '#5b5b5c', + 'devui-shadow': 'rgba(17, 18, 19, 0.4)', + 'devui-light-shadow': 'rgba(17, 18, 19, 0.5)', + // 图标 + 'devui-icon-text': '#E8E8E8', + 'devui-icon-bg': '#2E2F31', + 'devui-icon-fill': '#606061', + 'devui-icon-fill-hover': '#73788a', + 'devui-icon-fill-active': '#5e7ce0', + 'devui-icon-fill-active-hover': '#526ecc', + // 表单 + 'devui-form-control-line': '#505153', + 'devui-form-control-line-hover': '#909090', + 'devui-form-control-line-active': '#5e7ce0', + 'devui-form-control-line-active-hover': '#344899', + 'devui-list-item-active-bg': '#5e7ce0', + 'devui-list-item-active-text': '#ffffff', + 'devui-list-item-active-hover-bg': '#526ecc', + 'devui-list-item-hover-bg': '#383838', + 'devui-list-item-hover-text': '#526ecc', + 'devui-list-item-selected-bg': '#454545', + 'devui-list-item-strip-bg': '#383838', + // 禁用 + 'devui-disabled-bg': '#3D3E44', + 'devui-disabled-line': '#505153', + 'devui-disabled-text': '#7D7D7D', + 'devui-primary-disabled': '#2B3458', + 'devui-icon-fill-active-disabled': '#2B3458', + // 特殊背景色 + 'devui-label-bg': '#46443F', + 'devui-connected-overlay-bg': '#2F2F2F', + 'devui-connected-overlay-line': '#526ecc', + 'devui-fullscreen-overlay-bg': '#2E2F31', + 'devui-feedback-overlay-bg': '#4C4C4C', + 'devui-feedback-overlay-text': '#DFE1E6', + 'devui-embed-search-bg': '#383838', + 'devui-embed-search-bg-hover': '#3D3E40', + 'devui-float-block-shadow': 'rgba(94, 124, 224, 0.3)', + 'devui-highlight-overlay': 'rgba(255, 255, 255, 0.1)', + 'devui-range-item-hover-bg': '#454545', + // 按钮 + 'devui-primary': '#5e7ce0', + 'devui-primary-hover': '#425288', + 'devui-primary-active': '#344899', + 'devui-contrast-hover': '#D64A52', + 'devui-contrast-active': '#B12220', + // 状态 + 'devui-danger-line': '#985C5A', + 'devui-danger-bg': '#4B3A39', + 'devui-warning-line': '#8D6138', + 'devui-warning-bg': '#554434', + 'devui-info-line': '#546BB7', + 'devui-info-bg': '#383D4F', + 'devui-success-line': '#5D887D', + 'devui-success-bg': '#304642', + 'devui-primary-line': '#546BB7', + 'devui-primary-bg': '#383D4F', + 'devui-default-line': '#5e7ce0', + 'devui-default-bg': '#383838', +} \ No newline at end of file diff --git a/packages/devui-vue/devui/theme/themes/light.ts b/packages/devui-vue/devui/theme/themes/light.ts new file mode 100644 index 0000000000000000000000000000000000000000..b86c08ca99498e3fa557b970e5f034329a4c8cfc --- /dev/null +++ b/packages/devui-vue/devui/theme/themes/light.ts @@ -0,0 +1,135 @@ +export default { + // 基础变量 + 'devui-global-bg': '#f3f6f8', + 'devui-global-bg-normal': '#ffffff', + 'devui-base-bg': '#ffffff', + 'devui-base-bg-dark': '#333854', + 'devui-brand': '#5e7ce0', + 'devui-brand-foil': '#859bff', + 'devui-brand-hover': '#7693f5', + 'devui-brand-active': '#526ecc', + 'devui-brand-active-focus': '#344899', + 'devui-contrast': '#c7000b', + 'devui-text': '#252b3a', + 'devui-text-weak': '#575d6c', + 'devui-aide-text': '#8a8e99', + 'devui-aide-text-stress': '#575d6c', + 'devui-placeholder': '#8a8e99', + 'devui-light-text': '#ffffff', + 'devui-dark-text': '#252b3a', + 'devui-link': '#526ecc', + 'devui-link-active': '#526ecc', + 'devui-link-light': '#96adfa', + 'devui-link-light-active': '#beccfa', + 'devui-line': '#adb0b8', + 'devui-dividing-line': '#dfe1e6', + 'devui-block': '#ffffff', + 'devui-area': '#f8f8f8', + 'devui-danger': '#f66f6a', + 'devui-warning': '#fac20a', + 'devui-waiting': '#9faad7', + 'devui-success': '#50d4ab', + 'devui-info': '#5e7ce0', + 'devui-initial': '#e9edfa', + 'devui-unavailable': '#f5f5f6', + 'devui-shadow': 'rgba(0, 0, 0, 0.2)', + 'devui-light-shadow': 'rgba(0, 0, 0, 0.1)', + // 图标 + 'devui-icon-text': '#252b3a', + 'devui-icon-bg': '#ffffff', + 'devui-icon-fill': '#d3d5d9', + 'devui-icon-fill-hover': '#adb5ce', + 'devui-icon-fill-active': '#5e7ce0', + 'devui-icon-fill-active-hover': '#526ecc', + // 表单 + 'devui-form-control-line': '#adb0b8', + 'devui-form-control-line-hover': '#575d6c', + 'devui-form-control-line-active': '#5e7ce0', + 'devui-form-control-line-active-hover': '#344899', + 'devui-list-item-active-bg': '#5e7ce0', + 'devui-list-item-active-text': '#ffffff', + 'devui-list-item-active-hover-bg': '#526ecc', + 'devui-list-item-hover-bg': '#f2f5fc', + 'devui-list-item-hover-text': '#526ecc', + 'devui-list-item-selected-bg': '#e9edfa', + 'devui-list-item-strip-bg': '#f2f5fc', + // 禁用 + 'devui-disabled-bg': '#f5f5f6', + 'devui-disabled-line': '#dfe1e6', + 'devui-disabled-text': '#adb0b8', + 'devui-primary-disabled': '#beccfa', + 'devui-icon-fill-active-disabled': '#beccfa', + // 特殊背景色 + 'devui-label-bg': '#eef0f5', + 'devui-connected-overlay-bg': '#ffffff', + 'devui-connected-overlay-line': '#526ecc', + 'devui-fullscreen-overlay-bg': '#ffffff', + 'devui-feedback-overlay-bg': '#464d6e', + 'devui-feedback-overlay-text': '#dfe1e6', + 'devui-embed-search-bg': '#f2f5fc', + 'devui-embed-search-bg-hover': '#eef0f5', + 'devui-float-block-shadow': 'rgba(94, 124, 224, 0.3)', + 'devui-highlight-overlay': 'rgba(255, 255, 255, 0.8)', + 'devui-range-item-hover-bg': '#e9edfa', + // 按钮 + 'devui-primary': '#5e7ce0', + 'devui-primary-hover': '#7693f5', + 'devui-primary-active': '#344899', + 'devui-contrast-hover': '#d64a52', + 'devui-contrast-active': '#b12220', + // 状态 + 'devui-danger-line': '#f66f6a', + 'devui-danger-bg': '#ffeeed', + 'devui-warning-line': '#fa9841', + 'devui-warning-bg': '#fff3e8', + 'devui-info-line': '#5e7ce0', + 'devui-info-bg': '#f2f5fc', + 'devui-success-line': '#50d4ab', + 'devui-success-bg': '#edfff9', + 'devui-primary-line': '#5e7ce0', + 'devui-primary-bg': '#f2f5fc', + 'devui-default-line': '#5e7ce0', + 'devui-default-bg': '#f3f6f8', + // 字体设置相关 + 'devui-font-size': '12px', + 'devui-font-size-card-title': '14px', + 'devui-font-size-page-title': '16px', + 'devui-font-size-modal-title': '18px', + 'devui-font-size-price': '20px', + 'devui-font-size-data-overview': '24px', + 'devui-font-size-icon': '16px', + 'devui-font-size-sm': '12px', + 'devui-font-size-md': '12px', + 'devui-font-size-lg': '14px', + 'devui-font-title-weight': 'bold', + 'devui-font-content-weight': 'normal', + 'devui-line-height-base': '1.5', + // 圆角 + 'devui-border-radius': '2px', + 'devui-border-radius-feedback': '4px', + 'devui-border-radius-card': '6px', + // 阴影 + 'devui-shadow-length-base': '0 1px 4px 0', + 'devui-shadow-length-slide-left': '-2px 0 8px 0', + 'devui-shadow-length-slide-right': '2px 0 8px 0', + 'devui-shadow-length-connected-overlay': '0 2px 8px 0', + 'devui-shadow-length-hover': '0 4px 16px 0', + 'devui-shadow-length-feedback-overlay': '0 4px 16px 0', + 'devui-shadow-fullscreen-overlay': '0 8px 40px 0', + // 动效 + 'devui-animation-duration-slow': '300ms', + 'devui-animation-duration-base': '200ms', + 'devui-animation-duration-fast': '100ms', + 'devui-animation-ease-in': 'cubic-bezier(0.5, 0, 0.84, 0.25)', + 'devui-animation-ease-out': 'cubic-bezier(0.16, 0.75, 0.5, 1)', + 'devui-animation-ease-in-out': 'cubic-bezier(0.5, 0.05, 0.5, 0.95)', + 'devui-animation-ease-in-smooth': 'cubic-bezier(0.645, 0.045, 0.355, 1)', + 'devui-animation-linear': 'cubic-bezier(0, 0, 1, 1)', + // zIndex + 'devui-z-index-full-page-overlay': '1080', + 'devui-z-index-pop-up': '1060', + 'devui-z-index-dropdown': '1052', + 'devui-z-index-modal': '1050', + 'devui-z-index-drawer': '1040', + 'devui-z-index-framework': '1000' +} \ No newline at end of file diff --git a/packages/devui-vue/devui/time-axis/__tests__/time-axis.spec.ts b/packages/devui-vue/devui/time-axis/__tests__/time-axis.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6fd410f8cd1286d1c876fbd52c4cf0a281f76e80 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/__tests__/time-axis.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { TimeAxis } from '../index'; + +describe('time-axis test', () => { + it('time-axis init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/time-axis/index.ts b/packages/devui-vue/devui/time-axis/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4edffd52dcf3f043fddd35c818a481b3b56ace4e --- /dev/null +++ b/packages/devui-vue/devui/time-axis/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import TimeAxis from './src/time-axis' + +TimeAxis.install = function(app: App): void { + app.component(TimeAxis.name, TimeAxis) +} + +export { TimeAxis } + +export default { + title: 'TimeAxis 时间轴', + category: '数据展示', + status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(TimeAxis as any) + } +} diff --git a/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.scss b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..a819cfa1e9d10077233442134348da064ea7eb5f --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.scss @@ -0,0 +1,160 @@ +@import '../../../../style/theme/color'; + +.devui-time-axis-item-type { + &-primary { + border: 2px solid $devui-placeholder; + border-radius: 50%; + } + + &-right { + i { + color: $devui-success; + } + } + + &-danger { + path { + fill: $devui-danger; + } + + circle { + fill: $devui-light-text; + } + } + + &-warning { + i { + color: $devui-warning; + } + } + + &-running { + line-height: 16px; + text-align: center; + animation: devui-time-axis-running 1.5s linear infinite; + border: 2px solid $devui-success; + border-radius: 50%; + } +} + +.devui-time-axis-item-vertical-time-bottom { + display: flex; + + .devui-time-axis-item-axis { + display: flex; + flex-direction: column; + align-items: center; + } + + .devui-time-axis-item-dot { + &, + & > svg { + width: 18px; + height: 18px; + } + + & > i { + font-size: 18px; + } + } + + .devui-time-axis-item-custom-dot { + width: 18px; + height: 18px; + text-align: center; + } + + .devui-time-axis-item-line-time-bottom { + position: relative; + height: calc(100% - 36px); + border-left-width: 2px; + border-left-color: $devui-dividing-line; + } + + .devui-time-axis-line-style { + &-dashed { + border-left-style: dashed; + } + + &-solid { + border-left-style: solid; + } + + &-none { + border-left-style: none; + } + } + + .devui-time-axis-middle-zone { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } + + .devui-time-axis-item-data-time-bottom { + margin-left: 12px; + margin-bottom: 40px; + } + + .devui-time-axis-item-template { + margin-left: 12px; + margin-bottom: 24px; + } +} + +@keyframes devui-time-axis-running { + 0% { + transform: rotate(0deg); + color: $devui-success; + border-color: $devui-success; + } + + 50% { + transform: rotate(180deg); + color: $devui-success; + border-color: $devui-success; + } + + 100% { + transform: rotate(360deg); + color: $devui-success; + border-color: $devui-success; + } +} + +.devui-time-axis-item-data-hidden { + visibility: hidden; +} + +:host.devui-time-axis-item-horizontal-no-line { + width: auto !important; + + .devui-time-axis-item-data-horizontal-top { + width: max-content; + } + + .devui-time-axis-item-data-horizontal-bottom { + width: max-content; + } +} + +:host.devui-time-axis-item-vertical-no-line { + .devui-time-axis-item-data-time-bottom { + margin-bottom: 0; + } + + .devui-time-axis-item-data-vertical-left { + margin-bottom: 0; + } + + .devui-time-axis-item-data-vertical-right { + margin-bottom: 0; + } +} + +.devui-time-axis-item-horizontal-align-center { + position: relative; + width: fit-content; + transform: translateX(-50%); + left: 8px; +} diff --git a/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.tsx b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..15fae5660100e80a3e8a2117a88a9f22a9fc2952 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/index.tsx @@ -0,0 +1,32 @@ +import {defineComponent} from 'vue' + +import {timeAxisItemProps, TimeAxisItemProps} from './types' +import './index.scss' + +export default defineComponent({ + name: 'DTimeAxisItem', + props: timeAxisItemProps, + emits: [], + setup(props: TimeAxisItemProps, ctx) { + const itemClass = 'devui-time-axis-item' + return () => { + return ( + <div class={itemClass}> + <div class={`${itemClass}-data-left ${itemClass}-data-top`}> + <span> + {props.time} + </span> + </div> + <div class={`${itemClass}-axis`}> + <div class={`${itemClass}-line ${itemClass}-line-style-solid`}></div> + <div class={`${itemClass}-dot ${itemClass}-type-primary`} style={{borderColor: props.dotColor}}></div> + <div class={`${itemClass}-line ${itemClass}-line-style-solid`}></div> + </div> + <div class={`${itemClass}-data-right ${itemClass}-data-bottom`}> + {props.text} + </div> + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/time-axis/src/components/time-axis-item/types.ts b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..fba08a5ed5f787293acb330924a5927f1712b356 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/components/time-axis-item/types.ts @@ -0,0 +1,19 @@ +import type { PropType, ExtractPropTypes } from 'vue' + + + +export const timeAxisItemProps = { + time: { + type: String, + }, + text: { + type: String, + }, + + //可选,自定义时间圈颜色 + dotColor: { + type: String + } +} as const + +export type TimeAxisItemProps = ExtractPropTypes<typeof timeAxisItemProps> diff --git a/packages/devui-vue/devui/time-axis/src/time-axis-types.ts b/packages/devui-vue/devui/time-axis/src/time-axis-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb00d1b4fc1609451bc39c21cdd7eb491e12eca1 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/time-axis-types.ts @@ -0,0 +1,39 @@ +import type { PropType, ExtractPropTypes } from 'vue' +export type DataDirection = 'vertical' | 'horizontal' + + + +export interface DataItem { + //时间 + time: string + //文本内容 + text: string + // lineStyle?: Object<{}> + //可选,自定义时间圈颜色 + dotColor?: string + customDot?: string | HTMLElement + //时间点类型 + type?: 'primary' | 'success' | 'danger' | 'warning' + status?: 'runned' | 'running' | '' + position?: 'top' | 'bottom' | 'left' | 'right' + extraElement?: string | HTMLElement + iconClass?: string + data?: any +} + + + +export const timeAxisProps = { + //设置时间轴方向 + direction: { + type: String as PropType<DataDirection>, + default: 'vertical' + }, + //列表数据 + data: { + type: Array as PropType<DataItem[]>, + default:()=>[] + } +} as const + +export type TimeAxisProps = ExtractPropTypes<typeof timeAxisProps> diff --git a/packages/devui-vue/devui/time-axis/src/time-axis.scss b/packages/devui-vue/devui/time-axis/src/time-axis.scss new file mode 100644 index 0000000000000000000000000000000000000000..0a78557fdc4e81df1ad735d0eb20550c27233585 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/time-axis.scss @@ -0,0 +1,171 @@ +@import '../../style/theme/color'; + +$devui-time-axis-item-dot-size: 18px; + +.devui-time-axis { + &-vertical { + display: flex; + flex-direction: column; + align-items: center; + position: relative; + + .devui-time-axis-item { + display: flex; + flex-direction: row; + width: 100%; + + &-axis { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 12px; + } + + &-line { + position: relative; + height: calc(100% - #{$devui-time-axis-item-dot-size}); + border-left-width: 2px; + border-left-color: $devui-dividing-line; + + &:first-child { + display: none; + } + } + + &-data-left { + text-align: end; + margin-bottom: 24px; + height: $devui-time-axis-item-dot-size; + line-height: $devui-time-axis-item-dot-size; + flex: 1; + } + + &-data-right { + margin-bottom: 24px; + height: $devui-time-axis-item-dot-size; + line-height: $devui-time-axis-item-dot-size; + flex: 1; + } + + &-line-style { + &-dashed { + border-left-style: dashed; + } + + &-solid { + border-left-style: solid; + } + + &-dotted { + border-left-style: dotted; + } + + &-none { + border-left-style: none; + } + } + + .devui-time-axis-middle-zone { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } + } + } + + &-horizontal { + display: flex; + flex-direction: row; + align-items: center; + position: relative; + + .devui-time-axis-item { + display: flex; + flex-direction: column; + height: 100%; + + &-axis { + display: flex; + flex-direction: row; + align-items: center; + padding: 12px 0; + } + + &-line { + position: relative; + min-width: 20px; + width: calc(50% - calc(#{$devui-time-axis-item-dot-size} / 2)); + border-bottom-width: 2px; + border-bottom-color: $devui-dividing-line; + } + + &:first-child { + .devui-time-axis-item-line { + &:first-child { + opacity: 0; + } + } + } + + &-data-top { + text-align: center; + display: flex; + align-items: flex-end; + padding: 0 12px; + flex: 1; + } + + &-data-bottom { + text-align: center; + padding: 0 12px; + flex: 1; + } + + &-line-style { + &-dashed { + border-bottom-style: dashed; + } + + &-solid { + border-bottom-style: solid; + } + + &-dotted { + border-bottom-style: dotted; + } + + &-none { + border-bottom-style: none; + } + } + + .devui-time-axis-middle-zone { + position: absolute; + left: 50%; + transform: translate(-50%, -50%); + } + } + } +} + +.devui-time-axis-item { + &-dot { + &, + & > svg { + width: $devui-time-axis-item-dot-size; + height: $devui-time-axis-item-dot-size; + } + + & > i { + font-size: $devui-time-axis-item-dot-size; + } + } + + &:last-child { + .devui-time-axis-item-line { + &:last-child { + display: none; + } + } + } +} diff --git a/packages/devui-vue/devui/time-axis/src/time-axis.tsx b/packages/devui-vue/devui/time-axis/src/time-axis.tsx new file mode 100644 index 0000000000000000000000000000000000000000..03ae7416ef30f94c8fa9914c8c817d7ced486d19 --- /dev/null +++ b/packages/devui-vue/devui/time-axis/src/time-axis.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue' +import { timeAxisProps, TimeAxisProps } from './time-axis-types' +import TimeAxisItem from './components/time-axis-item' +import './time-axis.scss' + +export default defineComponent({ + name: 'DTimeAxis', + components: { TimeAxisItem }, + props: timeAxisProps, + emits: [], + setup(props: TimeAxisProps, ctx) { + return () => { + return ( + <div class={`devui-time-axis-${props.direction}`}> + { + props.data.map(item=> <TimeAxisItem {...item}/>) + } + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/time-picker/__tests__/time-picker.spec.ts b/packages/devui-vue/devui/time-picker/__tests__/time-picker.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..865b5c9d457cc1ced0481fa41b81c1120e2450e2 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/__tests__/time-picker.spec.ts @@ -0,0 +1,204 @@ +import { mount } from '@vue/test-utils'; +import DTimePicker from '../src/time-picker'; +import { nextTick, ref } from 'vue'; + +describe('time-picker test', () => { + it('time-picker init render', async () => { + + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker></d-time-picker>`, + + setup() { + return + } + }); + + const container = wrapper.find('.devui-time-picker'); + const timeUl = wrapper.findAll('.time-ul') + await nextTick() + expect(timeUl[0].element.childElementCount).toBe(24) + expect(timeUl[1].element.childElementCount).toBe(60) + expect(timeUl[2].element.childElementCount).toBe(60) + expect(container.classes()).toContain('devui-time-picker') + }) + + it('time-picker default open work', async () => { + + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker v-model="vModelValue" :time-picker-width="300" :autoOpen="autoOpen"></d-time-picker>`, + setup() { + + const vModelValue = ref('12:30:40') + const autoOpen = ref(true) + + return { + vModelValue, + autoOpen + } + } + }); + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + const tiemPopup = wrapper.find('.devui-time-popup') + + await nextTick() + expect(timeInput.element.value).toBe('12:30:40') + expect(tiemPopup.classes()).toContain('devui-show-time-popup') + expect(tiemPopup.attributes('style')).toMatch('width: 300px'); + + }); + + it('time-picker disabled work', async () => { + const wrapper = mount(DTimePicker, { + props: { + disabled: true, + }, + }); + + expect(wrapper.find('.devui-time-picker').classes()).toContain('picker-disabled') + expect(wrapper.find<HTMLInputElement>('.time-input').element.disabled).toBe(true) + }) + + it('time-picker min-time work', async () => { + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker min-time='01:04:30' v-model="vModelValue"></d-time-picker>`, + setup() { + const vModelValue = ref('01:03:00') + return { + vModelValue + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + await nextTick() + // 如果 v-mode 的时间超出 限制范围,将返回最小时间值 + expect(timeInput.element.value).toBe('01:04:30') + }) + + it('time-picker max-time work', async () => { + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker max-time='22:46:20' v-model="vModelValue"></d-time-picker>`, + setup() { + const vModelValue = ref('23:30:00') + return { + vModelValue + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + await nextTick() + expect(timeInput.element.value).toBe('22:46:20') + }) + + it('time-picker format mm:HH:ss work', async () => { + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker v-model="vModelValue" format='mm:HH:ss'></d-time-picker>`, + setup() { + const vModelValue = ref('23:30:00') + return { + vModelValue + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + await nextTick() + expect(timeInput.element.value).toBe('30:23:00') + }) + + it('time-picker format mm:ss work', async () => { + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker v-model="vModelValue" format='mm:ss'></d-time-picker>`, + setup() { + const vModelValue = ref('23:30:00') + return { + vModelValue + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + await nextTick() + expect(timeInput.element.value).toBe('30:00') + }) + + it('time-picker format hh:mm work', async () => { + const wrapper = mount({ + components: { DTimePicker }, + template: `<d-time-picker v-model="vModelValue" format='hh:mm'></d-time-picker>`, + setup() { + const vModelValue = ref('23:30:00') + return { + vModelValue + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + await nextTick() + expect(timeInput.element.value).toBe('23:30') + }) + + it('time-picker slot customViewTemplate work', async () => { + + const slotDemo = ref() + + const chooseTime = () => { + const timeObj = { + time: '21', + type: 'mm' + } + slotDemo.value.chooseTime(timeObj) + } + // 插槽内方法 -- 选择当前时间 + const chooseNowFun = () => { + const date = new Date() + const hour = date.getHours() > 9 ? date.getHours() : '0' + date.getHours() + const minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes() + const second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds() + const timeObj = { + time: hour + ':' + minute + ':' + second + } + slotDemo.value.chooseTime(timeObj) + + return timeObj.time + } + + const wrapper = mount({ + components: { DTimePicker }, + template: ` + <d-time-picker ref='slotDemo'> + <template v-slot:customViewTemplate> + <div class='slot-box'> + <div class='slot-bottom-now' @click='chooseNowFun'>choose now</div> + <div class='slot-bottom-one' @click='chooseTime' >choose 23:00</div> + </div> + </template> + </d-time-picker>`, + setup() { + return { + chooseNowFun, + chooseTime, + slotDemo + } + } + }) + + const timeInput = wrapper.find<HTMLInputElement>('.time-input') + const slotBottomNow = wrapper.find<HTMLElement>('.slot-bottom-now') + const slotBottomOne = wrapper.find<HTMLElement>('.slot-bottom-one') + await slotBottomNow.trigger('click') + expect(timeInput.element.value).toBe(chooseNowFun()) + + await slotBottomOne.trigger('click') + expect(timeInput.element.value).toMatch(/21/) + }) +}) diff --git a/packages/devui-vue/devui/time-picker/index.ts b/packages/devui-vue/devui/time-picker/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..85c682ab4d4724704f772c4c0ab14652024dd2c9 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import TimePicker from './src/time-picker' + +TimePicker.install = function(app: App): void { + app.component(TimePicker.name, TimePicker) +} + +export { TimePicker } + +export default { + title: 'TimePicker 时间选择器', + category: '数据录入', + status: '90%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(TimePicker as any) + } +} diff --git a/packages/devui-vue/devui/time-picker/src/components/popup-line/composables/use-popup-line.ts b/packages/devui-vue/devui/time-picker/src/components/popup-line/composables/use-popup-line.ts new file mode 100644 index 0000000000000000000000000000000000000000..93f8a55d9c550ce6c7f3f98272e63069ab050eb1 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/popup-line/composables/use-popup-line.ts @@ -0,0 +1,256 @@ +import { Ref, ref } from 'vue' +import { ArrType } from '../../../types' + +const usePopupLine =( + hourListRef:Array<ArrType>,minuteListRef:Array<ArrType>,secondListRef:Array<ArrType>, + minTime:string,maxTime:string,format:string,timeListDom:Ref, + ):any =>{ + + const activeTime = ref('00:00:00') + const activeHour = ref('00') + const activeMinute = ref('00') + const activeSecond = ref('00') + + const activeTimeFun = (e:any, item:ArrType, index:number)=>{ + if(item.isDisabled){ + return false + }else{ + setTimeActive(item,index) + e.target.parentElement.parentElement.scrollTop = index * 32 + + } + } + + + const setTimeActive = (item:ArrType,index:number)=>{ + + let activeTimeList = [] + let acitveTimeValue = ref('') + if(item.flag == 'hour'){ + activeTimeList = hourListRef + acitveTimeValue = activeHour + getItemAstrict(item) + }else if(item.flag == 'minute'){ + activeTimeList = minuteListRef + acitveTimeValue = activeMinute + getItemAstrict(item) + }else if(item.flag == 'second'){ + activeTimeList = secondListRef + acitveTimeValue = activeSecond + } + + activeTimeList.map((tiemItem,tiemeIndex)=>{ + tiemItem.isActive = index === tiemeIndex + }) + acitveTimeValue.value = activeTimeList[index].time + + + activeTime.value = `${activeHour.value}:${activeMinute.value}:${activeSecond.value}` + + if(activeTime.value < minTime){ + activeTime.value = minTime + resetTimeValue(minTime) + }else if(format == 'mm:ss' && `${activeMinute.value}:${activeSecond.value}` > maxTime.slice(3)){ + const newMinTime = minTime.slice(0,3) + maxTime.slice(3) + resetTimeValue(newMinTime) + }else if(activeTime.value > maxTime){ + activeTime.value = maxTime + resetTimeValue(maxTime) + } + } + + // 获取最大值 最小值 + const getItemAstrict = (item:ArrType):void=>{ + let min ='00' + let max ='00' + + const minTimeHour = minTime.split(':')[0] + const minTimeMinute = minTime.split(':')[1] + const minTimeSecond = minTime.split(':')[2] + + const maxTimeHour = maxTime.split(':')[0] + const maxTimeMinute = maxTime.split(':')[1] + const maxTimeSecond = maxTime.split(':')[2] + + if(item.flag == 'hour'){ + if(item.time == minTimeHour){ + min = minTimeMinute + setItemAstrict(minuteListRef,min,max) + activeMinute.value < minTimeMinute && setItemAstrict(secondListRef,minTimeSecond,max) + }else if ( item.time == maxTimeHour){ + max = maxTimeMinute + setItemAstrict(minuteListRef,min,max) + setItemAstrict(secondListRef,min,maxTimeSecond) + }else{ + setItemAstrict(minuteListRef,min,max) + setItemAstrict(secondListRef,min,max) + } + } + if(item.flag == 'minute' && format == 'mm:ss'){ + if(item.time == minTimeMinute){ + min = minTimeSecond + setItemAstrict(secondListRef,min,max) + }else if(item.time == maxTimeMinute){ + max = maxTimeSecond + setItemAstrict(secondListRef,min,max) + } else{ + setItemAstrict(secondListRef,min,max) + } + }else if(item.flag == 'minute'){ + if(activeHour.value == minTimeHour && item.time == minTimeMinute){ + min = minTimeSecond + setItemAstrict(secondListRef,min,max) + }else if(activeHour.value == maxTimeHour && item.time == maxTimeMinute){ + max = maxTimeSecond + setItemAstrict(secondListRef,min,max) + } else{ + setItemAstrict(secondListRef,min,max) + } + } + + } + // 设置最大值 最小值 + const setItemAstrict = (timeArr:Array<ArrType>,min:string,max:string) =>{ + timeArr.map(itme=>{ + if(min !='00' && itme.time < min){ + itme.isDisabled = true + }else if(max !='00' && itme.time > max){ + itme.isDisabled = true + }else{ + itme.isDisabled = false + } + }) + } + + // 指定时间 + const resetTimeValue = (time:string)=>{ + const timeValueArr = time.split(':') + const minTiveArr = minTime.split(':') + + let hh = 0 + let mm = 0 + let ss = 0 + + if(format == 'hh:mm:ss'){ + + hh = parseInt(timeValueArr[0]) + mm = parseInt(timeValueArr[1]) + ss = parseInt(timeValueArr[2]) + + timeListDom.value.children[0].lastElementChild.children[0].scrollTop = hh * 32 + timeListDom.value.children[1].lastElementChild.children[0].scrollTop = mm * 32 + timeListDom.value.children[2].lastElementChild.children[0].scrollTop = ss * 32 + + activeHour.value = timeValueArr[0] + activeMinute.value = timeValueArr[1] + activeSecond.value = timeValueArr[2] + + resetTimeActive(hourListRef,timeValueArr[0]) + resetTimeActive(minuteListRef,timeValueArr[1]) + resetTimeActive(secondListRef,timeValueArr[2]) + + resetTimeAstrict(hourListRef,activeHour.value) + resetTimeAstrict(minuteListRef,activeMinute.value) + + } + else if(format == 'mm:hh:ss'){ + hh = parseInt(timeValueArr[0]) + mm = parseInt(timeValueArr[1]) + ss = parseInt(timeValueArr[2]) + + timeListDom.value.children[0].lastElementChild.children[0].scrollTop = mm * 32 + timeListDom.value.children[1].lastElementChild.children[0].scrollTop = hh * 32 + timeListDom.value.children[2].lastElementChild.children[0].scrollTop = ss * 32 + + activeHour.value = timeValueArr[0] + activeMinute.value = timeValueArr[1] + activeSecond.value = timeValueArr[2] + + resetTimeActive(hourListRef,timeValueArr[0]) + resetTimeActive(minuteListRef,timeValueArr[1]) + resetTimeActive(secondListRef,timeValueArr[2]) + + resetTimeAstrict(hourListRef,activeHour.value) + resetTimeAstrict(minuteListRef,activeMinute.value) + + }else if(format == 'hh:mm'){ + + hh = parseInt(timeValueArr[0]) + mm = parseInt(timeValueArr[1]) + + timeListDom.value.children[0].lastElementChild.children[0].scrollTop = hh * 32 + timeListDom.value.children[1].lastElementChild.children[0].scrollTop = mm * 32 + + activeHour.value = timeValueArr[0] + activeMinute.value = timeValueArr[1] + + resetTimeActive(hourListRef,timeValueArr[0]) + resetTimeActive(minuteListRef,timeValueArr[1]) + + resetTimeAstrict(hourListRef,activeHour.value) + + }else if(format == 'mm:ss'){ + + mm = parseInt(timeValueArr[1]) + ss = parseInt(timeValueArr[2]) + + timeListDom.value.children[0].lastElementChild.children[0].scrollTop = mm * 32 + timeListDom.value.children[1].lastElementChild.children[0].scrollTop = ss * 32 + + activeHour.value = minTiveArr[0] + activeMinute.value = timeValueArr[1] + activeSecond.value = timeValueArr[2] + + resetTimeActive(minuteListRef,timeValueArr[1]) + resetTimeActive(secondListRef,timeValueArr[2]) + + resetTimeAstrict(minuteListRef,activeMinute.value) + } + } + + // 解决清空之后,再次打开 最大值最小值限制范围失效 + const resetTimeAstrict = (timeArr:Array<ArrType>,time:string) =>{ + timeArr.map(item=>{ + if(item.time == time){ + getItemAstrict(item) + } + }) + } + + // 指定选中 + const resetTimeActive = (timeArr:Array<ArrType>,itemValue:string) =>{ + timeArr.map( item =>{ + item.isActive = item.time === itemValue + }) + } + + // 暂时返回选中 时 分 秒 + const getNewTime = ()=>{ + return { activeTime,activeHour,activeMinute,activeSecond } + } + + // 回到顶部 + const resetScrollTop = ()=>{ + for (let i = 0; i < timeListDom.value.children.length; i++) { + timeListDom.value.children[i].lastElementChild.children[0].scrollTop = 0 + } + } + + return{ + activeTime, + activeHour, + activeMinute, + activeSecond, + activeTimeFun, + resetTimeValue, + getNewTime, + resetScrollTop + } +} + +export { + usePopupLine +} + + + diff --git a/packages/devui-vue/devui/time-picker/src/components/popup-line/index.scss b/packages/devui-vue/devui/time-picker/src/components/popup-line/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..52ba7c3eb5b43ab0561938029936b725f421f273 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/popup-line/index.scss @@ -0,0 +1,76 @@ +@import '../../../../style/theme/color'; +@import '../../../../style/theme/shadow'; +@import '../../../../style/theme/corner'; +@import '../../../../style/core/_font'; + +.devui-time-list { + width: 100%; + height: 256px; + border-bottom: 1px solid $devui-dividing-line; + + .time-item { + height: 100%; + display: inline-block; + border-right: 1px solid $devui-dividing-line; + overflow-y: auto; + + &:last-child { + border-right: none; + } + + .time-ul { + width: 100%; + height: 100%; + cursor: pointer; + padding: 0; + margin: 0 auto; + list-style: none; + + .time-li { + display: block; + box-sizing: border-box; + list-style: none; + text-align: center; + margin: 0; + height: 26px; + overflow: hidden; + line-height: 26px; + margin-bottom: 6px; + font-size: 0; + color: $devui-text; + + &:hover { + background-color: $devui-list-item-hover-bg; + color: $devui-list-item-hover-text; + } + + span { + display: block; + font-size: 16px; + } + } + + &:last-child::after { + content: ''; + display: block; + height: 224px; + } + + .active-li { + background-color: $devui-list-item-active-bg; + color: $devui-list-item-active-text; + + &:hover { + background-color: $devui-list-item-active-bg; + color: $devui-list-item-active-text; + } + } + + .disabled-li { + background-color: $devui-disabled-bg; + color: $devui-disabled-text; + cursor: not-allowed; + } + } + } +} diff --git a/packages/devui-vue/devui/time-picker/src/components/popup-line/index.tsx b/packages/devui-vue/devui/time-picker/src/components/popup-line/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3cd2538158b7759516032fb3ad1dd5babf657333 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/popup-line/index.tsx @@ -0,0 +1,123 @@ +import { ref, defineComponent, onMounted } from 'vue' +import { usePopupLine } from './composables/use-popup-line' +import { ArrType } from '../../types' +import TimeScroll from '../time-scroll' + +import './index.scss' + + +export default defineComponent({ + name:'DTimeList', + components:{ TimeScroll }, + props:{ + hourList:{ + type:Array, + default:()=>[] + }, + minuteList:{ + type:Array, + default:()=>[] + }, + secondList:{ + type:Array, + default:()=>[] + }, + format:{ + type:String, + default:'hh:mm:ss' + }, + minTime:{ + type:String, + default:'00:00:00' + }, + maxTime:{ + type:String, + default:'23:59:59' + } + }, + + setup(props,ctx,){ + const timeListDom = ref<Element>() + const { + getNewTime, + activeTimeFun, + resetTimeValue, + resetScrollTop + } = usePopupLine( + props.hourList as Array<ArrType>, + props.minuteList as Array<ArrType>, + props.secondList as Array<ArrType>, + props.minTime, + props.maxTime, + props.format, + timeListDom, + ) + + + const setOutoTime = (time:string)=>{ + resetTimeValue(time) + } + + const TimeLi = (timeArr:Array<ArrType>):any=>{ + return ( + timeArr.map((item: ArrType, index: number) => { + return ( + <li + class={`time-li ${item.flag}Id-${index} ${item.isActive ? 'active-li' : ''} ${item.isDisabled ? 'disabled-li' : ''}`} + onClick={(e) => { activeTimeFun(e, item, index,) }} + > + <span>{item.time}</span> + </li> + ) + }) + ) + } + + const TimeUl = (timeList:Array<ArrType>)=>{ + return ( + <div class='time-item' style={{'width':props.format.length>6?'33.333%':'50%'}}> + <TimeScroll> + <ul class='time-ul'> + {TimeLi(timeList)} + </ul> + </TimeScroll> + </div> + ) + } + + const formatTimeUl = ()=>{ + const timeList = { + 'hh':props.hourList, + 'mm':props.minuteList, + 'ss':props.secondList + } + + const timeFormatArr = (props.format as string).split(':') + + return( + timeFormatArr.map((timeItme)=>{ + return( + TimeUl(timeList[timeItme]) + ) + }) + ) + } + + ctx.expose({ + resetScrollTop,setOutoTime,getNewTime + }) + + return ()=>{ + return ( + <div class='devui-time-list' ref={timeListDom}> + { + formatTimeUl() + } + </div> + ) + } + } +}) + + + \ No newline at end of file diff --git a/packages/devui-vue/devui/time-picker/src/components/time-popup/index.scss b/packages/devui-vue/devui/time-picker/src/components/time-popup/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..161c6f300c997374f3bbb45c28cafc08438de294 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/time-popup/index.scss @@ -0,0 +1,34 @@ +@import '../../../../style/theme/color'; +@import '../../../../style/theme/shadow'; +@import '../../../../style/theme/corner'; +@import '../../../../style/theme/z-index'; + +.devui-time-popup { + height: 310px; + background-color: $devui-connected-overlay-bg; + box-shadow: 0 0 2px 2px $devui-shadow; + border-radius: $devui-border-radius; + border: 1px solid $devui-line; + overflow: hidden; + position: fixed; + z-index: -1; + visibility: hidden; + opacity: 0; + transition: 0.3s; + transition-property: visibility, opacity, z-index; +} + +.devui-show-time-popup { + visibility: visible; + z-index: $devui-z-index-dropdown; + opacity: 1; + transition-property: visibility, opacity, z-index; +} + +.devui-time-popup-btn { + height: 60px; + padding: 0 10px; + display: flex; + justify-content: space-between; + align-items: center; +} diff --git a/packages/devui-vue/devui/time-picker/src/components/time-popup/index.tsx b/packages/devui-vue/devui/time-picker/src/components/time-popup/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bba0cd3a1951d8e70e098091a2f3d6b34d1ec767 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/time-popup/index.tsx @@ -0,0 +1,112 @@ +import { defineComponent, reactive, ref,watch ,onMounted} from 'vue'; +import { initializeTimeData,setTimeAstrict } from '../../utils' +import TimeList from '../popup-line/index' +import { Button } from '../../../../button/index'; + +import './index.scss' +export default defineComponent({ + name:'DTimePopup', + components:{ + TimeList,Button + }, + props:{ + showPopup:{ + type:Boolean, + default:false + }, + popupTop:{ + type:Number, + default:-100 + }, + popupLeft:{ + type:Number, + default:-100 + }, + popupWidth:{ + type:Number, + default:300 + }, + popupFormat:{ + type:String, + default:'hh:mm:ss' + }, + minTime:{ + type:String, + default:'00:00:00' + }, + maxTime:{ + type:String, + default:'23:59:59' + }, + bindData:{ + type:String, + default:'00:00:00' + } + }, + emits:['subData'], + setup(props,ctx){ + const popupDome = ref<Node>() + const timeListDom = ref() + const hourList = initializeTimeData('hour') + const minuteList = initializeTimeData('minute') + const secondList = initializeTimeData('second') + + onMounted(()=>{ + setTimeAstrict(hourList,minuteList,secondList,props.minTime,props.maxTime,props.popupFormat) + }) + + watch(()=>[props.showPopup,props.bindData],([showPopup,newTimeVal],[oldShowPopup,oldTimeVal])=>{ + if(showPopup || newTimeVal != oldTimeVal){ + timeListDom.value.setOutoTime(newTimeVal) + }else{ + timeListDom.value.resetScrollTop() + } + }) + + const changTimeData = ()=>{ + return timeListDom.value.getNewTime() + } + + const subDataFun = (e:MouseEvent)=>{ + e.stopPropagation() + ctx.emit('subData') + } + + ctx.expose({ + changTimeData + }) + + return()=>{ + return( + <> + <div ref={popupDome} + class={`devui-time-popup ${props.showPopup ? 'devui-show-time-popup' : ''}`} + style={{'width': props.popupWidth + 'px','top':props.popupTop+'px','left':props.popupLeft+'px'}}> + <TimeList + ref={timeListDom} + hourList={hourList} + minuteList={minuteList} + secondList={secondList} + minTime={props.minTime} + maxTime={props.maxTime} + format={props.popupFormat} + /> + + <div class="devui-time-popup-btn" > + <div class='popup-slots'> + { + ctx.slots.default?.() + } + </div> + <div onClick={subDataFun}> + <Button btnStyle="common">确定</Button> + </div> + + </div> + </div> + </> + ) + } + } +}) + diff --git a/packages/devui-vue/devui/time-picker/src/components/time-scroll/composables/use-time-scroll.ts b/packages/devui-vue/devui/time-picker/src/components/time-scroll/composables/use-time-scroll.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1c039738c1961aadb011b8bb7f0ef01ecbc78d3 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/time-scroll/composables/use-time-scroll.ts @@ -0,0 +1,95 @@ +import { ref } from 'vue' + +export default function useTimeScroll():any{ + const scrollBoxDom = ref() + const scrollContentDom = ref() + const scrollThumbDom = ref() + const scrollTrackDom = ref() + + const isDown = ref(false) + + // 获取滚动条 thumb高度 + const getScrollHeight=()=>{ + const thumbHeight = (scrollContentDom.value.clientHeight / scrollContentDom.value.scrollHeight) * 100 + scrollThumbDom.value.style.height = thumbHeight + '%' + } + + // 设置滚动条 thumb位置 + const setVirtualScroll =()=>{ + const thumbMoveY = (scrollContentDom.value.scrollTop * 100 / scrollContentDom.value.clientHeight); + scrollThumbDom.value.style.transform = `translateY(${thumbMoveY}%)` + } + + // 点击轨道 thumb滚动到相应位置 + const clickTrackFun = (e:MouseEvent)=>{ + const offset = Math.abs(scrollTrackDom.value.getBoundingClientRect().top - e.clientY) + const thumbCenter = scrollThumbDom.value.offsetHeight / 2; + const thumbPosition = (offset - thumbCenter) * 100 / scrollContentDom.value.offsetHeight; + scrollContentDom.value.scrollTop = (thumbPosition * scrollContentDom.value.scrollHeight / 100); + scrollContentDom.value.style.top = scrollContentDom.value.scrollTop + 'px' + } + + // 鼠标拖到 + const mouseDownThum = ()=>{ + isDown.value = true + scrollTrackDom.value.style.opacity = 1 + } + // 鼠标离开 + const mouseOutThum = (e:MouseEvent)=>{ + isDown.value = false + thumbMouseMove(e) + } + + const thumbMouseMove = (e:any)=>{ + + const path = (e.composedPath && e.composedPath()) || e.path + + if(path.includes(scrollBoxDom.value) || isDown.value){ + scrollTrackDom.value.style.opacity = 1 + }else{ + scrollTrackDom.value.style.opacity = 0 + } + + if( !isDown.value ) return + clickTrackFun(e) + + } + + const getScrollWidth=()=>{ + const ua = navigator.userAgent + let marginRight = -20 + + if (ua.indexOf('Chrome') > -1) { + marginRight = -8 + }else{ + const outer = document.createElement('div'); + outer.className = 'devui-scrollbar-wrap'; + outer.style.width = '100px'; + outer.style.visibility = 'hidden'; + outer.style.position = 'absolute'; + outer.style.top = '-9999px'; + document.body.appendChild(outer); + + const widthNoScroll = outer.offsetWidth; + outer.style.overflow = 'scroll'; + + const inner = document.createElement('div'); + inner.style.width = '100%'; + outer.appendChild(inner); + + const widthWithScroll = inner.offsetWidth; + outer.parentNode.removeChild(outer); + + marginRight = (widthNoScroll - widthWithScroll + 3) * -1; + } + + return marginRight + } + + + return{ + scrollThumbDom,scrollTrackDom,scrollContentDom,scrollBoxDom,isDown, + getScrollHeight,setVirtualScroll,clickTrackFun,mouseDownThum,mouseOutThum,thumbMouseMove, + getScrollWidth + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.scss b/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..b263596ea62e97f4942c681c03fed85e962751b2 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.scss @@ -0,0 +1,42 @@ +@import '../../../../style/theme/color'; + +.devui-scroll-box { + width: 100%; + height: 100%; + overflow: hidden; + position: relative; + + * { + user-select: none; + } + + .box-content { + height: 100%; + overflow-y: auto; + overflow-x: hidden; + scroll-behavior: smooth; + } + + .box-content-behavior-auto { + scroll-behavior: auto; + } + + .box-sroll { + width: 8px; + height: 100%; + position: absolute; + right: 0; + top: 0; + opacity: 0; + background-color: rgba(212, 107, 107, 0); + + .scroll-child { + width: 100%; + position: absolute; + top: 0; + right: 0; + background: $devui-line; + border-radius: 8px; + } + } +} diff --git a/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.tsx b/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..36cf4c2e9b6f041b235c8df502f5bd395d58c3af --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/components/time-scroll/index.tsx @@ -0,0 +1,63 @@ +import { defineComponent, onBeforeUnmount, onMounted, onUnmounted } from 'vue' +import useTimeScroll from './composables/use-time-scroll' + +import './index.scss' + +export default defineComponent({ + name:'DTimeScroll', + setup(props,ctx){ + const { + scrollBoxDom, + scrollThumbDom, + scrollTrackDom, + scrollContentDom,isDown, + getScrollHeight, + setVirtualScroll, + clickTrackFun, + mouseDownThum, + mouseOutThum, + thumbMouseMove, + getScrollWidth + }=useTimeScroll() + const marginRight = getScrollWidth() + + onMounted(()=>{ + getScrollWidth() + getScrollHeight() + scrollBoxDom.value.addEventListener('click',setVirtualScroll) + scrollContentDom.value.addEventListener('scroll',setVirtualScroll) + scrollThumbDom.value.addEventListener('mousedown',mouseDownThum) + document.addEventListener('mouseup',mouseOutThum) + document.addEventListener('mousemove',thumbMouseMove) + }) + onBeforeUnmount(()=>{ + scrollBoxDom.value.removeEventListener('click',setVirtualScroll) + scrollContentDom.value.removeEventListener('scroll',setVirtualScroll) + scrollThumbDom.value.removeEventListener('mousedown',mouseDownThum) + }) + onUnmounted(()=>{ + document.removeEventListener('mouseup',mouseOutThum) + document.removeEventListener('mousemove',thumbMouseMove) + }) + + return()=>{ + return ( + <> + <div ref={scrollBoxDom} class="devui-scroll-box"> + <div ref={scrollContentDom} class={`box-content ${ isDown.value ? 'box-content-behavior-auto':''}`} + style={{'margin-right': marginRight + 'px'}}> + { + ctx.slots.default?.() + } + </div> + + <div ref={scrollTrackDom} class="box-sroll" onClick={clickTrackFun}> + <div ref={scrollThumbDom} class="scroll-child"></div> + </div> + </div> + </> + ) + } + + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/time-picker/src/composables/use-time-picker.ts b/packages/devui-vue/devui/time-picker/src/composables/use-time-picker.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b2f58b9dfcb0998870e73930f57ee2ec1a6e027 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/composables/use-time-picker.ts @@ -0,0 +1,175 @@ +import { Ref, ref } from 'vue' +import { TimeObj } from '../types' +import { getPositionFun } from '../utils' + +export default function useTimePicker( + hh:Ref,mm:Ref,ss:Ref,minTime:string,maxTime:string,format:string, + autoOpen:boolean,disabled:boolean,value:string + ):any{ + const isActive = ref(false) + const showPopup = ref(false) + const devuiTimePicker = ref() + const inputDom = ref() + const left = ref(-100) + const top = ref(-100) + const timePopupDom = ref() + const timePickerValue = ref('') + const showClearIcon = ref(false) + const firsthandActiveTime = ref(`${hh.value}:${mm.value}:${ss.value}`) + const vModeValue = ref(value) + + const getPopupPosition = ()=>{ + getPositionFun(devuiTimePicker.value,left,top) + } + + const clickVerifyFun = (e: any) => { + e.stopPropagation() + isActive.value = false + showPopup.value = false + + if(disabled) return + + const path = (e.composedPath && e.composedPath()) || e.path + const inInputDom = path.includes(devuiTimePicker.value) + inInputDom && mouseInIputFun() + } + + const mouseInIputFun = ()=>{ + if(firsthandActiveTime.value == '00:00:00'){ + + const vModelValueArr = vModeValue.value.split(':') + const minTimeValueArr = minTime.split(':') + + vModeValue.value == '' + ? vModeValue.value = '00:00:00' + : '' + + if( vModeValue.value > minTime ){ + firsthandActiveTime.value = vModeValue.value + setInputValue(vModelValueArr[0],vModelValueArr[1],vModelValueArr[2]) + }else{ + firsthandActiveTime.value = minTime + setInputValue(minTimeValueArr[0],minTimeValueArr[1],minTimeValueArr[2]) + } + } + + isActive.value = true + showPopup.value = true + } + + /** + * 判断v-model 绑定的时间是否超出 最大值 最小值 范围 + * 如果带有格式化 , 将执行格式化 + * */ + const vModelIsBeyond = ()=>{ + if(vModeValue.value != '' && vModeValue.value < minTime){ + vModeValue.value = minTime + }else if( vModeValue.value != '' && vModeValue.value > maxTime ){ + vModeValue.value = maxTime + } + + const vModelValueArr = vModeValue.value.split(':') + vModeValue.value && setInputValue(vModelValueArr[0],vModelValueArr[1],vModelValueArr[2]) + } + + + const getTimeValue = (e:MouseEvent)=>{ + e.stopPropagation() + if(showPopup.value){ + hh.value = timePopupDom.value.changTimeData().activeHour.value + mm.value = timePopupDom.value.changTimeData().activeMinute.value + ss.value = timePopupDom.value.changTimeData().activeSecond.value + firsthandActiveTime.value = `${hh.value}:${mm.value}:${ss.value}` + setInputValue(hh.value,mm.value,ss.value) + } + } + + const setInputValue = (hh:string,mm:string,ss:string)=> { + if(format == 'hh:mm:ss'){ + vModeValue.value = `${hh}:${mm}:${ss}` + }else if(format == 'mm:hh:ss'){ + vModeValue.value = `${mm}:${hh}:${ss}` + }else if(format == 'hh:mm'){ + vModeValue.value = `${hh}:${mm}` + }else if(format == 'mm:ss'){ + vModeValue.value = `${mm}:${ss}` + } + } + + const clearAll = (e:MouseEvent)=>{ + e.stopPropagation() + showPopup.value = false + + if(minTime != '00:00:00'){ + const minTimeArr = minTime.split(':') + hh.value = minTimeArr[0] + mm.value = minTimeArr[1] + ss.value = minTimeArr[2] + }else{ + hh.value = '00' + mm.value = '00' + ss.value = '00' + } + firsthandActiveTime.value = `${hh.value}:${mm.value}:${ss.value}` + setInputValue(hh.value,mm.value,ss.value) + } + + const isOutOpen =()=>{ + if(autoOpen){ + + const timeArr = vModeValue.value.split(':') + hh.value = timeArr[0] + mm.value = timeArr[1] + ss.value = timeArr[2] + + firsthandActiveTime.value = vModeValue.value + + setInputValue(hh.value,mm.value,ss.value) + + isActive.value = true + showPopup.value = autoOpen + } + } + + // slot -- 选择时间 + const chooseTime = (slotTime:TimeObj) => { + if (slotTime.type) { + if (slotTime.type.toLowerCase() == 'hh') { + hh.value = slotTime.time + } else if (slotTime.type.toLowerCase() == 'mm') { + mm.value = slotTime.time + } else if (slotTime.type.toLowerCase() == 'ss') { + ss.value = slotTime.time + } + firsthandActiveTime.value = `${hh.value}:${mm.value}:${ss.value}` + setInputValue(hh.value,mm.value,ss.value) + } else { + const timeArr = slotTime.time.split(':') + hh.value = timeArr[0] + mm.value = timeArr[1] + ss.value = timeArr[2] + firsthandActiveTime.value = `${hh.value}:${mm.value}:${ss.value}` + setInputValue(hh.value,mm.value,ss.value) + } + } + + return { + isActive, + showPopup, + devuiTimePicker, + timePickerValue, + inputDom, + timePopupDom, + left,top, + showClearIcon, + firsthandActiveTime, + vModeValue, + getPopupPosition, + getTimeValue, + clickVerifyFun, + isOutOpen, + vModelIsBeyond, + clearAll, + chooseTime + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/time-picker/src/time-picker-types.ts b/packages/devui-vue/devui/time-picker/src/time-picker-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..498f69297a676a65871c8711c9c87bc22350cbf6 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/time-picker-types.ts @@ -0,0 +1,40 @@ +import { ExtractPropTypes, PropType } from 'vue'; + +export const timePickerProps = { + modelValue:{ + type: String, + default: '' + }, + placeholder: { + type: String, + default: '00:00:00' + }, + disabled: { + type: Boolean, + default: false + }, + timePickerWidth: { + type: Number, + default: 212 + }, + minTime: { + type: String, + default: '00:00:00' + // 默认时间优先级:minTime > modelValue + }, + maxTime: { + type: String, + default: '23:59:59' + }, + format:{ + type:String, + default:'hh:mm:ss' + }, + autoOpen:{ + type:Boolean, + default:false + } +} as const; + + +export type TimePickerProps = ExtractPropTypes<typeof timePickerProps>; diff --git a/packages/devui-vue/devui/time-picker/src/time-picker.scss b/packages/devui-vue/devui/time-picker/src/time-picker.scss new file mode 100644 index 0000000000000000000000000000000000000000..91d712b0ff9933c0338b1d48bf31527cbb6805a4 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/time-picker.scss @@ -0,0 +1,56 @@ +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; + +.devui-time-picker { + width: 200px; + box-sizing: border-box; + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid $devui-form-control-line; + position: relative; + transition: 0.2s; + + &:hover { + border: 1px solid $devui-form-control-line-hover; + } + + .time-input { + border: none; + outline: none; + width: 100%; + background-color: $devui-base-bg; + color: $devui-text; + } + + .time-input-icon { + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + background-color: $devui-base-bg; + + div { + text-align: right; + height: 25px; + line-height: 22px; + padding: 0 4px; + } + } +} + +.time-picker-active { + border: 1px solid $devui-form-control-line-active !important; +} + +.picker-disabled { + background-color: $devui-unavailable; + cursor: no-drop; + + :not(.time-input-icon) { + background-color: $devui-unavailable; + cursor: no-drop; + } +} diff --git a/packages/devui-vue/devui/time-picker/src/time-picker.tsx b/packages/devui-vue/devui/time-picker/src/time-picker.tsx new file mode 100644 index 0000000000000000000000000000000000000000..15be03e08c1ec8b8f58aff5dd79aabb5a4f48158 --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/time-picker.tsx @@ -0,0 +1,121 @@ +import { defineComponent, ref, onMounted, onUnmounted, watch } from 'vue' +import { TimePickerProps, timePickerProps } from './time-picker-types' +import { Icon } from '../../icon' +import useTimePicker from './composables/use-time-picker' +import TimePopup from './components/time-popup/index' + +import './time-picker.scss' + +export default defineComponent({ + name: 'DTimePicker', + components: { TimePopup }, + props: timePickerProps, + emits: ['selectedTimeChage','update:modelValue'], + setup(props: TimePickerProps, ctx) { + + const activeHour = ref('00') + const activeMinute = ref('00') + const activeSecond = ref('00') + const format = props.format.toLowerCase() + + const { + isActive, + showPopup, + devuiTimePicker, + inputDom, + left,top, + showClearIcon, + firsthandActiveTime, + chooseTime, + getTimeValue, + clickVerifyFun, + isOutOpen, + vModelIsBeyond, + clearAll, + timePopupDom, + vModeValue, + getPopupPosition + } = useTimePicker(activeHour,activeMinute,activeSecond,props.minTime,props.maxTime,format,props.autoOpen,props.disabled,props.modelValue) + + + const selectedTimeChage = (e:MouseEvent) => { + isActive.value = false + showPopup.value = false + ctx.emit('selectedTimeChage', vModeValue.value) + } + + onMounted(() => { + getPopupPosition() + isOutOpen() + vModelIsBeyond() + document.addEventListener('click', clickVerifyFun) + document.addEventListener('click',getTimeValue) + document.addEventListener('scroll',getPopupPosition) + window.addEventListener('resize',getPopupPosition) + }) + onUnmounted(() => { + document.removeEventListener('click', clickVerifyFun) + document.removeEventListener('click',getTimeValue) + document.removeEventListener('scroll',getPopupPosition) + window.removeEventListener('resize',getPopupPosition) + }) + + watch(vModeValue,(newValue:string)=>{ + ctx.emit('update:modelValue',vModeValue.value) + if(newValue != props.minTime && newValue != '00:00'){ + showClearIcon.value = true + }else{ + showClearIcon.value = false + } + }) + + ctx.expose({ + clearAll,chooseTime + }) + + return () => { + return ( + <> + <div class={`devui-time-picker ${isActive.value ? 'time-picker-active' : ''} ${props.disabled ? 'picker-disabled' : ''}`} + ref={devuiTimePicker} + > + <TimePopup + ref={timePopupDom} + showPopup={showPopup.value} + popupTop={top.value} + popupLeft={left.value} + popupWidth={props.timePickerWidth} + popupFormat={ props.format.toLowerCase() } + minTime={props.minTime} + maxTime={props.maxTime} + bindData={firsthandActiveTime.value} + onSubData={selectedTimeChage} + > + { + ctx.slots.customViewTemplate?.() + } + </TimePopup> + <input ref={inputDom} + type="text" + value={vModeValue.value} + placeholder={`${props.placeholder}`} + disabled={props.disabled} + class='time-input' /> + <div class='time-input-icon'> + <div onClick={clearAll}> + { + showClearIcon.value + ? <Icon size="small" name="close" /> + :'' + } + </div> + <div> + <Icon size="small" name="time" /> + </div> + </div> + </div> + </> + ) + } + } +}) diff --git a/packages/devui-vue/devui/time-picker/src/types.ts b/packages/devui-vue/devui/time-picker/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c02163b663abd812d725c6ef4a21d18cd76513c --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/types.ts @@ -0,0 +1,14 @@ + +export type timeType = 'hh' | 'HH' | 'mm' | 'MM' | 'ss' | 'SS'; +export type TimeObj = { + time: string + type?: timeType +} + +export type ArrType = { + type:'hour' | 'minute' | 'seconde' + isActive:boolean + isDisabled:boolean + time:string + flag:string +} diff --git a/packages/devui-vue/devui/time-picker/src/utils.ts b/packages/devui-vue/devui/time-picker/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..16260778dcc057ae94e37293210a76e55ad14dcf --- /dev/null +++ b/packages/devui-vue/devui/time-picker/src/utils.ts @@ -0,0 +1,95 @@ +import { Ref , reactive} from 'vue' +import { ArrType } from './types' + +/** + * 动态调整弹窗位置 + * @param element + * @returns { top , left } + */ +export function getPositionFun(el:Element,left:Ref,top:Ref):any{ + const inputDom = el.getBoundingClientRect() + const button = window.innerHeight - (inputDom.top + 20) + if(button > inputDom.top + 20){ + left.value = inputDom.x + top.value = inputDom.top + 20 + 10 + }else{ + left.value = inputDom.x + top.value = inputDom.top - 316 + } +} + +/** + * 初始化数据 + * @param type 类型( 时,分,秒 ) + * @returns Array<time> + */ + +export function initializeTimeData(type:string):any{ + const timeArr = reactive([]) + let arrLenght = 0 + if(type == 'hour'){ + arrLenght = 24 + }else{ + arrLenght = 60 + } + for (let i = 0; i < arrLenght; i++) { + timeArr.push({ + time:i<10?'0'+i:i+'', + isActive:false, + flag:type, + isDisabled:false + }) + } + return timeArr +} + +/** + * 初始化 最小值 最大值 + * @param hourList + * @param minuteList + * @param maxTime + * @param minTime + * @param farmat + */ +export const setTimeAstrict = ( + hourList:Array<ArrType>, + minuteList:Array<ArrType>, + secondList:Array<ArrType>, + minTime:string, + maxTime:string, + format:string):void=>{ + + const maxTimeHour = maxTime.split(':')[0] + const maxTimeMinute = maxTime.split(':')[1] + const minTimeHour = minTime.split(':')[0] + const minTimeMinute = minTime.split(':')[1] + const minTimeSecond = minTime.split(':')[2] + + hourList.map((item,index)=>{ + if(item.time < minTimeHour || item.time > maxTimeHour ){ + item.isDisabled = true + } + }) + + // 如果为mm:ss格式,限制小时的选择范围 + if(format == 'mm:ss'){ + minuteList.map((item,index)=>{ + if(item.time < minTimeMinute || item.time > maxTimeMinute ){ + item.isDisabled = true + } + }) + }else{ + minuteList.map((item,index)=>{ + if(item.time < minTimeMinute ){ + item.isDisabled = true + } + }) + } + secondList.map((item,index)=>{ + if(item.time < minTimeSecond ){ + item.isDisabled = true + } + }) +} + + diff --git a/packages/devui-vue/devui/toast/index.ts b/packages/devui-vue/devui/toast/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d091b1558be1ebd0a63148e84960d334c16369b --- /dev/null +++ b/packages/devui-vue/devui/toast/index.ts @@ -0,0 +1,19 @@ +import type { App } from 'vue' +import Toast from './src/toast' +import ToastService from './src/toast-service' + +Toast.install = function(app: App) { + app.component(Toast.name, Toast) +} + +export { Toast, ToastService } + +export default { + title: 'Toast 全局提示', + category: '反馈', + status: '已完成', + install(app: App): void { + app.use(Toast as any) + app.config.globalProperties.$toastService = ToastService + } +} diff --git a/packages/devui-vue/devui/toast/src/hooks/use-toast-constant.ts b/packages/devui-vue/devui/toast/src/hooks/use-toast-constant.ts new file mode 100644 index 0000000000000000000000000000000000000000..af0627dec114e01d01bff9a73f00d74cc54eb93b --- /dev/null +++ b/packages/devui-vue/devui/toast/src/hooks/use-toast-constant.ts @@ -0,0 +1,11 @@ +export function useToastConstant() { + const ANIMATION_NAME = 'slide-in' + const ANIMATION_TIME = 300 + const ID_PREFIX = 'toast-message' + + return { + ANIMATION_TIME, + ANIMATION_NAME, + ID_PREFIX + } as const +} diff --git a/packages/devui-vue/devui/toast/src/hooks/use-toast-event.ts b/packages/devui-vue/devui/toast/src/hooks/use-toast-event.ts new file mode 100644 index 0000000000000000000000000000000000000000..45c7f16fa90c48990214f21058f0d17f7606c061 --- /dev/null +++ b/packages/devui-vue/devui/toast/src/hooks/use-toast-event.ts @@ -0,0 +1,23 @@ +import { getCurrentInstance } from 'vue' +import { Message } from '../toast-types' +import { useToastConstant } from './use-toast-constant' + +const { ANIMATION_TIME } = useToastConstant() + +export function useToastEvent() { + const ctx = getCurrentInstance() + + function onCloseEvent(msg: Message) { + ctx.emit('closeEvent', msg) + } + + function onValueChange(msgs: Message[]) { + ctx.emit('valueChange', msgs) + } + + function onHidden() { + setTimeout(() => (ctx.attrs.onHidden as () => void)?.(), ANIMATION_TIME) + } + + return { onCloseEvent, onValueChange, onHidden } +} diff --git a/packages/devui-vue/devui/toast/src/hooks/use-toast-helper.ts b/packages/devui-vue/devui/toast/src/hooks/use-toast-helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc12f581c1fa139657ba6d2e072c7f2db01e23e0 --- /dev/null +++ b/packages/devui-vue/devui/toast/src/hooks/use-toast-helper.ts @@ -0,0 +1,15 @@ +import { Message } from '../src/toast.type' + +export function useToastHelper() { + function severityDelay(msg: Message) { + switch (msg.severity) { + case 'warn': + case 'error': + return 10e3 + default: + return 5e3 + } + } + + return { severityDelay } +} diff --git a/packages/devui-vue/devui/toast/src/hooks/use-toast-z-index.ts b/packages/devui-vue/devui/toast/src/hooks/use-toast-z-index.ts new file mode 100644 index 0000000000000000000000000000000000000000..22e2519012a7176b0921bc3c8b1e5bd4abe521bf --- /dev/null +++ b/packages/devui-vue/devui/toast/src/hooks/use-toast-z-index.ts @@ -0,0 +1,5 @@ +export let toastZIndex = 1060 + +export function toastIncrease() { + toastZIndex++ +} diff --git a/packages/devui-vue/devui/toast/src/toast-icon-close.tsx b/packages/devui-vue/devui/toast/src/toast-icon-close.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6ded5f19fb3cae699bb74a8ee518b9bbe97f9f26 --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast-icon-close.tsx @@ -0,0 +1,22 @@ +import { defineComponent, PropType } from 'vue' +import { Icon } from '../../icon' + +export default defineComponent({ + name: 'DToastIconClose', + props: { + prefixCls: String, + onClick: Function as PropType<(e: MouseEvent) => void> + }, + emits: ['click'], + render() { + const { prefixCls, $emit } = this + + const wrapperCls = `${prefixCls}-icon-close` + + return ( + <div class={wrapperCls} onClick={(e) => $emit('click', e)}> + <Icon name="close" size="14px" /> + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/toast/src/toast-image.tsx b/packages/devui-vue/devui/toast/src/toast-image.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8c6c74242471e7705bb63fa30dc0db0a71677da5 --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast-image.tsx @@ -0,0 +1,27 @@ +import { defineComponent, PropType } from 'vue' +import { IToastSeverity } from './toast-types' +import { Icon } from '../../icon' + +export default defineComponent({ + name: 'DToastImage', + props: { + prefixCls: String, + severity: String as PropType<IToastSeverity> + }, + render() { + const { prefixCls, severity } = this + + const wrapperCls = [`${prefixCls}-image`, `${prefixCls}-image-${severity || 'common'}`] + + const severityIconMap = { + info: 'info-o', + success: 'right-o', + warn: 'warning-o', + error: 'error-o' + } + + const showIcon = () => severity !== 'common' + + return <span class={wrapperCls}>{showIcon() ? <Icon name={severityIconMap[severity]} size="14px" /> : null}</span> + } +}) diff --git a/packages/devui-vue/devui/toast/src/toast-service.ts b/packages/devui-vue/devui/toast/src/toast-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb72303cc24e700c6f96cdafa5e9556d93f408cb --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast-service.ts @@ -0,0 +1,35 @@ +import { createApp, onUnmounted } from 'vue' +import { ToastProps } from './toast-types' +import Toast from './toast' + +function createToastApp(props: Record<string, any>) { + return createApp(Toast, props) +} + +class ToastService { + static open(props: Partial<ToastProps> & Pick<ToastProps, 'value'>) { + let $body: HTMLElement | null = document.body + let $div: HTMLDivElement | null = document.createElement('div') + + $body.appendChild($div) + + let app = createToastApp({ ...(props ?? {}), onHidden: () => app?.unmount() }) + let toastInstance = app.mount($div) + + onUnmounted(() => { + $body.removeChild($div) + + $body = null + $div = null + + app = null + toastInstance = null + }, toastInstance.$) + + return { + toastInstance + } + } +} + +export default ToastService diff --git a/packages/devui-vue/devui/toast/src/toast-types.ts b/packages/devui-vue/devui/toast/src/toast-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..458161ec242941d01f5a0d5a0fa7ccfb2bd86c53 --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast-types.ts @@ -0,0 +1,99 @@ +import type { CSSProperties, ExtractPropTypes, PropType, h } from 'vue' + +export type IToastLifeMode = 'single' | 'global' +export type IToastSeverity = 'common' | 'success' | 'error' | 'warn' | 'info' | string +export type IToastSeverityConfig = { color: string; icon: string; } + +export interface Message { + /** + * 消息级别。 + * 预设值有 common、success、error、warn、info,超时时间参见 life 说明, + * 未设置或非预设值时超时时间为 5000 毫秒,warn 和 error 为 10000 毫秒。 + */ + severity?: IToastSeverity + /** + * 消息标题。 + * 当设置超时时间,未设置标题时,不展示标题和关闭按钮。 + */ + summary?: string + /** + * 消息内容,推荐使用content替换。 + */ + detail?: string + /** + * 消息内容,支持纯文本和插槽,推荐使用。 + */ + content?: string | `slot:${string}` | ((message: Message) => ReturnType<typeof h>) + /** + * 单个消息超时时间,需设置 lifeMode 为 single 。 + * 每个消息使用自己的超时时间,开启该模式却未设置时按 severity 判断超时时间。 + */ + life?: number + /** + * 消息 ID。 + */ + id?: any +} + +export const toastProps = { + /** + * 必选,消息内容数组,Message 对象定义见下文。 + */ + value: { + type: Array as PropType<Message[]>, + required: true, + default: () => [] + }, + /** + * 可选,超时时间,超时后自动消失,鼠标悬停可以阻止消失,单位毫秒。 + * + * @description 普通、成功、提示类默认为 5000 毫秒,错误、警告类默认为 10000 毫秒。 + */ + life: { + type: Number, + default: null + }, + /** + * 可选,超时时间模式,预设值为 global 和 single 。 + * + * @description + * 默认为 global,所有消息使用 life 或群组第一个消息的预设超时时间; + * 设置为 single 时,每个消息使用自身的超时时间,参见 Message 中的 life 定义。 + * + * @default 'global' + */ + lifeMode: { + type: String as PropType<IToastLifeMode>, + default: 'global' + }, + /** + * 可选,是否常驻,默认自动关闭。 + * + * @default false + */ + sticky: { + type: Boolean, + default: false + }, + /** + * 可选,样式。 + */ + style: { + type: Object as PropType<CSSProperties>, + default: () => ({}) + }, + /** + * 可选,类名。 + */ + styleClass: { + type: String + }, + onCloseEvent: { + type: Function as PropType<(message: Message) => void> + }, + onValueChange: { + type: Function as PropType<(restMessages: Message[]) => void> + } +} as const + +export type ToastProps = ExtractPropTypes<typeof toastProps> diff --git a/packages/devui-vue/devui/toast/src/toast.scss b/packages/devui-vue/devui/toast/src/toast.scss new file mode 100644 index 0000000000000000000000000000000000000000..3f8c25127153904b0b75f22c09057057868c90cd --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast.scss @@ -0,0 +1,127 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/shadow'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; + +.devui-toast { + position: fixed; + top: 50px; + right: 20px; + width: 20em; + word-break: normal; + word-wrap: break-word; + + a { + &:link, + &:visited { + color: $devui-link-light; + } + + &:hover, + &:active { + color: $devui-link-light-active; + } + } +} + +.devui-toast-item-container { + position: relative; + transform: translateX(100%); + margin: 0 0 10px 0; + opacity: 0.95; + filter: alpha(opacity=95); + box-shadow: $devui-shadow-length-feedback-overlay $devui-shadow; + border-radius: $devui-border-radius-feedback; + color: $devui-feedback-overlay-text; + transition: all $devui-animation-duration-slow $devui-animation-ease-in-out; + background-color: $devui-feedback-overlay-bg; + + &.slide-in { + transform: translateX(0); + } +} + +.devui-toast-item { + position: relative; + display: block; + padding: 12px 16px; +} + +.devui-toast-item p { + padding: 0; + margin: 0; +} + +.devui-toast-icon-close { + position: absolute; + top: 7px; + right: 10px; + cursor: pointer; + + & i.icon { + color: $devui-light-text !important; + } +} + +.devui-toast-title { + font-size: $devui-font-size-card-title; + padding: 0 0 calc(0.5em - 2px) 0; + display: block; + font-weight: 700; +} + +.devui-toast-image { + position: absolute; + display: inline-block; + width: 16px; + height: 16px; + border-radius: 50%; + left: 16px; + top: 10px; + padding: 0; + + &.devui-toast-image-warn i.icon { + color: $devui-warning !important; + } + + &.devui-toast-image-info i.icon { + color: $devui-info !important; + } + + &.devui-toast-image-error i.icon { + color: $devui-danger !important; + } + + &.devui-toast-image-success i.icon { + color: $devui-success !important; + } + + .devui-toast-image-info-path, + .devui-toast-image-error-path, + .devui-toast-image-success-path { + fill: $devui-light-text; + } +} + +.devui-toast-message { + margin-left: 20px; + + p { + padding: 0 8px 0 4px; + } + + span.devui-toast-title + p { + padding: 0; + } +} + +.devui-toast-message-common .devui-toast-message { + margin-left: 0; +} + +.devui-toast-message p { + font-size: $devui-font-size; + margin-top: 2px; +} diff --git a/packages/devui-vue/devui/toast/src/toast.tsx b/packages/devui-vue/devui/toast/src/toast.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5f925c361d101e215315cfc73b9511178e522edf --- /dev/null +++ b/packages/devui-vue/devui/toast/src/toast.tsx @@ -0,0 +1,332 @@ +import './toast.scss' + +import { computed, defineComponent, nextTick, onUnmounted, ref, watch } from 'vue' +import { Message, ToastProps, toastProps } from './toast-types' +import ToastIconClose from './toast-icon-close' +import ToastImage from './toast-image' +import { cloneDeep, isEqual, merge, omit, throttle } from 'lodash-es' +import { useToastEvent } from './hooks/use-toast-event' +import { useToastHelper } from './hooks/use-toast-helper' +import { useToastConstant } from './hooks/use-toast-constant' +import { toastZIndex, toastIncrease } from './hooks/use-toast-z-index' + +const { ANIMATION_NAME, ANIMATION_TIME, ID_PREFIX } = useToastConstant() + +export default defineComponent({ + name: 'DToast', + inheritAttrs: false, + props: toastProps, + emits: ['closeEvent', 'valueChange'], + setup(props: ToastProps, ctx) { + const { onCloseEvent, onHidden, onValueChange } = useToastEvent() + const { severityDelay } = useToastHelper() + + const removeThrottle = throttle(remove, ANIMATION_TIME) + + const messages = ref<Message[]>([]) + const msgAnimations = ref<Message[]>([]) + + const containerRef = ref<any>() + const msgItemRefs = ref<any[]>([]) + + let timestamp: number = Date.now() + let timeout: number | undefined + const timeoutArr: typeof timeout[] = [] + + const defaultLife = computed(() => { + if (props.life !== null) return props.life + + if (messages.value.length > 0) return severityDelay(messages.value[0]) + + return 5e3 + }) + + watch( + () => props.value, + (value) => { + if (value.length === 0) return + + if (hasMsgAnimation()) { + initValue() + } + + nextTick(() => { + initValue(value) + handleValueChange() + }) + }, + { deep: true, immediate: true } + ) + + watch(messages, (value) => { + value.length === 0 && msgAnimations.value.length > 0 && (msgAnimations.value = []) + }) + + watch(msgAnimations, (value, oldValue) => { + oldValue.length > 0 && value.length === 0 && onHidden() + }) + + onUnmounted(() => { + if (props.sticky) { + return + } + + if (props.lifeMode === 'single') { + timeoutArr.forEach((t) => t && clearTimeout(t)) + } else { + clearTimeout(timeout) + } + }) + + function initValue(value: Message[] = []) { + const cloneValue = cloneDeep(value) + messages.value = cloneValue.map((v, i) => merge(v, { id: `${ID_PREFIX}-${i}` })) + msgAnimations.value = [] + } + + function handleValueChange() { + toastIncrease() + + setTimeout(() => { + messages.value.forEach((msg) => msgAnimations.value.push(msg)) + }, 0) + + if (props.sticky) return + + if (timeout) { + timeout = clearTimeout(timeout) as undefined + } + + if (timeoutArr.length > 0) { + timeoutArr.splice(0).forEach((t) => clearTimeout(t)) + } + + timestamp = Date.now() + + if (props.lifeMode === 'single') { + setTimeout(() => { + messages.value.forEach((msg, i) => { + timeoutArr[i] = setTimeout(() => singleModeRemove(msg, i), msg.life || severityDelay(msg)) + }) + }) + } else { + timeout = setTimeout(() => removeAll(), defaultLife.value) + } + } + + function singleModeRemove(msg: Message, i: number) { + removeMsgAnimation(msg) + setTimeout(() => { + onCloseEvent(msg) + + if (hasMsgAnimation()) { + messages.value.splice(i, 1) + } else { + messages.value = [] + } + + onValueChange(messages.value) + }, ANIMATION_TIME) + } + + function interrupt(i: number) { + // 避免正在动画中的 toast 触发方法 + if (!msgAnimations.value.includes(messages.value[i])) return + + if (props.lifeMode === 'single') { + if (timeoutArr[i]) { + timeoutArr[i] = clearTimeout(timeoutArr[i]) as undefined + } + } else { + resetDelay(() => { + messages.value.forEach((msg, _i) => i !== _i && removeMsgAnimation(msg)) + }) + } + } + + function resetDelay(fn: () => void) { + if (!props.sticky && timeout) { + timeout = clearTimeout(timeout) as undefined + + const remainTime = defaultLife.value - (Date.now() - timestamp) + timeout = setTimeout(() => fn(), remainTime) + } + } + + function remove(i: number) { + if (props.lifeMode === 'single' && timeoutArr[i]) { + timeoutArr[i] = clearTimeout(timeoutArr[i]) as undefined + timeoutArr.splice(i, 1) + } + + removeMsgAnimation(messages.value[i]) + + setTimeout(() => { + onCloseEvent(messages.value[i]) + + messages.value.splice(i, 1) + + onValueChange(messages.value) + + if (props.lifeMode === 'global') { + removeReset() + } + }, ANIMATION_TIME) + } + + function removeAll() { + if (messages.value.length > 0) { + msgAnimations.value = [] + + setTimeout(() => { + messages.value.forEach((msg) => onCloseEvent(msg)) + + messages.value = [] + + onValueChange(messages.value) + }, ANIMATION_TIME) + } + } + + function removeReset(i?: number, msg?: Message) { + // 避免点击关闭但正在动画中或自动消失正在动画中的 toast 触发重置方法 + const removed = messages.value.findIndex((_msg) => _msg === msg) === -1 + + if (removed || (msg !== undefined && !msgAnimations.value.includes(msg))) { + return + } + + if (props.lifeMode === 'single') { + const msgLife = msg!.life || severityDelay(msg!) + const remainTime = msgLife - (Date.now() - timestamp) + timeoutArr[i!] = setTimeout(() => singleModeRemove(msg!, i!), remainTime) + } else { + resetDelay(() => removeAll()) + } + } + + function removeIndexThrottle(i: number) { + if (i < msgItemRefs.value.length && i > -1) { + removeThrottle(i) + } + } + + function removeMsgThrottle(msg: Message) { + const ignoreDiffKeys = ['id'] + const index = messages.value.findIndex((_msg) => isEqual(omit(_msg, ignoreDiffKeys), omit(msg, ignoreDiffKeys))) + removeIndexThrottle(index) + } + + function removeMsgAnimation(msg: Message) { + msgAnimations.value = msgAnimations.value.filter((_msg) => _msg !== msg) + } + + function close(params?: number | Message): void { + if (params === undefined) { + return removeAll() + } + + if (typeof params === 'number') { + removeIndexThrottle(params) + } else { + removeMsgThrottle(params) + } + } + + function msgItemRef(i: number) { + return msgItemRefs.value[i] as HTMLDivElement + } + + function hasMsgAnimation() { + return msgAnimations.value.length > 0 + } + + return { + messages, + msgAnimations, + containerRef, + msgItemRefs, + interrupt, + removeReset, + removeThrottle, + close, + msgItemRef + } + }, + render() { + const { + style: extraStyle, + styleClass: extraClass, + messages, + msgAnimations, + msgItemRefs, + life, + interrupt, + removeReset, + removeThrottle, + $attrs, + $slots + } = this + + const prefixCls = 'devui-toast' + + const wrapperStyles = [`z-index: ${toastZIndex}`, extraStyle] + const wrapperCls = [prefixCls, extraClass] + + const msgCls = (msg: Message) => [ + `${prefixCls}-item-container`, + `${prefixCls}-message-${msg.severity}`, + { [ANIMATION_NAME]: msgAnimations.includes(msg) } + ] + + const showClose = (msg: Message) => !(!msg.summary && life !== null) + const showImage = (msg: Message) => msg.severity !== 'common' + const showSummary = (msg: Message) => !!msg.summary + const showContent = (msg: Message) => !!msg.content + const showDetail = (msg: Message) => !showContent(msg) && !!msg.detail + + const msgContent = (msg: Message) => { + if (typeof msg.content === 'function') { + return msg.content(msg) + } + + if ([null, undefined].includes(msg.content)) { + return null + } + + const slotPrefix = 'slot:' + const isSlot = String(msg.content).startsWith(slotPrefix) + + if (isSlot) { + return $slots[msg.content.slice(slotPrefix.length)]?.(msg) + } + + return msg.content + } + + return ( + <div ref="containerRef" style={wrapperStyles} class={wrapperCls} {...$attrs}> + {messages.map((msg, i) => ( + <div + ref={(el) => (msgItemRefs[i] = el)} + key={msg.id} + class={msgCls(msg)} + aria-live="polite" + onMouseenter={() => interrupt(i)} + onMouseleave={() => removeReset(i, msg)} + > + <div class={`${prefixCls}-item`}> + {showClose(msg) ? <ToastIconClose prefixCls={prefixCls} onClick={() => removeThrottle(i)} /> : null} + {showImage(msg) ? <ToastImage prefixCls={prefixCls} severity={msg.severity} /> : null} + <div class="devui-toast-message"> + {showSummary(msg) ? <span class="devui-toast-title">{msg.summary}</span> : null} + {showContent(msg) ? msgContent(msg) : null} + {showDetail(msg) ? <p innerHTML={msg.detail}></p> : null} + </div> + </div> + </div> + ))} + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/tooltip/index.ts b/packages/devui-vue/devui/tooltip/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a27b320b48beb756177827812fcbb691f63d847c --- /dev/null +++ b/packages/devui-vue/devui/tooltip/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Tooltip from './src/tooltip' + +Tooltip.install = function(app: App) { + app.component(Tooltip.name, Tooltip) +} + +export { Tooltip } + +export default { + title: 'Tooltip提示', + category: '反馈', + status: '50%', + install(app: App): void { + app.use(Tooltip as any) + } +} diff --git a/packages/devui-vue/devui/tooltip/src/tooltip-types.ts b/packages/devui-vue/devui/tooltip/src/tooltip-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..545d337fabfca2f2c9b78efa0d6ee20ff5029807 --- /dev/null +++ b/packages/devui-vue/devui/tooltip/src/tooltip-types.ts @@ -0,0 +1,27 @@ +import type { ExtractPropTypes } from 'vue' + +export type TTooltip = 'top' | 'right' | 'bottom' | 'left'; + +export const tooltipProps = { + position: { + type: String, + default: 'top' + }, + showAnimation: { + type: Boolean, + default: true + }, + content: { + type: String + }, + mouseLeaveDelay: { + type: String, + default: '150' + }, + mouseEnterDelay: { + type: String, + default: '100' + } +} as const + +export type TooltipProps = ExtractPropTypes<typeof tooltipProps> diff --git a/packages/devui-vue/devui/tooltip/src/tooltip.scss b/packages/devui-vue/devui/tooltip/src/tooltip.scss new file mode 100644 index 0000000000000000000000000000000000000000..f75dc22d82c2136b1a866d400c77f15a7da572ea --- /dev/null +++ b/packages/devui-vue/devui/tooltip/src/tooltip.scss @@ -0,0 +1,28 @@ +@import '../../style/theme/color'; + +.devui-tooltip { + box-sizing: border-box; + + .tooltip { + box-sizing: border-box; + position: absolute; + width: fit-content; + transition: all 0.5s; + + .arrow { + width: 0; + height: 0; + position: absolute; + } + + .tooltipcontent { + box-sizing: border-box; + padding: 10px; + margin-left: 10px; + border-radius: 4px; + width: fit-content; + background-color: $devui-feedback-overlay-bg; + color: $devui-feedback-overlay-text; + } + } +} diff --git a/packages/devui-vue/devui/tooltip/src/tooltip.tsx b/packages/devui-vue/devui/tooltip/src/tooltip.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d26f5506c10bc5527478cc0f4cd9213913f6874a --- /dev/null +++ b/packages/devui-vue/devui/tooltip/src/tooltip.tsx @@ -0,0 +1,161 @@ +import { defineComponent, reactive, ref, watch, onMounted, getCurrentInstance, onBeforeUnmount, renderSlot, useSlots} from 'vue' +import { tooltipProps } from './tooltip-types' +import EventListener from '../utils/event-listener' +import './tooltip.scss' + +export default defineComponent({ + name: 'DTooltip', + props: tooltipProps, + setup(props, ctx){ + const position = reactive({ + left: 0, + top: 0 + }) + const show = ref(false) + + // slotElement元素的ref + const slotElement = ref(null) + // tooltip元素的引用 + const tooltip = ref(null) + // arrow元素的引用 + const arrow = ref(null) + // tooltipcontent的引用 + const tooltipcontent = ref(null) + + let enterEvent + let leaveEvent + + const arrowStyle = (attr, value)=>{ + arrow.value.style[attr] = value + } + + // 延迟显示 + const delayShowTrue = function (fn, delay=props.mouseEnterDelay){ + let start + if (parseInt(delay)>=0){ + return function (){ + if (start){ + clearTimeout(start) + } + start = setTimeout(fn, parseInt(delay)) + } + } else{ + console.error('the value of delay is bigger than 0 and the type of delay must be string!') + return + } + } + // 延迟消失 + const delayShowFalse = function (fn, delay=props.mouseLeaveDelay){ + if (show.value && parseInt(delay) >= 0){ + setTimeout(fn, parseInt(delay)) + } + } + + onMounted(()=>{ + // 组件初始化不渲染tooltip + if (!show.value){ + tooltip.value.style.opacity = '0' + } + + // 注册鼠标引入事件 + /*enterEvent = EventListener.listen(slotElement.value.children[0], 'mouseenter', function (){ + show.value = true + })*/ + enterEvent = EventListener.listen(slotElement.value.children[0], 'mouseenter', delayShowTrue(function (){ + show.value = true + }, props.mouseEnterDelay)) + + // 注册鼠标移除事件 + leaveEvent = EventListener.listen(slotElement.value.children[0], 'mouseleave', function (){ + if (show.value){ + setTimeout(function (){ + show.value = false + }, props.mouseLeaveDelay) + } + }) + }) + + watch(show, function (newValue, oldValue){ + if (newValue){ + // 鼠标悬浮为true,显示提示框 + tooltip.value.style.opacity = '1' + tooltip.value.style.zIndex = '999' + arrow.value.style.border = '5px solid transparent' + // 具体的判定规则 + switch (props.position){ + case 'top': + // 设置 tooltip 内容的样式 + position.left = (slotElement.value.children[0].offsetLeft - tooltip.value.offsetWidth / 2 + slotElement.value.children[0].offsetWidth / 2) - 5; + position.top = slotElement.value.children[0].offsetTop - 10 - tooltipcontent.value.offsetHeight + // 设置箭头的样式 + arrowStyle('borderTop', '5px solid rgb(70, 77, 110)') + arrow.value.style.top = `${tooltipcontent.value.offsetHeight}px` + arrow.value.style.left = `${tooltipcontent.value.offsetWidth/2 + 5}px` + break + + case 'right': + // 设置tooltip 内容的样式 + position.left = slotElement.value.children[0].offsetLeft + slotElement.value.children[0].offsetWidth + position.top = slotElement.value.children[0].offsetTop + slotElement.value.children[0].offsetHeight/2 - tooltipcontent.value.offsetHeight/2 + // 设置箭头的样式 + arrowStyle('borderRight', '5px solid rgb(70, 77, 110)') + arrow.value.style.top = `${tooltipcontent.value.offsetHeight/2 - 5}px` + arrow.value.style.left = '-0px' + break + + case 'bottom': + // 设置tooltip的样式 + position.top = slotElement.value.children[0].offsetHeight + slotElement.value.children[0].offsetTop + 10 + position.left = (slotElement.value.children[0].offsetLeft + slotElement.value.children[0].offsetWidth/2 - tooltipcontent.value.offsetWidth/2) - 5; + // 设置arrow.value的样式 + arrowStyle('borderBottom', '5px solid rgb(70, 77, 110)') + arrow.value.style.top = '-10px' + arrow.value.style.left = `${tooltipcontent.value.offsetWidth/2 + 5}px` + break + + case 'left': + position.top = slotElement.value.children[0].offsetTop + slotElement.value.children[0].offsetHeight/2 - tooltipcontent.value.offsetHeight/2 + position.left = slotElement.value.children[0].offsetLeft - 20 - tooltipcontent.value.offsetWidth + // 设置arrow.value的样式 + arrowStyle('borderLeft', '5px solid rgb(70, 77, 110)') + arrow.value.style.left = `${tooltipcontent.value.offsetWidth + 10}px` + arrow.value.style.top = `${tooltipcontent.value.offsetHeight/2 - 5}px` + break + + default: + console.error('The attribute position value is wrong, the value is one of top、right、left、bottom') + break + } + tooltip.value.style.top = position.top + 'px' + tooltip.value.style.left = position.left + 'px' + } else { + position.top = 0 + position.left = 0 + // 鼠标移走为false,隐藏提示框 + tooltip.value.style.opacity = '0' + } + }) + + onBeforeUnmount (()=>{ + enterEvent.remove() + leaveEvent.remove() + }) + + return ()=>{ + const defaultSlot = renderSlot(useSlots(), 'default') + return ( + <div class="devui-tooltip"> + <div class="slotElement" ref={slotElement}> + {defaultSlot} + </div> + <div class="tooltip" ref={tooltip}> + <div class="arrow" ref={arrow}></div> + <div class="tooltipcontent" ref={tooltipcontent}> + {props.content} + </div> + </div> + </div> + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/tooltip/utils/event-listener.js b/packages/devui-vue/devui/tooltip/utils/event-listener.js new file mode 100644 index 0000000000000000000000000000000000000000..73f6f68c535deb2a2001bca79a2c0916460fd1f2 --- /dev/null +++ b/packages/devui-vue/devui/tooltip/utils/event-listener.js @@ -0,0 +1,21 @@ +const EventListener = { + listen: function (target, eventType, callback) { + if (target.addEventListener){ + target.addEventListener(eventType, callback, false); + return { + remove (){ + target.removeEventListener(target, callback, false); + } + } + } else { + target.attchEvent(eventType, callback); + return { + remove (){ + target.detachEvent(eventType, callback); + } + }; + } + } +}; + +export default EventListener; \ No newline at end of file diff --git a/packages/devui-vue/devui/transfer/common/use-transfer-base.ts b/packages/devui-vue/devui/transfer/common/use-transfer-base.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff58c15297aea7accbffc91caa9a348455be3817 --- /dev/null +++ b/packages/devui-vue/devui/transfer/common/use-transfer-base.ts @@ -0,0 +1,128 @@ +import { computed, ExtractPropTypes, PropType, ComputedRef } from 'vue' +import { IItem, TState, TResult } from '../types' +import { TransferProps } from './use-transfer' + +export type TransferOperationProps = ExtractPropTypes<typeof transferBaseProps> + +export const transferBaseProps = { + sourceOption: { + type: Array as () => IItem[], + default(): Array<IItem> { + return [] + } + }, + targetOption: { + type: Array as () => IItem[], + default(): Array<IItem> { + return [] + } + }, + type: { + type: String, + default: (): string => 'source' + }, + title: { + type: String, + default: (): string => 'Source' + }, + search: { + type: Boolean, + default: (): boolean => false + }, + allChecked: { + type: Boolean, + default: (): boolean => false + }, + query: { + type: String, + default: (): string => '' + }, + alltargetState: { + type: Boolean, + default: (): boolean => false + }, + checkedNum: { + type: Number, + default: (): number => 0 + }, + checkedValues: { + type: Array, + default: (): string[] => [] + }, + allCount: { + type: Number, + default: (): number => 0 + }, + scopedSlots: { + type: Object + }, + onChangeAllSource: { + type: Function as unknown as () => ((val: boolean) => void) + }, + onChangeQuery: { + type: Function as PropType<(val: string) => void> + }, + onUpdateCheckeds: { + type: Function as PropType<(val: string[]) => void> + } +} + +export type TransferBaseProps = ExtractPropTypes<typeof transferBaseProps> + +export const transferOperationProps = { + sourceDisabled: { + type: Boolean, + default: (): boolean => true + }, + targetDisabled: { + type: Boolean, + default: (): boolean => true + }, + onUpdateSourceData: { + type: Function as unknown as () => (() => void) + }, + onUpdateTargetData: { + type: Function as unknown as () => (() => void) + } +} + +const getFilterData = (props, type: string): TResult => { + const newModel: string[] = []; + const data: IItem[] = type === 'source' ? props.sourceOption : props.targetOption + const resultData: IItem[] = data.map((item: IItem) => { + const checked = props.modelValue.some(cur => cur === item.value) + checked && newModel.push(item.value) + return item + }) + return { + model: newModel, + data: resultData + } +} + + + +export const initState = (props: TransferProps, type: string): TState => { + const initModel: TResult = getFilterData(props, type); + const state: TState = { + data: initModel.data, + allChecked: false, + disabled: false, + checkedNum: initModel.model.length, + query: '', + checkedValues: initModel.model, + filterData: initModel.data + } + return state +} + +export const TransferBaseClass = (props: TransferOperationProps): ComputedRef => { + return computed(() => { + return `devui-transfer-panel devui-transfer-${props.type}` + }) +} + +export const Query = ((props: TransferOperationProps): ComputedRef => { + return computed(() => props.query) +}) + diff --git a/packages/devui-vue/devui/transfer/common/use-transfer-operation.ts b/packages/devui-vue/devui/transfer/common/use-transfer-operation.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4eb000f664dd5542a18903ffc0972bc8a2c8d5c --- /dev/null +++ b/packages/devui-vue/devui/transfer/common/use-transfer-operation.ts @@ -0,0 +1,22 @@ + + +export const transferOperationProps = { + sourceDisabled: { + type: Boolean, + default: (): boolean => true + }, + targetDisabled: { + type: Boolean, + default: (): boolean => true + }, + disabled: { + type: Boolean, + default: (): boolean => false + }, + onUpdateSourceData: { + type: Function as unknown as () => (() => void) + }, + onUpdateTargetData: { + type: Function as unknown as () => (() => void) + } +} diff --git a/packages/devui-vue/devui/transfer/common/use-transfer.ts b/packages/devui-vue/devui/transfer/common/use-transfer.ts new file mode 100644 index 0000000000000000000000000000000000000000..42eee67d6467e8360e35629dc0b6717906d8b467 --- /dev/null +++ b/packages/devui-vue/devui/transfer/common/use-transfer.ts @@ -0,0 +1,71 @@ +import { ExtractPropTypes, PropType, SetupContext } from 'vue' +import { IItem, ITitles, IModel } from '../types' + +export const transferProps = { + sourceOption: { + type: Array as () => IItem[], + require: true, + default(): IItem[] { + return [] + } + }, + targetOption: { + type: Array as () => IItem[], + require: true, + default(): IItem[] { + return [] + } + }, + titles: { + type: Array as PropType<ITitles>, + default: () => (): ITitles[] => ['Source', 'Target'] + }, + modelValue: { + type: Array as PropType<string | number[]>, + default: () => (): IModel[] => [], + }, + height: { + type: String, + default: '320px' + }, + isSearch: { + type: Boolean, + default: false + }, + isSourceDroppable: { + type: Boolean, + default: false + }, + isTargetDroppable: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + showOptionTitle: { + type: Boolean, + default: false + }, + slots: { + type: Object + } +} + +export type TransferProps = ExtractPropTypes<typeof transferProps>; + +export const headerSlot = (ctx: SetupContext, name: string): unknown => { + return !ctx.slots[`${name}-header`] ? null : () => ctx.slots[`${name}-header`] && ctx.slots[`${name}-header`]() +} + +export const bodySlot = (ctx: SetupContext, name: string): unknown => { + return !ctx.slots[`${name}-body`] ? null : () => ctx.slots[`${name}-body`] && ctx.slots[`${name}-body`]() +} + +export const opeartionSlot = (ctx: SetupContext): unknown => { + return ctx.slots && ctx.slots.operation && ctx.slots.operation() || null +} + + + diff --git a/packages/devui-vue/devui/transfer/index.ts b/packages/devui-vue/devui/transfer/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..27766015645e3eaf4fccbd09cfea5d53eb7f0189 --- /dev/null +++ b/packages/devui-vue/devui/transfer/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Transfer from './src/transfer' + +Transfer.install = function (app: App) { + app.component(Transfer.name, Transfer) +} + +export { Transfer } + +export default { + title: 'Transfer 穿梭框', + category: '数据录入', + status: '10%', + install(app: App): void { + app.use(Transfer as any) + } +} diff --git a/packages/devui-vue/devui/transfer/src/transfer-base.tsx b/packages/devui-vue/devui/transfer/src/transfer-base.tsx new file mode 100644 index 0000000000000000000000000000000000000000..605057afef26349ad7188ae0ec8841e919b35610 --- /dev/null +++ b/packages/devui-vue/devui/transfer/src/transfer-base.tsx @@ -0,0 +1,95 @@ +import { defineComponent, computed } from 'vue' +import { transferBaseProps, TransferBaseClass , TransferBaseProps } from '../common/use-transfer-base' +import DCheckbox from '../../checkbox/src/checkbox' +import DCheckboxGroup from '../../checkbox/src/checkbox-group' +import DSearch from '../../search/src/search' +export default defineComponent({ + name: 'DTransferBase', + components: { + DSearch, + DCheckboxGroup, + DCheckbox + }, + props: transferBaseProps, + setup(props: TransferBaseProps, ctx) { + /** data start **/ + const modelValues = computed(() => props.checkedValues) + const searchQuery = computed(() => props.query) + const baseClass = TransferBaseClass(props) + /** data end **/ + + /** watch start **/ + /** watch start **/ + + /** methods start **/ + const updateSearchQuery = (val: string): void => ctx.emit('changeQuery', val) + /** methods start **/ + + return { + baseClass, + searchQuery, + modelValues, + updateSearchQuery + } + }, + render() { + const { + title, + baseClass, + checkedNum, + allChecked, + sourceOption, + allCount, + updateSearchQuery, + search, + searchQuery, + modelValues + } = this + + return ( + <div class={baseClass}> + { + this.$slots.header ? this.$slots.header() : (<div class="devui-transfer-panel-header"> + <div class="devui-transfer-panel-header-allChecked"> + <DCheckbox + modelValue={allChecked} + onChange={(value: boolean) => this.$emit('changeAllSource', value)}> + {title} + </DCheckbox> + </div> + <div class="devui-transfer-panel-header-num">{checkedNum}/{allCount}</div> + </div>) + } + { + this.$slots.body ? this.$slots.body() : <div class="devui-transfer-panel-body"> + {search && <div class="devui-transfer-panel-body-search"> + <DSearch modelValue={searchQuery} onUpdate:modelValue={updateSearchQuery} /> + </div>} + <div class="devui-transfer-panel-body-list" + style={{ + height: `calc(100% - 40px - ${search ? 42 : 0}px)` + }}> + { + sourceOption.length ? <DCheckboxGroup modelValue={modelValues} + onChange={(values: string[]): void => this.$emit('updateCheckeds', values)}> + { + sourceOption.map((item, idx) => { + return <DCheckbox + class="devui-transfer-panel-body-list-item" + label={item.key} + value={item.value} + disabled={item.disabled} + key={idx}> + </DCheckbox> + }) + } + </DCheckboxGroup> : + <div class="devui-transfer-panel-body-list-empty">无数据</div> + } + </div> + </div> + } + </div> + ) + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/transfer/src/transfer-operation.tsx b/packages/devui-vue/devui/transfer/src/transfer-operation.tsx new file mode 100644 index 0000000000000000000000000000000000000000..388024b4a5f44e350ae7f0469587dcd1a532d19a --- /dev/null +++ b/packages/devui-vue/devui/transfer/src/transfer-operation.tsx @@ -0,0 +1,28 @@ +import { defineComponent, computed } from 'vue'; +import DButton from '../../button/src/button' +import { transferOperationProps } from '../common/use-transfer-operation' + +export default defineComponent({ + name: 'DTransferOperation', + components: { + DButton + }, + props: transferOperationProps, + setup(props, ctx) { + return () => { + return ctx.slots.operation && ctx.slots.operation() || <div class="devui-transfer-panel-operation"> + <div class="devui-transfer-panel-operation-group"> + <DButton + class="devui-transfer-panel-operation-group-left" + disabled={props.disabled ? props.disabled : props.sourceDisabled} + onClick={() => ctx.emit('updateSourceData')}> + <span class="icon-collapse"></span> + </DButton> + <DButton class="devui-transfer-panel-operation-group-right" disabled={props.disabled ? props.disabled : props.targetDisabled} onClick={() => ctx.emit('updateTargetData')}> + <span class="icon-chevron-right"></span> + </DButton> + </div> + </div> + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/transfer/src/transfer.scss b/packages/devui-vue/devui/transfer/src/transfer.scss new file mode 100644 index 0000000000000000000000000000000000000000..9328c50e46fc8cacec585a5ba9dd7b26f60b72c3 --- /dev/null +++ b/packages/devui-vue/devui/transfer/src/transfer.scss @@ -0,0 +1,98 @@ +@import '../../style/theme/color'; + +$devui-transfer-border-color: #adb0b8; +$devui-transfer-border-radius: 2px; +$devui-transfer-header-height: 40px; +$devui-transfer-header-border-line-color:#dfe1e6; +$devui-transfer-body-search-height: 42px; +$devui-transfer-body-list-item-height: 36px; + +.devui-transfer { + display: flex; + + &-panel { + width: 300px; + border: 1px solid $devui-transfer-border-color; + border-radius: $devui-transfer-border-radius; + + &-header { + display: flex; + justify-content: space-between; + height: $devui-transfer-header-height; + line-height: $devui-transfer-header-height; + border-bottom: 1px solid$devui-transfer-header-border-line-color; + + &-allChecked { + display: flex; + margin-left: 20px; + } + + &-num { + margin-right: 12px; + } + } + + &-body { + height: 100%; + + &-search { + height: $devui-transfer-body-search-height; + display: flex; + justify-content: center; + width: calc(100% - 40px); + align-items: center; + margin: 0 auto; + + .devui-search, + .devui-input__wrap { + width: 100%; + } + } + + &-list { + overflow: auto; + height: calc(100% - #{$devui-transfer-header-height} - #{$devui-transfer-body-search-height}); + width: 100%; + + &-item { + margin: 0 20px; + height: $devui-transfer-body-list-item-height; + line-height: $devui-transfer-body-list-item-height; + } + + &-empty { + height: 100%; + display: flex; + justify-content: center; + align-items: center; + color: $devui-disabled-text; + } + } + } + + &-operation { + width: 10%; + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + + &-group { + width: 36px; + + &-left .devui-btn, + &-right .devui-btn { + width: 36px; + height: 36px; + border-radius: 50%; + padding: 0; + min-width: 36px !important; + } + + &-right { + margin-top: 12px; + } + } + } + } +} diff --git a/packages/devui-vue/devui/transfer/src/transfer.tsx b/packages/devui-vue/devui/transfer/src/transfer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e05273d0cc6a1e663f17720f0b3b40246298411e --- /dev/null +++ b/packages/devui-vue/devui/transfer/src/transfer.tsx @@ -0,0 +1,178 @@ +import { defineComponent, reactive, watch, ref, SetupContext } from 'vue' +import { TState } from '../types' +import DTransferBase from './transfer-base' +import DTransferOperation from './transfer-operation' +import { initState } from '../common/use-transfer-base' +import { transferProps, TransferProps, headerSlot, bodySlot, opeartionSlot } from '../common/use-transfer' +import DCheckbox from '../../checkbox/src/checkbox' +import './transfer.scss' + +export default defineComponent({ + name: 'DTransfer', + components: { + DTransferBase, + DTransferOperation, + DCheckbox + }, + props: transferProps, + setup(props: TransferProps, ctx: SetupContext) { + /** data start **/ + const leftOptions = reactive<TState>(initState(props, 'source')) + const rightOptions = reactive<TState>(initState(props, 'target')) + const origin = ref(null); + /** data end **/ + + /** watch start **/ + watch( + () => leftOptions.query, + (nVal: string): void => { + searchFilterData(leftOptions) + } + ) + + watch( + () => leftOptions.checkedValues, + (values: string[]): void => { + leftOptions.checkedNum = values.length + setAllCheckedState(leftOptions, values) + }, + { + deep: true + } + ) + + watch( + () => rightOptions.query, + (nVal: string): void => { + searchFilterData(rightOptions) + }, + ) + + watch( + () => rightOptions.checkedValues, + (values: string[]): void => { + rightOptions.checkedNum = values.length; + setAllCheckedState(rightOptions, values) + }, + { + deep: true + } + ) + + /** watch end **/ + + /** methods start **/ + const setAllCheckedState = (source: TState, value: string[]): void => { + if (origin.value === 'click') { + source.allChecked = false + } else { + source.allChecked = value.length === source.data.filter(item => !item.disabled).length ? true : false + } + } + + const updateFilterData = (source: TState, target: TState): void => { + const newData = [] + source.data = source.data.filter(item => { + const hasInclues = source.checkedValues.includes(item.value) + hasInclues && newData.push(item) + return !hasInclues + }) + target.data = target.data.concat(newData) + source.checkedValues = [] + target.disabled = !target.disabled + searchFilterData(source, target) + searchFilterData(target, source) + setOrigin('click') + } + const changeAllSource = (source: TState, value: boolean): void => { + if (source.filterData.every(item => item.disabled)) return + source.allChecked = value + if (value) { + source.checkedValues = source.filterData.filter(item => !item.disabled) + .map(item => item.value) + } else { + source.checkedValues = [] + } + setOrigin('change') + } + const updateLeftCheckeds = (values: string[]): void => { + leftOptions.checkedValues = values + setOrigin('change') + } + const updateRightCheckeds = (values: string[]): void => { + rightOptions.checkedValues = values + setOrigin('change') + } + const searchFilterData = (source: TState, target?: TState): void => { + source.filterData = source.data.filter(item => item.key.indexOf(source.query) !== -1) + if (target) { + target.allChecked = false + } + } + const setOrigin = (value: string): void => { + origin.value = value + } + /** methods end **/ + + return () => { + return <div class="devui-transfer"> + <DTransferBase + style={{ + height: props.height + }} + sourceOption={leftOptions.filterData} + title={props.titles[0]} + type="source" + search={props.isSearch} + allChecked={leftOptions.allChecked} + checkedNum={leftOptions.checkedNum} + query={leftOptions.query} + checkedValues={leftOptions.checkedValues} + allCount={leftOptions.data.length} + v-slots={ + { + header: headerSlot(ctx, 'left'), + body: bodySlot(ctx, 'left') + } + } + onChangeAllSource={(value) => changeAllSource(leftOptions, value)} + onUpdateCheckeds={updateLeftCheckeds} + onChangeQuery={(value) => leftOptions.query = value} + /> + <DTransferOperation + v-slots={{ + operation: opeartionSlot(ctx) + }} + disabled={props.disabled} + sourceDisabled={rightOptions.checkedNum > 0 ? false : true} + targetDisabled={leftOptions.checkedNum > 0 ? false : true} + onUpdateSourceData={() => { updateFilterData(rightOptions, leftOptions) }} + onUpdateTargetData={() => { updateFilterData(leftOptions, rightOptions) }} + /> + <DTransferBase + v-slots={ + { + header: headerSlot(ctx, 'right'), + body: bodySlot(ctx, 'right') + } + } + style={{ + height: props.height + }} + sourceOption={rightOptions.filterData} + title={props.titles[1]} + type="target" + search={props.isSearch} + allChecked={rightOptions.allChecked} + checkedNum={rightOptions.checkedNum} + query={rightOptions.query} + checkedValues={rightOptions.checkedValues} + allCount={rightOptions.data.length} + onChangeAllSource={(value) => changeAllSource(rightOptions, value)} + onUpdateCheckeds={updateRightCheckeds} + onChangeQuery={(value) => rightOptions.query = value} + /> + </div> + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/transfer/types.ts b/packages/devui-vue/devui/transfer/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..c527d74e6661facaf96f8b1c9ec507305194df46 --- /dev/null +++ b/packages/devui-vue/devui/transfer/types.ts @@ -0,0 +1,54 @@ + +export interface IItem { + key: string + value: string + disabled: boolean +} + +export interface ITitles { + [index: number]: string +} + +export interface IModel { + [index: number]: string | number +} + +export interface TState { + data: IItem[] + allChecked: boolean + checkedNum: number + query: string + checkedValues: string[] + filterData: IItem[] + disabled: boolean +} + +export interface TResult { + model: string[] + data: IItem[] +} + + + +// import { ComputedRef } from 'vue' +// export type TItem = { +// key: string +// value: string +// disabled: boolean +// checked?: boolean +// } + +// export type TState = { +// data: TItem[] +// allChecked: boolean +// // disabled: boolean // ComputedRef// +// checkedNum: number +// query: string +// checkedValues: string[] +// filterData: TItem[] +// } + +// export type TResult = { +// model: string[] +// data: TItem[] +// } diff --git a/packages/devui-vue/devui/tree-select/index.ts b/packages/devui-vue/devui/tree-select/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a3ed884e921042dc112face7b8c7dd4ec550d09 --- /dev/null +++ b/packages/devui-vue/devui/tree-select/index.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue' +import TreeSelect from './src/tree-select' + +TreeSelect.install = function(app: App): void { + app.component(TreeSelect.name, TreeSelect) +} + +export { TreeSelect } + +export default { + title: 'TreeSelect 树形选择框', + category: '数据录入', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + + app.use(TreeSelect as any) + } +} diff --git a/packages/devui-vue/devui/tree-select/src/tree-select-types.ts b/packages/devui-vue/devui/tree-select/src/tree-select-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..fcb84dccdb48e718a957106f532610d0f3aca596 --- /dev/null +++ b/packages/devui-vue/devui/tree-select/src/tree-select-types.ts @@ -0,0 +1,69 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export interface TreeItem { + id?: number | string + label?: string + data?: any + parent?: TreeItem | null + children?: Array<TreeItem> | null + level?: number + loading?: boolean + isOpen?: boolean + isChecked?: boolean + disabled?: boolean + + [prop: string]: any +} + +export type TreeData = Array<TreeItem> + +export type ModelValue = number | string | Array<number | string>; + +export const treeSelectProps = { + modelValue: { + type: [String, Number, Array] as PropType<ModelValue>, + default: '', + }, + treeData: { + type: Array as PropType<TreeData>, + default: () => [], + }, + placeholder: { + type: String, + default: '请选择', + }, + disabled: { + type: Boolean, + default: false + }, + expandTree: { + type: Boolean, + default: false + }, + multiple: { + type: Boolean, + default: false, + }, + leafOnly: { + type: Boolean, + default: false, + }, + searchable: { + type: Boolean, + default: false, + }, + allowClear: { + type: Boolean, + default: false + }, + onToggleChange: { + type: Function as PropType<(bool: boolean) => void>, + default: undefined, + }, + onValueChange: { + type: Function as PropType<(item: TreeItem, index: number) => void>, + default: undefined, + }, +} as const + +export type TreeSelectProps = ExtractPropTypes<typeof treeSelectProps> diff --git a/packages/devui-vue/devui/tree-select/src/tree-select.scss b/packages/devui-vue/devui/tree-select/src/tree-select.scss new file mode 100644 index 0000000000000000000000000000000000000000..9cae05128d0cbd928cd48ce97aaad4945d6605b1 --- /dev/null +++ b/packages/devui-vue/devui/tree-select/src/tree-select.scss @@ -0,0 +1,136 @@ +@import '../../style/mixins/index'; +@import '../../style/theme/color'; +@import '../../style/theme/corner'; + +$tree-select-input-height: 28px; +$tree-select-dropdown-max-height: 300px; +$tree-select-item-min-height: 36px; +$tree-select-item-font-size: 16px; + +.devui-tree-select { + position: relative; + width: 100%; +} + +.devui-tree-select-disabled { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; + + .devui-tree-select-input { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; + } + + .devui-tree-select-arrow { + cursor: not-allowed; + color: $devui-disabled-text; + } +} + +.devui-tree-select-open { + .devui-tree-select-arrow { + transform: rotate3d(0, 0, 1, 180deg); + } +} + +.devui-tree-select-input { + cursor: pointer; + width: 100%; + height: $tree-select-input-height; + padding: 4px $tree-select-input-height 4px 10px; + color: $devui-text; + vertical-align: middle; + border: 1px solid $devui-form-control-line; + border-radius: $devui-border-radius; + outline: none; + background-color: $devui-base-bg; +} + +.devui-tree-select-dropdown { + border-radius: $devui-border-radius; + background: $devui-base-bg; + box-shadow: 0 2px 5px 0 $devui-shadow; +} + +.devui-tree-select-dropdown-list { + max-height: $tree-select-dropdown-max-height; + overflow-y: auto; + padding: 0; + margin: 0; +} + +.devui-tree-select-item { + font-size: $tree-select-item-font-size; + display: block; + min-height: $tree-select-item-min-height; + line-height: 1.5; + width: 100%; + padding: 10px; + clear: both; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + border: 0; + color: $devui-text; + cursor: pointer; + + &:hover:not(.active):not(.disabled) { + color: $devui-list-item-hover-text; + background-color: $devui-list-item-hover-bg; + } +} + +.devui-tree-select-clearable:hover { + .devui-tree-select-clear { + display: inline-flex; + } + + .devui-tree-select-arrow { + display: none; + } +} + +.devui-tree-select-clearable:hover { + .devui-tree-select-clear { + display: inline-flex; + } + + .devui-tree-select-arrow { + display: none; + } +} + +.devui-tree-select-clear, +.devui-tree-select-arrow { + position: absolute; + right: 0; + height: 100%; + width: $tree-select-input-height; + display: inline-flex; + justify-content: center; + align-items: center; +} + +.devui-tree-select-clear { + display: none; + + &:hover { + cursor: pointer; + color: $devui-icon-fill-active; + } +} + +.devui-tree-select-arrow-expand { + display: inline-flex; + justify-content: center; + align-items: center; + transform: rotate3d(0, 0, 1, 270deg); +} + +.devui-tree-select-arrow-open { + transform: rotate3d(0, 0, 1, 0deg); +} diff --git a/packages/devui-vue/devui/tree-select/src/tree-select.tsx b/packages/devui-vue/devui/tree-select/src/tree-select.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ed99e34b6d3d37764ac7386e3ac40509c3cf5260 --- /dev/null +++ b/packages/devui-vue/devui/tree-select/src/tree-select.tsx @@ -0,0 +1,145 @@ +import './tree-select.scss' + +import { defineComponent, ref, reactive, toRefs, computed } from 'vue' +import { treeSelectProps, TreeSelectProps } from './tree-select-types' +import { className } from './utils' + +export default defineComponent({ + name: 'DTreeSelect', + props: treeSelectProps, + emits: ['toggleChange', 'valueChange', 'update:modelValue'], + setup(props: TreeSelectProps, ctx) { + + const visible = ref<boolean>(false) + const origin = ref() + const position = reactive({ + originX: 'left', + originY: 'bottom', + overlayX: 'left', + overlayY: 'top' + }) + const inputValue = ref<string>('') + + const { treeData } = toRefs(props) + + const mergeClearable = computed<boolean>(() => { + return !props.disabled && props.allowClear && inputValue.value.length > 0; + }) + + function toggleChange() { + if (props.disabled) return + visible.value = !visible.value + ctx.emit('toggleChange', visible.value) + } + + function valueChange(data) { + if (data.isOpen !== undefined) { + data.isOpen = !data.isOpen + } else { + inputValue.value = data.label + visible.value = false + ctx.emit('update:modelValue', data.label) + ctx.emit('toggleChange', visible.value) + } + } + + function handleClear(e: MouseEvent) { + e.preventDefault() + e.stopPropagation() + if (props.multiple) { + ctx.emit('update:modelValue', []) + } else { + ctx.emit('update:modelValue', '') + inputValue.value = '' + } + } + + return { + visible, + origin, + position, + inputValue, + mergeClearable, + treeData, + handleClear, + toggleChange, + valueChange, + } + }, + render() { + const { + origin, + position, + inputValue, + mergeClearable, + treeData, + placeholder, + disabled, + handleClear, + toggleChange, + valueChange + } = this + + const treeSelectCls = className('devui-tree-select', { + 'devui-tree-select-open': this.visible, + 'devui-tree-select-disabled': disabled, + }) + + const renderNode = (item) => ( + <div + class="devui-tree-select-item" + style={{ paddingLeft: `${20 * (item.level - 1)}px` }} + onClick={(e: MouseEvent) => { + e.preventDefault() + e.stopPropagation() + valueChange(item) + }}> + { item.children ? + <span class={['devui-tree-select-arrow-expand', item.isOpen ? 'devui-tree-select-arrow-open' : '']}> + <d-icon name="select-arrow" /> + </span> : <span>{'\u00A0\u00A0\u00A0'}</span>} + {item.label} + </div> + ) + + const renderTree = (treeData) => { + return treeData.map(item => { + if (item.children) { + return ( + <> + { renderNode(item) } + { item.isOpen && renderTree(item.children) } + </> + ) + } + return renderNode(item) + }) + } + + return ( + <div class={treeSelectCls}> + <div class={mergeClearable ? 'devui-tree-select-clearable' : ''} ref="origin" onClick={toggleChange}> + <input + value={inputValue} + type="text" + class="devui-tree-select-input" + placeholder={placeholder} + readonly + disabled={disabled} + /> + <span onClick={handleClear} class="devui-tree-select-clear"> + <d-icon name="close" /> + </span> + <span class="devui-tree-select-arrow"> + <d-icon name="select-arrow" /> + </span> + </div> + <d-flexible-overlay origin={origin} v-model={[this.visible, 'visible']} position={position}> + <div class="devui-tree-select-dropdown"> + <ul class="devui-tree-select-dropdown-list">{renderTree(treeData)}</ul> + </div> + </d-flexible-overlay> + </div> + ) + } +}) diff --git a/packages/devui-vue/devui/tree-select/src/utils.ts b/packages/devui-vue/devui/tree-select/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..3092da7789a04ffc4321311f268cccd1b802bb9b --- /dev/null +++ b/packages/devui-vue/devui/tree-select/src/utils.ts @@ -0,0 +1,19 @@ +/** + * 动态获取class字符串 + * @param classStr 是一个字符串,固定的class名 + * @param classOpt 是一个对象,key表示class名,value为布尔值,true则添加,否则不添加 + * @returns 最终的class字符串 + */ +export function className( + classStr: string, + classOpt?: { [key: string]: boolean; } +): string { + let classname = classStr; + if (typeof classOpt === 'object') { + Object.keys(classOpt).forEach((key) => { + classOpt[key] && (classname += ` ${key}`); + }); + } + + return classname; +} diff --git a/packages/devui-vue/devui/tree/__tests__/tree.spec.ts b/packages/devui-vue/devui/tree/__tests__/tree.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..427125f6d772f47edbd603e131d8f7e02e178f0c --- /dev/null +++ b/packages/devui-vue/devui/tree/__tests__/tree.spec.ts @@ -0,0 +1,187 @@ +import { mount, VueWrapper } from '@vue/test-utils' +import { ref, nextTick } from 'vue' +import DTree from '../src/tree' + +describe('tree', () => { + let wrapper: VueWrapper<any> + + beforeEach(() => { + const data = ref([ + { + label: 'parent node 1 - expanded', + open: true, + disabled: true, + level: 1, + children: [ + { + label: 'parent node 11 - folded', + level: 2, + children: [ + { + label: 'leaf node 111', + level: 3, + }, + { + label: 'leaf node 112', + level: 3, + }, + { + label: 'leaf node 113', + level: 3, + }, + { + label: 'leaf node 114', + level: 3, + } + ] + }, + { + label: 'parent node 12 - folded', + disableToggle: true, + level: 2, + children: [ + { + label: 'leaf node 121', + level: 3, + }, + { + label: 'leaf node 122', + level: 3, + }, + { + label: 'leaf node 123', + level: 3, + }, + { + label: 'leaf node 124', + level: 3, + } + ] + }, + { + label: 'parent node 13 - without children - dynamic loading', + isParent: true, + level: 2, + } + ] + }, + { + label: 'parent node 2 - folded', + level: 1, + children: [ + { + label: 'parent node 21 - expanded', + open: true, + level: 2, + children: [ + { + label: 'leaf node 211', + level: 3, + }, + { + label: 'leaf node 212', + level: 3, + }, + { + label: 'leaf node 213', + level: 3, + }, + { + label: 'leaf node 214', + level: 3, + } + ] + }, + { + label: 'parent node 22 - folded', + level: 2, + children: [ + { + label: 'leaf node 221', + level: 3, + }, + { + label: 'leaf node 222', + level: 3, + }, + { + label: 'leaf node 223', + level: 3, + }, + { + label: 'leaf node 224', + level: 3, + } + ] + }, + { + label: 'parent node 23 - folded', + level: 2, + children: [ + { + label: 'leaf node 231', + level: 3, + }, + { + label: 'leaf node 232', + level: 3, + }, + { + label: 'leaf node 233', + level: 3, + }, + { + label: 'leaf node 234', + level: 3, + } + ] + } + ] + }, + { + id: 'dynamicNode', + label: 'parent node 3 - without children - dynamic loading', + isParent: true, + level: 1, + data: { + id: 'newChildNode', + name: 'new child node' + } + } + ]) + + wrapper = mount({ + components: { DTree }, + template: ` + <d-tree :data="data"></d-tree> + `, + setup () { + return { + data, + } + } + }) + }) + + it('should render correctly', () => { + expect(wrapper.classes()).toContain('devui-tree') + expect(wrapper.element.childElementCount).toBe(6) + }) + + it('should expand and collapse correctly', async () => { + const firstNode: Element = wrapper.element.firstElementChild + + // 初始状态,节点是展开的 + expect(firstNode.classList).toContain('devui-tree-node__open') + + // 点击之后,节点收起 + await wrapper.find('.devui-tree-node').trigger('click') + await nextTick() + expect(firstNode.classList).not.toContain('devui-tree-node__open') + + // 再次点击,节点展开 + await wrapper.find('.devui-tree-node').trigger('click') + await nextTick() + expect(firstNode.classList).toContain('devui-tree-node__open') + }) +}) diff --git a/packages/devui-vue/devui/tree/index.ts b/packages/devui-vue/devui/tree/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cae6212838ca06901b29e9e4f6fa1dafdf014484 --- /dev/null +++ b/packages/devui-vue/devui/tree/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Tree from './src/tree' + +Tree.install = function(app: App): void { + app.component(Tree.name, Tree) +} + +export { Tree } + +export default { + title: 'Tree 树', + category: '数据展示', + status: '20%', + install(app: App): void { + app.use(Tree as any) + } +} diff --git a/packages/devui-vue/devui/tree/src/assets/close.svg b/packages/devui-vue/devui/tree/src/assets/close.svg new file mode 100644 index 0000000000000000000000000000000000000000..2bb8e7f8194373d0c40e23af4cc80c684c9c140a --- /dev/null +++ b/packages/devui-vue/devui/tree/src/assets/close.svg @@ -0,0 +1,17 @@ +<svg + width="16px" + height="16px" + viewBox="0 0 16 16" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + class="svg-icon" +> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <rect x="0.5" y="0.5" width="15" height="15" rx="2" stroke="#252b3a"></rect> + <path + fill="#252b3a" + d="M8.75,4 L8.75,7.25 L12,7.25 L12,8.75 L8.749,8.75 L8.75,12 L7.25,12 L7.249,8.75 L4,8.75 L4,7.25 L7.25,7.25 L7.25,4 L8.75,4 Z" + ></path> + </g> +</svg> diff --git a/packages/devui-vue/devui/tree/src/assets/open.svg b/packages/devui-vue/devui/tree/src/assets/open.svg new file mode 100644 index 0000000000000000000000000000000000000000..a69af88b169b95da702114d77e49b9a510ecfd21 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/assets/open.svg @@ -0,0 +1,14 @@ +<svg + width="16px" + height="16px" + viewBox="0 0 16 16" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + class="svg-icon svg-icon-close" +> + <g stroke-width="1" fill="none" fill-rule="evenodd"> + <rect x="0.5" y="0.5" width="15" height="15" rx="2" stroke="#5e7ce0"></rect> + <rect x="4" y="7" width="8" height="2" fill="#5e7ce0"></rect> + </g> +</svg> \ No newline at end of file diff --git a/packages/devui-vue/devui/tree/src/composables/use-checked.ts b/packages/devui-vue/devui/tree/src/composables/use-checked.ts new file mode 100644 index 0000000000000000000000000000000000000000..b22d9927887fa34430543a0a3d3b41e831829b6d --- /dev/null +++ b/packages/devui-vue/devui/tree/src/composables/use-checked.ts @@ -0,0 +1,144 @@ +import type { SetupContext, Ref } from 'vue' +import { unref, ref } from 'vue' +import { + TreeItem, + SelectType, + ReverseTree, + CheckableRelationType, +} from '../tree-types' +import { flatten } from '../util' + +export default function useChecked( + cbr: Ref<CheckableRelationType>, + ctx: SetupContext, + data: any[] +) { + const selected = ref<SelectType>({}) + const flatData = flatten(data) + + const findPedigreeById = (id: string) => { + const treeData = data + let parentLevel: ReverseTree = {} + let childLevel: string[] = [] + let target = undefined + const ergodic = (curr: any[], parentNode: ReverseTree) => { + curr.every(({ children, id: itemId }) => { + if (target) { + return false + } + if (itemId === id) { + parentLevel = parentNode + childLevel = Array.isArray(children) + ? flatten(children).map(({ id: key }) => key) + : [] + target = itemId + return false + } + if (Array.isArray(children)) { + ergodic(children, { + id: itemId, + children: children.map(({ id: key }) => key), + parent: parentNode, + }) + } + return true + }) + } + ergodic(treeData, {}) + return { + parentLevel, + childLevel, + } + } + + const generateParentObject = ( + parentLevel: ReverseTree, + isSelected: boolean, + checkId: string + ): SelectType => { + const state: SelectType = {} + const currentSelected = unref(selected) + const ergodic = (currObj: ReverseTree, isOverflow = false) => { + const { id, children, parent } = currObj + if (!parent) { + return + } + if (isSelected) { + const optional = children.filter( + (item) => !currentSelected[item] || currentSelected[item] === 'none' + ) + if (optional.length <= 1) { + if (optional[0] === checkId) { + state[id] = 'select' + } else if (isOverflow) { + state[id] = 'half' + } + } else { + state[id] = 'half' + } + ergodic(parent, state[id] === 'select') + } else { + const optional = children.filter( + (item) => currentSelected[item] && currentSelected[item] !== 'none' + ) + if (optional.length <= 1) { + if (optional[0] === checkId || isOverflow) { + state[id] = 'none' + } + } else { + state[id] = 'half' + } + ergodic(parent, state[id] === 'none') + } + } + ergodic(parentLevel) + return state + } + + const onNodeClick = (item: TreeItem) => { + const { id } = item + let currentSelected = Object.assign({}, unref(selected)) + const isSelected = currentSelected[id] === 'none' || !currentSelected[id] + if (cbr.value === 'none') { + currentSelected = Object.assign(currentSelected, { + [id]: isSelected ? 'select' : 'none', + }) + } else if (cbr.value === 'both') { + const { parentLevel, childLevel } = findPedigreeById(id) + currentSelected = Object.assign( + currentSelected, + Object.fromEntries( + childLevel.map((key) => [key, isSelected ? 'select' : 'none']) + ), + generateParentObject(parentLevel, isSelected, id), + { [id]: isSelected ? 'select' : 'none' } + ) + } else if (cbr.value === 'upward') { + const { parentLevel } = findPedigreeById(id) + currentSelected = Object.assign( + currentSelected, + generateParentObject(parentLevel, isSelected, id), + { [id]: isSelected ? 'select' : 'none' } + ) + } else if (cbr.value === 'downward') { + const { childLevel } = findPedigreeById(id) + currentSelected = Object.assign( + currentSelected, + Object.fromEntries( + childLevel.map((key) => [key, isSelected ? 'select' : 'none']) + ), + { [id]: isSelected ? 'select' : 'none' } + ) + } + selected.value = currentSelected + const currentSelectedItem = flatData.filter( + ({ id }) => currentSelected[id] && currentSelected[id] !== 'none' + ) + ctx.emit('nodeSelected', currentSelectedItem) + } + + return { + selected, + onNodeClick, + } +} diff --git a/packages/devui-vue/devui/tree/src/composables/use-highlight.ts b/packages/devui-vue/devui/tree/src/composables/use-highlight.ts new file mode 100644 index 0000000000000000000000000000000000000000..5874f66f0994241ed8da6509f097c693dc97b510 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/composables/use-highlight.ts @@ -0,0 +1,38 @@ +import { ref, Ref } from 'vue' + +interface TypeHighlightClass { + [key: string]: 'active' | '' | 'devui-tree_isDisabledNode' +} +type TypeUseHighlightNode = () => { + nodeClassNameReflect: Ref<TypeHighlightClass> + handleClickOnNode: (index: string) => void + handleInitNodeClassNameReflect: (isDisabled: boolean, ...keys: Array<string>) => string +} + +const HIGHLIGHT_CLASS = 'active' +const IS_DISABLED_FLAG = 'devui-tree_isDisabledNode' +const useHighlightNode: TypeUseHighlightNode = () => { + const nodeClassNameReflectRef = ref<TypeHighlightClass>({}) + const handleInit = (isDisabled = false, ...keys) => { + const key = keys.join('-') + nodeClassNameReflectRef.value[key] = isDisabled ? IS_DISABLED_FLAG : (nodeClassNameReflectRef.value[key] || '') + return key + } + const handleClick = (key) => { + if (nodeClassNameReflectRef.value[key] === IS_DISABLED_FLAG) { + return + } + nodeClassNameReflectRef.value = + Object.fromEntries( + Object + .entries(nodeClassNameReflectRef.value) + .map(([k]) => [k, k === key ? HIGHLIGHT_CLASS : '']) + ) + } + return { + nodeClassNameReflect: nodeClassNameReflectRef, + handleClickOnNode: handleClick, + handleInitNodeClassNameReflect: handleInit, + } +} +export default useHighlightNode diff --git a/packages/devui-vue/devui/tree/src/composables/use-lazy.ts b/packages/devui-vue/devui/tree/src/composables/use-lazy.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b7debd0478b4ffdd35c11b409e7c23370752de7 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/composables/use-lazy.ts @@ -0,0 +1,64 @@ +import { ref, Ref } from 'vue' +import { TreeData, TreeItem } from '../tree-types' + +interface TypeReflectValue { + // 外部传入 + id: keyof TypeReflect // 懒加载节点 id + onGetNodeData: () => Promise<TreeData> // 懒加载获取数据函数, 当前是节点 children + renderLoading?: (id: string) => any // loadingTemplate 挂载 + // useLazy 内部使用 + loadingTargetId?: string // loadingTemplate 挂载节点 id + dataSource?: TreeData // 懒加载数据 +} +interface TypeReflect { + [key: string]: TypeReflectValue +} +type TypeHandleInit = (item: TreeItem, value: TypeReflectValue) => void +type TypeGetLazyData = (key: keyof TypeReflect) => Promise<TreeItem> | any +type TypeUseLazy = () => { + lazyNodesReflect: Ref<TypeReflect> + handleInitLazyNodeReflect: TypeHandleInit + getLazyData: TypeGetLazyData +} + +const useLazy: TypeUseLazy = () => { + const reflect = ref<TypeReflect>({}) + + const handleInit: TypeHandleInit = (item, value) => { + if (!item.isParent) { + return + } + const key = reflect.value[value.id]?.id.toString() + if (!key) { + reflect.value[value.id] = { + ...value, + loadingTargetId: `devui-tree_loadingTemplate-${value.id}`, + dataSource: null + } + } + } + + const getLazyData: TypeGetLazyData = async (key) => { + const ds = reflect.value[key] + if (ds.dataSource) { + return ds.dataSource + } + const handleLoading = reflect.value[key].renderLoading(reflect.value[key].loadingTargetId) + try { + reflect.value[key].dataSource = await ds.onGetNodeData() + } catch(e) { + console.error(e) + } finally { + handleLoading.loadingInstance.close() + } + return reflect.value[key].dataSource + } + + return { + lazyNodesReflect: reflect, + handleInitLazyNodeReflect: handleInit, + getLazyData, + } +} + +export default useLazy diff --git a/packages/devui-vue/devui/tree/src/composables/use-merge-node.ts b/packages/devui-vue/devui/tree/src/composables/use-merge-node.ts new file mode 100644 index 0000000000000000000000000000000000000000..705cf07809a726a03854203c13b513b818d2d6b2 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/composables/use-merge-node.ts @@ -0,0 +1,54 @@ +import { ref } from 'vue' + +export default function useMergeNode(data: Array<any>): any { + + + const mergeObject = ( + treeItem, + childName = 'children', + labelName = 'label' + ) => { + const { [childName]: children, [labelName]: label } = treeItem + if ( + Array.isArray(children) && + children.length === 1 && + children[0][childName] && + children[0][childName].length === 1 + ) { + return mergeObject( + Object.assign({}, children[0], { + [labelName]: `${label} \\ ${children[0][labelName]}`, + }) + ) + } + return treeItem + } + + const mergeNode = ( + tree: Array<any>, + level = 0, + childName = 'children', + labelName = 'label' + ): Array<any> => { + return tree.map((item) => { + const { [childName]: children } = item + if (!Array.isArray(children) || !children.length) { + return Object.assign({}, item, { level: level + 1 }) + } + let currentObject = item + if (children.length === 1) { + currentObject = mergeObject(item) + } + return Object.assign({}, currentObject, { + [childName]: mergeNode(currentObject[childName], level + 1, childName, labelName), + level: level + 1, + }) + }) + } + + const mergeData = ref(mergeNode(data)) + + return { + mergeData, + } +} diff --git a/packages/devui-vue/devui/tree/src/composables/use-toggle.ts b/packages/devui-vue/devui/tree/src/composables/use-toggle.ts new file mode 100644 index 0000000000000000000000000000000000000000..632218d1e0afba618bf56f9dabeae6c236577646 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/composables/use-toggle.ts @@ -0,0 +1,25 @@ +import { ref } from 'vue' + +export default function useToggle(data: unknown): any { + const openedTree = (tree) => { + return tree.reduce((acc, item) => ( + item.open + ? acc.concat(item, openedTree(item.children)) + : acc.concat(item) + ), []) + } + + const openedData = ref(openedTree(data)) + + const toggle = (target, item) => { + target.stopPropagation() + if (!item.children) return + item.open = !item.open + openedData.value = openedTree(data) + } + + return { + openedData, + toggle, + } +} diff --git a/packages/devui-vue/devui/tree/src/config.ts b/packages/devui-vue/devui/tree/src/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbd834d3d802d9abfe6d304c07e3688df292c8f5 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/config.ts @@ -0,0 +1,9 @@ +export const CHECK_CONFIG = { + none: {}, + half: { + halfchecked: true + }, + select: { + checked: true, + }, +} diff --git a/packages/devui-vue/devui/tree/src/tree-node-content.tsx b/packages/devui-vue/devui/tree/src/tree-node-content.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3882736d4259f4328157874df81948bab3309f92 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/tree-node-content.tsx @@ -0,0 +1,22 @@ +import { defineComponent, h, inject } from 'vue' +import { TreeRootType } from './tree-types' + +export default defineComponent({ + name: 'DTreeNodeContent', + props: { + node: { + type: Object, + required: true, + }, + }, + setup(props) { + const tree = inject<TreeRootType>('treeRoot') + return () => { + const node = props.node + const { disabled, label } = node + return tree.ctx.slots.default + ? tree.ctx.slots.default({ node }) + : <span class={['devui-tree-node__title', disabled && 'select-disabled']}>{ label }</span> + } + }, +}) diff --git a/packages/devui-vue/devui/tree/src/tree-types.ts b/packages/devui-vue/devui/tree/src/tree-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..03c9940125596cc1e483e802e7a4a219f3c76c31 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/tree-types.ts @@ -0,0 +1,47 @@ +import type { PropType, ExtractPropTypes, SetupContext } from 'vue' + +export interface TreeItem { + id: string + label: string + isParent?: boolean + level: number + open?: boolean + children?: TreeData + [key: string]: any +} +export interface SelectType { + [key: string]: 'none' | 'half' | 'select' +} + +export interface ReverseTree { + id?: string + children?: string[] + parent?: ReverseTree +} + +export type TreeData = Array<TreeItem> + +export type CheckableRelationType = 'downward' | 'upward' | 'both' | 'none' + +export const treeProps = { + data: { + type: Array as PropType<TreeData>, + required: true, + default: () => [], + }, + checkable: { + type: Boolean, + default: false + }, + checkableRelation: { + type: String as () => CheckableRelationType, + default: 'none', + } +} as const + +export type TreeProps = ExtractPropTypes<typeof treeProps> + +export interface TreeRootType { + ctx: SetupContext<any> + props: TreeProps +} \ No newline at end of file diff --git a/packages/devui-vue/devui/tree/src/tree.scss b/packages/devui-vue/devui/tree/src/tree.scss new file mode 100644 index 0000000000000000000000000000000000000000..2ffc16243dfcc699939115e8bd448d71724a7c4b --- /dev/null +++ b/packages/devui-vue/devui/tree/src/tree.scss @@ -0,0 +1,314 @@ +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/mixins/index'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; + +$keyframe-blue: #5e7ce0; + +.devui-text-ellipsis { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.devui-tree-node { + color: $devui-text-weak; + line-height: 1.5; + white-space: nowrap; + position: relative; + + .devui-tree-node__content { + display: inline-flex; + align-items: center; + font-size: $devui-font-size; + padding-right: 10px; + width: 100%; + border-radius: $devui-border-radius; + padding-left: 6px; + + &.active { + background-color: $devui-list-item-selected-bg; + text-decoration: none; + border-color: transparent; + } + + &:not(.active):hover { + background-color: $devui-list-item-hover-bg; + } + } + + .devui-tree-node__content--value-wrapper { + display: inline-flex; + align-items: center; + height: 30px; + width: 100%; + + .devui-tree-node_loading { + margin-left: 50px; + + .devui-loading-area { + background: none; + } + } + } + + .devui-tree-node__children { + padding-left: 10px; + + &:first-child { + border-left-color: transparent; + } + + .devui-tree-node { + margin-left: 8px; + content: ''; + position: relative; + + &:last-child { + border-left-color: transparent; + } + } + } + + .devui-tree-node__title { + @extend .devui-text-ellipsis; + + margin-left: 5px; + display: inline-block; + border: 1px dashed transparent; + border-radius: $devui-border-radius; + max-width: 100%; + + &:not(.disabled) { + cursor: pointer; + } + } + + .devui-tree-node__edit { + margin-left: 0.4em; + padding: 0.1em; + + > .devui-input-sm { + height: 26px; + + &.error, + &.error:hover, + &.error:focus { + border-color: $devui-danger; + } + } + } + + .devui-tree-node__leaf { + &:not(.disabled) { + cursor: default; + } + + .devui-tree-node__leaf--default { + color: #f2a71f; + } + + .devui-leaf-icon-none { + display: inline-block; + width: 16px; + height: 16px; + } + } + + .devui-tree-node__folder { + display: inline-block; + vertical-align: middle; + user-select: none; + font-size: $devui-font-size-icon; + height: 16px; + line-height: 16px; + + .devui-tree-node__folder--icon { + display: inline-block; + height: 16px; + line-height: 16px; + + &:hover { + svg g path { + fill: $devui-icon-fill-active; + } + + svg g rect { + stroke: $devui-icon-fill-active; + } + } + } + + &:not(.disabled) { + cursor: pointer; + } + + .devui-tree-node__folder--default { + color: #f2b806; + } + } + + .devui-loading-children { + display: inline-block; + vertical-align: middle; + margin-left: 0.5em; + margin-top: 0.15em; + color: $devui-info; + font-style: italic; + font-size: 1em; + animation-name: devui-loading-children; + animation-duration: 2s; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; + } + @keyframes devui-loading-children { + 0% { + color: lighten($keyframe-blue, 0.95); + } + + 12.5% { + color: lighten($keyframe-blue, 0.85); + } + + 25% { + color: lighten($keyframe-blue, 0.75); + } + + 37.5% { + color: lighten($keyframe-blue, 0.65); + } + + 50% { + color: lighten($keyframe-blue, 0.55); + } + + 62.5% { + color: lighten($keyframe-blue, 0.45); + } + + 75% { + color: lighten($keyframe-blue, 0.35); + } + + 87.5% { + color: lighten($keyframe-blue, 0.1); + } + + 100% { + color: $keyframe-blue; + } + } + + svg.svg-icon path { + fill: $devui-icon-text; + } + + svg.svg-icon rect { + stroke: $devui-icon-text; + } + + &.devui-tree-node__open:not(.devui-tree-node__customIcon) { + & > .devui-tree-node__content svg.svg-icon path { + fill: $devui-icon-fill-active; + } + + & > .devui-tree-node__content svg.svg-icon rect { + stroke: $devui-icon-fill-active; + } + + & > .devui-tree-node__content svg.svg-icon.svg-icon-close rect:last-child { + stroke: none; + fill: $devui-icon-fill-active; + } + } + + svg.svg-icon.svg-icon-close rect:last-child { + stroke: none; + fill: $devui-icon-text; + } +} + +::ng-deep .devui-tree-mask { + background: $devui-list-item-hover-bg; +} + +/* 视觉融合灰线 */ +.devui-tree-node.devui-tree-without-virtual-scroll { + &.devui-tree-node__open { + & > .devui-tree-node__content { + position: relative; + } + } + + & > .devui-tree-node__children { + position: relative; + + &::before { + content: ''; + width: 1px; + height: calc(100% - 15px); // 父级总高度减去半个content的高度 + background-color: $devui-dividing-line; + position: absolute; + left: calc(10px - 1px); // 父级10px的padding减去自身1px宽度 + top: 0; + } + + .devui-tree-node__content { + // 只要是子级就都存在左边横线 + position: relative; + + &::before { + content: ''; + width: 8px; + height: 1px; + background-color: $devui-dividing-line; + position: absolute; + left: calc(-1px - 8px); // 对接左侧灰线,自身margin为1.2em加上1px的线宽 + top: 50%; + } + } + } +} + +.devui-tree-vertical-line { + width: 1px; + background-color: $devui-dividing-line; + position: absolute; +} + +.devui-tree-horizontal-line { + height: 1px; + background-color: $devui-dividing-line; + position: absolute; + top: 50%; + margin-left: -16px; +} + +.toggle-disabled { + cursor: not-allowed !important; + + svg.svg-icon rect { + stroke: $devui-disabled-text !important; + } + + svg.svg-icon.svg-icon-close rect:last-child { + stroke: none !important; + fill: $devui-disabled-text !important; + } + + svg.svg-icon path { + fill: $devui-disabled-text !important; + } +} + +.select-disabled { + color: $devui-disabled-text !important; + cursor: not-allowed !important; + background-color: transparent !important; +} + +.devui-tree-node__content { + transition: color $devui-animation-duration-fast $devui-animation-ease-in-smooth, background-color $devui-animation-duration-fast $devui-animation-ease-in-smooth; +} diff --git a/packages/devui-vue/devui/tree/src/tree.tsx b/packages/devui-vue/devui/tree/src/tree.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f9b45da9ea20e9deb5026317eeb991a2320e0e6e --- /dev/null +++ b/packages/devui-vue/devui/tree/src/tree.tsx @@ -0,0 +1,125 @@ +import { defineComponent, toRefs, provide } from 'vue' +import type { SetupContext } from 'vue' +import { treeProps, TreeProps, TreeItem, TreeRootType } from './tree-types' +import { CHECK_CONFIG } from './config' +import { precheckTree } from './util' +import Loading from '../../loading/src/service' +import Checkbox from '../../checkbox/src/checkbox' +import useToggle from './composables/use-toggle' +import useMergeNode from './composables/use-merge-node' +import useHighlightNode from './composables/use-highlight' +import useChecked from './composables/use-checked' +import useLazy from './composables/use-lazy' +import IconOpen from './assets/open.svg' +import IconClose from './assets/close.svg' +import NodeContent from './tree-node-content' +import './tree.scss' + +export default defineComponent({ + name: 'DTree', + props: treeProps, + emits: ['nodeSelected'], + setup(props: TreeProps, ctx: SetupContext) { + const { data, checkable, checkableRelation: cbr } = toRefs({ ...props, data: precheckTree(props.data) }) + const { mergeData } = useMergeNode(data.value) + const { openedData, toggle } = useToggle(mergeData.value) + const { nodeClassNameReflect, handleInitNodeClassNameReflect, handleClickOnNode } = useHighlightNode() + const { lazyNodesReflect, handleInitLazyNodeReflect, getLazyData } = useLazy() + const { selected, onNodeClick } = useChecked(cbr, ctx, data.value) + + provide<TreeRootType>('treeRoot', { ctx, props }) + const Indent = () => { + return <span style="display: inline-block; width: 16px; height: 16px; margin-left: 8px;"></span> + } + + const renderNode = (item: TreeItem) => { + const { id = '', label, disabled, open, isParent, level, children } = item + handleInitNodeClassNameReflect(disabled, id) + handleInitLazyNodeReflect(item, { + id, + onGetNodeData: async () => { + return new Promise((resolve) => { + setTimeout(() => { + resolve([ + { + id: `It is a test Node-1 ID = ${id}`, + label: `It is a test Node-1 ID = ${id}`, + level: item.level + 1 + }, { + id: `It is a test Node-2 ID = ${id}`, + label: `It is a test Node-2 ID = ${id}`, + level: item.level + 1 + } + ]) + }, 4000) + }) + }, + renderLoading: (id) => { + return Loading.open({ + target: document.getElementById(id), + message: '加载中...', + positionType: 'relative', + zIndex: 1, + }) + } + }) + const renderNodeWithIcon = (item: TreeItem) => { + const handleClick = async (target: MouseEvent) => { + if (item.isParent) { + item.children = await getLazyData(id) // item 按引用传递 + } + return toggle(target, item) + } + return ( + isParent || children + ? open + ? <IconOpen class="mr-xs" onClick={handleClick} /> + : <IconClose class="mr-xs" onClick={handleClick} /> + : <Indent /> + ) + } + const checkState = CHECK_CONFIG[selected.value[id] ?? 'none'] + return ( + <div + class={['devui-tree-node', open && 'devui-tree-node__open']} + style={{ paddingLeft: `${24 * (level - 1)}px` }} + > + <div + class={`devui-tree-node__content ${nodeClassNameReflect.value[id]}`} + onClick={() => handleClickOnNode(id)} + > + <div class="devui-tree-node__content--value-wrapper"> + {renderNodeWithIcon(item)} + {checkable.value && <Checkbox key={id} onClick={() => onNodeClick(item)} disabled={disabled} {...checkState} />} + <NodeContent node={item}/> + {item.isParent && <div class='devui-tree-node_loading' id={lazyNodesReflect.value[id].loadingTargetId} />} + </div> + </div> + </div> + ) + } + + const renderTree = (tree) => { + return tree.map(item => { + if (!item.children) { + return renderNode(item) + } else { + return ( + <> + {renderNode(item)} + {renderTree(item.children)} + </> + ) + } + }) + } + return () => { + return ( + <div class="devui-tree"> + {/* { renderTree(data.value) } */} + { openedData.value.map(item => renderNode(item)) } + </div> + ) + } + } +}) diff --git a/packages/devui-vue/devui/tree/src/util.ts b/packages/devui-vue/devui/tree/src/util.ts new file mode 100644 index 0000000000000000000000000000000000000000..65c68355aa582140e56e4e2c783e7b445451a73b --- /dev/null +++ b/packages/devui-vue/devui/tree/src/util.ts @@ -0,0 +1,38 @@ +import { TreeData, TreeItem } from './tree-types' + +export const omit = (obj: unknown, key: string): unknown => { + return Object.entries(obj) + .filter(item => item[0] !== key) + .reduce((acc, item) => Object.assign({}, acc, { [item[0]]: item[1] }), {}) +} + +export const flatten = (tree: Array<any>, key = 'children'): Array<any> => { + return tree.reduce((acc, item) => ( + !item[key] ? acc.concat(item) : acc.concat(item, flatten(item[key], key)) + ), []) +} + +/** + * 用于设置 Tree Node 的 ID 属性 + * 应用场景: 懒加载 loading 后元素定位 + */ +const precheckNodeId = (d: TreeItem): TreeItem => { + const random = parseInt((Math.random() * (10 ** 8)).toString().padEnd(8, '0')) + return { ...d, id: d.id ? `${d.id}_${random}` : `${d.label.replaceAll(' ', '-')}_${random}` } +} + +/** + * 用于 Tree Node 的数据格式检查 + */ +export const precheckTree = (ds: TreeData): TreeData => { + return ds.map(d => { + const dd = precheckNodeId(d) + if (d.children) { + return { + ...dd, + children: precheckTree(d.children) + } + } + return dd + }) +} diff --git a/packages/devui-vue/devui/upload/__tests__/upload.spec.ts b/packages/devui-vue/devui/upload/__tests__/upload.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..31dcf2239c7aae1b3f7a42a593626cb9b9dedc0f --- /dev/null +++ b/packages/devui-vue/devui/upload/__tests__/upload.spec.ts @@ -0,0 +1,198 @@ +import { mount } from '@vue/test-utils' +import { ref, nextTick, reactive } from 'vue' +import DSingleUpload from '../src/single-upload' +import DMultipleUpload from '../src/multiple-upload' +const getMockFile = (element: Element, files: File[]): void => { + Object.defineProperty(element, 'files', { + get() { + return files + }, + }) +} + +describe('single upload', () => { + it('should render correctly', () => { + const TestComponent = { + components: { + 'd-single-upload': DSingleUpload, + }, + template: ` + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + /> + `, + setup() { + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + }) + const uploadedFiles = ref([]) + return { + fileOptions, + uploadedFiles, + uploadOptions, + } + }, + } + mount(TestComponent) + }) + it('should work with `disabled` prop', () => { + const TestComponent = { + components: { + 'd-single-upload': DSingleUpload, + }, + template: ` + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + :disabled="true" + /> + `, + setup() { + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + }) + const uploadedFiles = ref([]) + return { + fileOptions, + uploadedFiles, + uploadOptions, + } + }, + } + const wrapper = mount(TestComponent) + expect(wrapper.find('.devui-input-group.disabled').exists()).toBe(true) + }) + it('should work with `before-upload auto-upload withoutBtn` prop', async () => { + const beforeUpload = jest.fn(async () => true) + + const TestComponent = { + components: { + 'd-single-upload': DSingleUpload, + }, + template: ` + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + :before-upload="beforeUpload" + :auto-upload="true" + :withoutBtn="true" + /> + `, + setup() { + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + }) + const uploadedFiles = ref([]) + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + } + }, + } + const wrapper = mount(TestComponent) + const uploadElment = wrapper.find('.devui-input-group') + await uploadElment.trigger('click') + await nextTick() + const input = document.getElementById('d-upload-temp') + const fileList = [new File(['test'], 'file.txt')] + getMockFile(input, fileList) + const evt = new Event('change') + await input.dispatchEvent(evt) + expect(beforeUpload).toHaveBeenCalled() + expect(wrapper.find('.devui-upload button').exists()).toBe(false) + }) + it('should work with `showTip placeholderText uploadText` prop', async () => { + const TestComponent = { + components: { + 'd-single-upload': DSingleUpload, + }, + template: ` + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + :showTip="true" + placeholderText="select file" + uploadText="upload" + /> + `, + setup() { + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + }) + const uploadedFiles = ref([]) + return { + fileOptions, + uploadedFiles, + uploadOptions, + } + }, + } + const wrapper = mount(TestComponent) + expect(wrapper.find('.devui-upload-tip').exists()).toBe(true) + expect(wrapper.find('.devui-upload-placeholder').text()).toBe('select file') + expect(wrapper.find('.devui-upload button').text()).toBe('upload') + }) +}) + +describe('multi upload', () => { + it('should render correctly', () => { + const TestComponent = { + components: { + 'd-multi-upload': DMultipleUpload, + }, + template: ` + <div> + <d-multi-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + /> + </div> + `, + setup() { + const fileOptions = reactive({ + accept: '', + multiple: true, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + }) + const uploadedFiles = ref([]) + return { + fileOptions, + uploadedFiles, + uploadOptions, + } + }, + } + mount(TestComponent) + }) +}) diff --git a/packages/devui-vue/devui/upload/index.ts b/packages/devui-vue/devui/upload/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..01f70902ad0d70ea773c1db79deac0d6dc641c33 --- /dev/null +++ b/packages/devui-vue/devui/upload/index.ts @@ -0,0 +1,21 @@ +import type { App } from 'vue' +import Upload from './src/single-upload' +import MultiUpload from './src/multiple-upload' +import fileDropDirective from './src/file-drop-directive' + +Upload.install = function (app: App) { + app.directive('file-drop', fileDropDirective) + app.component(Upload.name, Upload) + app.component(MultiUpload.name, MultiUpload) +} + +export { Upload, MultiUpload } + +export default { + title: 'Upload 上传', + category: '数据录入', + status: '80%', + install(app: App): void { + app.use(Upload as any) + }, +} diff --git a/packages/devui-vue/devui/upload/src/file-drop-directive.ts b/packages/devui-vue/devui/upload/src/file-drop-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..e74602f6911ee9ceb94cf7f4269d9acf8a20e72e --- /dev/null +++ b/packages/devui-vue/devui/upload/src/file-drop-directive.ts @@ -0,0 +1,86 @@ +interface BindingType { + value: { + enableDrop?: boolean + isSingle?: boolean + onFileDrop?: (files: File[]) => void + onFileOver?: (event: any) => void + } +} + +const getTransfer = (event: any) => { + return event.dataTransfer + ? event.dataTransfer + : event.originalEvent?.dataTransfer +} + +const haveFiles = (types: any) => { + if (!types) { + return false + } + + if (types.indexOf) { + return types.indexOf('Files') !== -1 + } else if (types.contains) { + return types.contains('Files') + } else { + return false + } +} + +const preventAndStop = (event: any) => { + event.preventDefault() + event.stopPropagation() +} + +const onDragOver = (el: HTMLElement, binding: BindingType) => { + const { onFileOver } = binding.value + el.addEventListener('dragover', (event) => { + const transfer = getTransfer(event) + if (!haveFiles(transfer.types)) { + return + } + preventAndStop(event) + onFileOver && onFileOver(true) + }) +} + +const onDragLeave = (el: HTMLElement, binding: BindingType) => { + const { onFileOver } = binding.value + el.addEventListener('dragleave', (event) => { + if (event.currentTarget === el) { + return + } + preventAndStop(event) + onFileOver && onFileOver(true) + }) +} + +const onDrop = (el: HTMLElement, binding: BindingType) => { + const { onFileDrop, isSingle } = binding.value + el.addEventListener('drop', (event) => { + const transfer = getTransfer(event) + if (!transfer) { + return + } + preventAndStop(event) + if (isSingle) { + onFileDrop && onFileDrop([transfer.files[0]]) + } else { + onFileDrop && onFileDrop(transfer.files) + } + }) +} + +const fileDropDirective = { + mounted: (el: HTMLElement, binding: BindingType): void => { + const { enableDrop } = binding.value + if (!enableDrop) { + return + } + onDragOver(el, binding) + onDragLeave(el, binding) + onDrop(el, binding) + }, +} + +export default fileDropDirective diff --git a/packages/devui-vue/devui/upload/src/file-uploader.ts b/packages/devui-vue/devui/upload/src/file-uploader.ts new file mode 100755 index 0000000000000000000000000000000000000000..1acef9d914ee0521119d18474f9ca1aa34bbf74c --- /dev/null +++ b/packages/devui-vue/devui/upload/src/file-uploader.ts @@ -0,0 +1,133 @@ +import { IUploadOptions, UploadStatus } from './upload-types' + +export class FileUploader { + private xhr: XMLHttpRequest + public status: UploadStatus + public response: any + public percentage = 0 + + constructor(public file: File, public uploadOptions: IUploadOptions) { + this.file = file + this.uploadOptions = uploadOptions + this.status = UploadStatus.preLoad + } + + send(uploadFiles?: FileUploader[]): Promise<{ file: File; response: any; }> { + return new Promise((resolve, reject) => { + const { + uri, + method, + headers, + authToken, + authTokenHeader, + additionalParameter, + fileFieldName, + withCredentials, + responseType, + } = this.uploadOptions + const authTokenHeader_ = authTokenHeader || 'Authorization' + const fileFieldName_ = fileFieldName || 'file' + + this.xhr = new XMLHttpRequest() + this.xhr.open(method || 'POST', uri) + + if (withCredentials) { + this.xhr.withCredentials = withCredentials + } + + if (responseType) { + this.xhr.responseType = responseType + } + + if (authToken) { + this.xhr.setRequestHeader(authTokenHeader_, authToken) + } + + if (headers) { + Object.keys(headers).forEach((key) => { + this.xhr.setRequestHeader(key, headers[key]) + }) + } + + this.xhr.upload.onprogress = (e) => { + this.percentage = Math.round((e.loaded * 100) / e.total) + } + + const formData = + uploadFiles && uploadFiles.length + ? this.oneTimeUploadFiles( + fileFieldName_, + additionalParameter, + uploadFiles + ) + : this.parallelUploadFiles(fileFieldName_, additionalParameter) + + this.xhr.send(formData) + this.status = UploadStatus.uploading + + this.xhr.onabort = () => { + this.status = UploadStatus.preLoad + this.xhr = null + } + + this.xhr.onerror = () => { + this.response = this.xhr.response + this.status = UploadStatus.failed + reject({ file: this.file, response: this.xhr.response }) + } + + this.xhr.onload = () => { + if ( + this.xhr.readyState === 4 && + this.xhr.status >= 200 && + this.xhr.status < 300 + ) { + this.response = this.xhr.response + this.status = UploadStatus.uploaded + resolve({ file: this.file, response: this.xhr.response }) + } else { + this.response = this.xhr.response + this.status = UploadStatus.failed + reject({ file: this.file, response: this.xhr.response }) + } + } + }) + } + + parallelUploadFiles( + fileFieldName_: string, + additionalParameter: Record<string, any> + ): FormData { + const formData = new FormData() + formData.append(fileFieldName_, this.file, this.file.name) + if (additionalParameter) { + Object.keys(additionalParameter).forEach((key: string) => { + formData.append(key, additionalParameter[key]) + }) + } + return formData + } + + oneTimeUploadFiles( + fileFieldName_: string, + additionalParameter: Record<string, any>, + uploadFiles: FileUploader[] + ): FormData { + const formData = new FormData() + uploadFiles.forEach((element) => { + formData.append(fileFieldName_, element.file, element.file.name) + if (additionalParameter) { + Object.keys(additionalParameter).forEach((key: string) => { + formData.append(key, additionalParameter[key]) + }) + } + }) + return formData + } + + cancel(): void { + if (this.xhr) { + this.xhr.abort() + } + } +} diff --git a/packages/devui-vue/devui/upload/src/i18n-upload.ts b/packages/devui-vue/devui/upload/src/i18n-upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2cbbc3820f514cde84b2dcba6344952a697d3f7 --- /dev/null +++ b/packages/devui-vue/devui/upload/src/i18n-upload.ts @@ -0,0 +1,42 @@ +export const i18nText = { + warning: '提醒', + upload: '上传', + chooseFile: '选择文件', + chooseFiles: '选择多个文件', + preload: '预加载', + uploading: '上传中...', + uploaded: '已上传', + uploadFailed: '上传失败', + uploadSuccess: '上传成功!', + delete: '删除', + reUpload: '重新上传', + cancelUpload: '取消上传', +} + +export const getFailedFilesCount = (failedCount: number): string => + `${failedCount}个文件上传失败!` +export const getUploadingFilesCount = ( + uploadingCount: number, + filesCount: number +): string => `${uploadingCount}/${filesCount}正在上传` +export const getSelectedFilesCount = (filesCount: number): string => + `已添加${filesCount}个文件` +export const getAllFilesBeyondMaximalFileSizeMsg = ( + maximalSize: number +): string => + `最大支持上传${maximalSize}MB的文件, 您本次上传的所有文件超过可上传文件大小` +export const getBeyondMaximalFileSizeMsg = ( + filename: string, + maximalSize: number +): string => { + return `最大支持上传${maximalSize}MB的文件, 您上传的文件"${filename}"超过可上传文件大小` +} +export const getNotAllowedFileTypeMsg = ( + filename: string, + scope: string +): string => { + return `支持的文件类型: "${scope}", 您上传的文件"${filename}"不在允许范围内,请重新选择文件` +} +export const getExistSameNameFilesMsg = (sameNames: string): string => { + return `您上传的 "${sameNames}" 存在重名文件, 请重新选择文件` +} diff --git a/packages/devui-vue/devui/upload/src/multiple-upload.tsx b/packages/devui-vue/devui/upload/src/multiple-upload.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0928fe4106b23878bb278236f0a9062e1de07173 --- /dev/null +++ b/packages/devui-vue/devui/upload/src/multiple-upload.tsx @@ -0,0 +1,390 @@ +import { defineComponent, toRefs, ref } from 'vue' +import { ToastService } from '../../toast' +import { UploadStatus, multiUploadProps } from './upload-types' +import { useSelectFiles } from './use-select-files' +import { useUpload } from './use-upload' +import { + getFailedFilesCount, + getSelectedFilesCount, + getUploadingFilesCount, + i18nText, + getExistSameNameFilesMsg, +} from './i18n-upload' +import { FileUploader } from './file-uploader' +import './upload.scss' + +export default defineComponent({ + name: 'DMultipleUpload', + props: multiUploadProps, + emits: [ + 'fileDrop', + 'fileOver', + 'fileSelect', + 'successEvent', + 'errorEvent', + 'deleteUploadedFileEvent', + 'update:uploadedFiles', + ], + setup(props, ctx) { + const { + uploadOptions, + fileOptions, + placeholderText, + autoUpload, + withoutBtn, + uploadText, + disabled, + beforeUpload, + enableDrop, + oneTimeUpload, + showTip, + uploadedFiles, + } = toRefs(props) + const { + triggerSelectFiles, + _validateFiles, + triggerDropFiles, + checkAllFilesSize, + } = useSelectFiles() + const { + getFiles, + fileUploaders, + addFile, + getFullFiles, + deleteFile, + upload, + resetSameNameFiles, + removeFiles, + _oneTimeUpload, + getSameNameFiles, + } = useUpload() + const isDropOVer = ref(false) + const uploadTips = ref('') + const alertMsg = (errorMsg: string) => { + ToastService.open({ + value: [{ severity: 'warn', content: errorMsg }], + }) + } + const checkValid = () => { + let totalFileSize = 0 + + fileUploaders.value.forEach((fileUploader) => { + totalFileSize += fileUploader.file.size + + const checkResult = _validateFiles( + fileUploader.file, + fileOptions.value.accept, + fileUploader.uploadOptions + ) + if (checkResult && checkResult.checkError) { + deleteFile(fileUploader.file) + alertMsg(checkResult.errorMsg) + return + } + }) + + if (oneTimeUpload.value) { + const checkResult = checkAllFilesSize( + totalFileSize, + uploadOptions.value.maximumSize + ) + if (checkResult && checkResult.checkError) { + removeFiles() + alertMsg(checkResult.errorMsg) + } + } + } + + const _dealFiles = (promise: Promise<File[]>) => { + resetSameNameFiles() + promise + .then((files) => { + files.forEach((file) => { + addFile(file, uploadOptions.value) + // debounceTime(100) + }) + checkValid() + const sameNameFiles = getSameNameFiles() + if (uploadOptions.value.checkSameName && sameNameFiles.length) { + alertMsg(getExistSameNameFilesMsg(sameNameFiles)) + } + const selectedFiles = fileUploaders.value + .filter( + (fileUploader) => fileUploader.status === UploadStatus.preLoad + ) + .map((fileUploader) => fileUploader.file) + ctx.emit('fileSelect', selectedFiles) + if (autoUpload.value) { + upload() + } + }) + .catch((error: Error) => { + alertMsg(error.message) + }) + } + + const handleClick = () => { + if (disabled.value) { + return + } + _dealFiles(triggerSelectFiles(fileOptions.value)) + } + + const onFileDrop = (files: File[]) => { + isDropOVer.value = false + _dealFiles(triggerDropFiles(files)) + ctx.emit('fileDrop', files) + } + const onFileOver = (event: boolean) => { + isDropOVer.value = event + ctx.emit('fileOver', event) + } + const onDeleteFile = (event: Event, file: File) => { + event.stopPropagation() + deleteFile(file) + } + // 删除已上传文件 + const deleteUploadedFile = (file: File) => { + const newUploadedFiles = uploadedFiles.value.filter((uploadedFile) => { + return uploadedFile.name !== file.name + }) + ctx.emit('deleteUploadedFileEvent', file) + ctx.emit('update:uploadedFiles', newUploadedFiles) + } + const canUpload = () => { + let uploadResult = Promise.resolve(true) + if (beforeUpload.value) { + const result: any = beforeUpload.value(getFullFiles()) + if (typeof result !== 'undefined') { + if (result.then) { + uploadResult = result + } else { + uploadResult = Promise.resolve(result) + } + } + } + return uploadResult + } + const fileUpload = (event: Event, fileUploader?: FileUploader) => { + if (event) { + event.stopPropagation() + } + canUpload().then((_canUpload) => { + if (!_canUpload) { + removeFiles() + return + } + const uploadObservable = oneTimeUpload.value + ? _oneTimeUpload() + : upload(fileUploader) + + uploadObservable + .then((results: Array<{ file: File; response: any; }>) => { + ctx.emit('successEvent', results) + const newFiles = results.map((result) => result.file) + const newUploadedFiles = [...newFiles, ...uploadedFiles.value] + ctx.emit('update:uploadedFiles', newUploadedFiles) + }) + .catch((error) => { + ctx.emit('errorEvent', error) + }) + }) + } + + const getStatus = () => { + let uploadingCount = 0 + let uploadedCount = 0 + let failedCount = 0 + const filesCount = fileUploaders.value.length + fileUploaders.value.forEach((fileUploader) => { + if (fileUploader.status === UploadStatus.uploading) { + uploadingCount++ + } else if (fileUploader.status === UploadStatus.uploaded) { + uploadedCount++ + } else if (fileUploader.status === UploadStatus.failed) { + failedCount++ + } + }) + if (failedCount > 0) { + uploadTips.value = getFailedFilesCount(failedCount) + return 'failed' + } + if (uploadingCount > 0) { + uploadTips.value = getUploadingFilesCount(uploadingCount, filesCount) + return 'uploading' + } + if (uploadedCount === filesCount && uploadedCount !== 0) { + return 'uploaded' + } + if (filesCount !== 0) { + uploadTips.value = getSelectedFilesCount(filesCount) + return 'selected' + } + } + + // 取消上传 + const cancelUpload = () => { + fileUploaders.value = fileUploaders.value.map((fileUploader) => { + if (fileUploader.status === UploadStatus.uploading) { + // 取消上传请求 + fileUploader.cancel() + fileUploader.status = UploadStatus.failed + } + return fileUploader + }) + } + + return { + uploadOptions, + fileOptions, + placeholderText, + autoUpload, + withoutBtn, + uploadText, + disabled, + beforeUpload, + enableDrop, + isDropOVer, + onFileDrop, + onFileOver, + handleClick, + fileUploaders, + onDeleteFile, + fileUpload, + showTip, + getStatus, + uploadTips, + cancelUpload, + deleteUploadedFile, + } + }, + render() { + const { + placeholderText, + autoUpload, + withoutBtn, + uploadText, + disabled, + beforeUpload, + enableDrop, + isDropOVer, + onFileDrop, + onFileOver, + handleClick, + fileUploaders, + onDeleteFile, + fileUpload, + showTip, + getStatus, + uploadTips, + cancelUpload, + uploadedFiles, + deleteUploadedFile, + } = this + return ( + <> + <div + class="devui-upload" + v-file-drop={{ enableDrop, isSingle: false, onFileDrop, onFileOver }} + style={`border: ${isDropOVer ? '1px solid #15bf15' : '0'}`} + > + {this.$slots.default?.() ? ( + <div onClick={handleClick}>{this.$slots.default()}</div> + ) : ( + <div + class={`devui-input-group ${disabled ? 'disabled' : ''}`} + onClick={handleClick} + > + {fileUploaders.length === 0 && ( + <div class="devui-form-control devui-upload-placeholder"> + {placeholderText} + </div> + )} + {fileUploaders.length > 0 && ( + <ul class="devui-form-control devui-files-list"> + {fileUploaders.map((fileUploader, index) => ( + <li + key={index} + class="devui-file-item devui-file-tag" + style="display: inline-block; margin: 0 2px 2px 0" + title={fileUploader.file.name} + > + <span + class={`evui-filename ${ + fileUploader.status === UploadStatus.failed + ? 'devui-failed-color' + : '' + }`} + > + {fileUploader.file.name} + </span> + <d-icon + name="close" + class={`${ + fileUploader?.status === UploadStatus.failed + ? 'devui-upload-delete-file-button' + : '' + } ${ + fileUploader?.status === UploadStatus.uploading || + fileUploader?.status === UploadStatus.uploaded + ? 'devui-uploading-delete' + : '' + }`} + onClick={(event) => + onDeleteFile(event, fileUploader.file) + } + /> + {fileUploader.status === UploadStatus.uploading && ( + <div class="icon devui-upload-progress"> + <d-progress + isCircle={true} + percentage={fileUploader.percentage} + barbgcolor="#50D4AB" + strokeWidth={8} + showContent={false} + ></d-progress> + </div> + )} + {fileUploader.status === UploadStatus.failed && ( + <d-icon name="running" onClick={fileUpload} /> + )} + {fileUploader.status === UploadStatus.uploaded && ( + <d-icon name="right" color="#50d4ab" /> + )} + </li> + ))} + </ul> + )} + <span class="devui-input-group-addon"> + <d-icon name="more-operate" color="#252b3a" /> + </span> + </div> + )} + {!autoUpload && !withoutBtn && ( + <d-button + style="marginLeft: 8px" + bsStyle="common" + disabled={disabled} + onClick={fileUpload} + > + {uploadText} + </d-button> + )} + </div> + {} + <div> + {this.$slots.preloadFiles?.({ + fileUploaders, + deleteFile: onDeleteFile, + })} + </div> + <div> + {this.$slots.uploadedFiles?.({ + uploadedFiles, + deleteFile: deleteUploadedFile, + })} + </div> + </> + ) + }, +}) diff --git a/packages/devui-vue/devui/upload/src/single-upload.tsx b/packages/devui-vue/devui/upload/src/single-upload.tsx new file mode 100644 index 0000000000000000000000000000000000000000..23c84d49f3acb7b58a4bb3ea54e48a5790d5753b --- /dev/null +++ b/packages/devui-vue/devui/upload/src/single-upload.tsx @@ -0,0 +1,346 @@ +import { defineComponent, toRefs, computed, ref } from 'vue' +import { ToastService } from '../../toast' +import { uploadProps, UploadProps, UploadStatus } from './upload-types' +import { useUpload } from './use-upload' +import { useSelectFiles } from './use-select-files' +import { i18nText } from './i18n-upload' +import './upload.scss' + +export default defineComponent({ + name: 'DSingleUpload', + props: uploadProps, + emits: [ + 'fileDrop', + 'fileOver', + 'fileSelect', + 'successEvent', + 'errorEvent', + 'deleteUploadedFileEvent', + 'update:uploadedFiles', + ], + setup(props: UploadProps, ctx) { + const { + uploadOptions, + fileOptions, + placeholderText, + autoUpload, + withoutBtn, + uploadText, + disabled, + beforeUpload, + enableDrop, + showTip, + uploadedFiles, + } = toRefs<UploadProps>(props) + const isDropOVer = ref(false) + const { + getFiles, + fileUploaders, + addFile, + getFullFiles, + deleteFile, + upload, + removeFiles, + } = useUpload() + const { triggerSelectFiles, _validateFiles, triggerDropFiles } = + useSelectFiles() + const filename = computed(() => (getFiles()[0] || {}).name || '') + + const alertMsg = (errorMsg: string) => { + ToastService.open({ + value: [{ severity: 'warn', content: errorMsg }], + }) + } + + const canUpload = () => { + let uploadResult = Promise.resolve(true) + if (beforeUpload.value) { + const result: any = beforeUpload.value( + (getFullFiles()[0] as unknown as File) || ({} as File) + ) + if (typeof result !== 'undefined') { + if (result.then) { + uploadResult = result + } else { + uploadResult = Promise.resolve(result) + } + } + } + return uploadResult + } + + const fileUpload = () => { + canUpload().then((canUpload) => { + if (!canUpload) { + return + } + upload() + .then((results: { file: File; response: any; }[]) => { + ctx.emit('successEvent', results) + const newFiles = results.map((result) => result.file) + const newUploadedFiles = [...newFiles, ...uploadedFiles.value] + ctx.emit('update:uploadedFiles', newUploadedFiles) + }) + .catch((error) => { + console.error(error) + if (fileUploaders.value[0]) { + fileUploaders.value[0].percentage = 0 + } + ctx.emit('errorEvent', error) + }) + }) + } + + const checkValid = () => { + fileUploaders.value.forEach((fileUploader) => { + const checkResult = _validateFiles( + fileUploader.file, + fileOptions.value.accept, + fileUploader.uploadOptions + ) + if (checkResult.checkError) { + deleteFile(fileUploader.file) + alertMsg(checkResult.errorMsg) + } + }) + } + + const _dealFiles = (promise: Promise<File[]>) => { + promise + .then((files) => { + files.forEach((file) => { + // 单文件上传前先清空数组 + removeFiles() + addFile(file, uploadOptions.value) + }) + checkValid() + const file = fileUploaders.value[0]?.file + if (props.onChange) { + props.onChange(file) + } + if (file) { + ctx.emit('fileSelect', file) + } + if (autoUpload.value) { + fileUpload() + } + }) + .catch((error: Error) => { + alertMsg(error.message) + }) + } + + const handleClick = () => { + if ( + disabled.value || + (fileUploaders.value[0] && + fileUploaders.value[0]?.status === UploadStatus.uploading) + ) { + return + } + _dealFiles(triggerSelectFiles(fileOptions.value)) + } + + const onDeleteFile = (event: Event) => { + event.stopPropagation() + const files = getFiles() + deleteFile(files[0]) + } + // 删除已上传文件 + const deleteUploadedFile = (file: File) => { + const newUploadedFiles = uploadedFiles.value.filter((uploadedFile) => { + return uploadedFile.name !== file.name + }) + ctx.emit('deleteUploadedFileEvent', file) + ctx.emit('update:uploadedFiles', newUploadedFiles) + } + const onFileDrop = (files: File[]) => { + isDropOVer.value = false + _dealFiles(triggerDropFiles(files)) + ctx.emit('fileDrop', files[0]) + } + const onFileOver = (event: boolean) => { + isDropOVer.value = event + ctx.emit('fileOver', event) + } + return { + placeholderText, + filename, + autoUpload, + withoutBtn, + fileUploaders, + uploadText, + handleClick, + onDeleteFile, + fileUpload, + enableDrop, + onFileDrop, + onFileOver, + isDropOVer, + showTip, + uploadedFiles, + deleteUploadedFile, + } + }, + render() { + const { + placeholderText, + filename, + autoUpload, + withoutBtn, + fileUploaders, + uploadText, + handleClick, + onDeleteFile, + fileUpload, + enableDrop, + onFileDrop, + onFileOver, + isDropOVer, + disabled, + showTip, + uploadedFiles, + deleteUploadedFile, + } = this + return ( + <div> + <div + class="devui-upload" + v-file-drop={{ enableDrop, isSingle: true, onFileDrop, onFileOver }} + style={`border: ${isDropOVer ? '1px solid #15bf15' : '0'}`} + > + {this.$slots.default?.() ? ( + <div onClick={handleClick}>{this.$slots.default()}</div> + ) : ( + <div + class={`devui-input-group ${ + disabled || fileUploaders[0]?.status === UploadStatus.uploading + ? 'disabled' + : '' + }`} + onClick={handleClick} + > + <div class="devui-form-control devui-files-list"> + {!filename && ( + <div class="devui-file-item devui-upload-placeholder"> + {placeholderText} + </div> + )} + {!!filename && ( + <div + class="devui-file-tag devui-file-item" + title={filename} + style="display: inline-block; margin: 0 2px 2px 0" + > + <span + class={`devui-filename ${ + fileUploaders[0]?.status === UploadStatus.failed + ? 'devui-failed-color' + : '' + }`} + > + {filename} + </span> + <d-icon + name="close" + class={`${ + fileUploaders[0]?.status === UploadStatus.failed + ? 'devui-upload-delete-file-button' + : '' + } ${ + fileUploaders[0]?.status === UploadStatus.uploading || + fileUploaders[0]?.status === UploadStatus.uploaded + ? 'devui-uploading-delete' + : '' + }`} + onClick={(event) => onDeleteFile(event)} + /> + {fileUploaders[0]?.status === UploadStatus.uploading && ( + <div class="icon devui-upload-progress"> + <d-progress + isCircle={true} + percentage={fileUploaders[0].percentage} + barbgcolor="#50D4AB" + strokeWidth={8} + showContent={false} + ></d-progress> + </div> + )} + {fileUploaders[0].status === UploadStatus.failed && ( + <d-icon name="running" onClick={fileUpload} /> + )} + {fileUploaders[0].status === UploadStatus.uploaded && ( + <d-icon name="right" color="#50d4ab" /> + )} + </div> + )} + </div> + <span class="devui-input-group-addon"> + <d-icon name="more-operate" color="#252b3a" /> + </span> + </div> + )} + {!autoUpload && !withoutBtn && ( + <d-button + style="marginLeft: 8px" + bsStyle="common" + onClick={fileUpload} + disabled={ + disabled || fileUploaders[0]?.status === UploadStatus.uploading + } + > + {(!fileUploaders[0] || !fileUploaders[0]?.status) && ( + <span>{uploadText}</span> + )} + {fileUploaders[0]?.status === UploadStatus.uploading && ( + <span>上传中...</span> + )} + {fileUploaders[0]?.status === UploadStatus.uploaded && ( + <span>已上传</span> + )} + {fileUploaders[0]?.status === UploadStatus.failed && ( + <span>上传失败</span> + )} + </d-button> + )} + </div> + {showTip && ( + <div class="devui-upload-tip"> + {fileUploaders[0]?.status === UploadStatus.uploading && ( + <span class="devui-loading">{i18nText.uploading}</span> + )} + {fileUploaders[0]?.status === UploadStatus.uploaded && ( + <div class="devui-loaded"> + <d-icon name="right-o" color="#50d4ab" /> + <span style="vertical-align: middle"> + {i18nText.uploadSuccess} + </span> + </div> + )} + {fileUploaders[0]?.status === UploadStatus.failed && ( + <div class="devui-upload-failed"> + <d-icon name="info-o" color="#f66f6a" /> + <span style="vertical-align: middle"> + <span style="margin-right: 8px">{i18nText.uploadFailed}</span> + <a onClick={fileUpload}>{i18nText.reUpload}</a> + </span> + </div> + )} + </div> + )} + <div> + {this.$slots.preloadFiles?.({ + fileUploaders, + deleteFile: onDeleteFile, + })} + </div> + <div> + {this.$slots.uploadedFiles?.({ + uploadedFiles, + deleteFile: deleteUploadedFile, + })} + </div> + </div> + ) + }, +}) diff --git a/packages/devui-vue/devui/upload/src/upload-types.ts b/packages/devui-vue/devui/upload/src/upload-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1567766aa35c53c34003545ebc17f4299dac26e8 --- /dev/null +++ b/packages/devui-vue/devui/upload/src/upload-types.ts @@ -0,0 +1,202 @@ +import type { PropType, ExtractPropTypes } from 'vue' +export class IUploadOptions { + // 上传接口地址 + uri: string + // http 请求方法 + method?: string + // 上传文件大小限制 + maximumSize?: number + // 自定义请求headers + headers?: { + [key: string]: any + } + // 认证token + authToken?: string + // 认证token header标示 + authTokenHeader?: string + // 上传额外自定义参数 + additionalParameter?: { + [key: string]: any + } + // 上传文件字段名称,默认file + fileFieldName?: string + // 多文件上传,是否检查文件重名,设置为true,重名文件不会覆盖,否则会覆盖上传 + checkSameName?: boolean + // 指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求 + withCredentials?: boolean + // 手动设置返回数据类型 + responseType?: 'arraybuffer' | 'blob' | 'json' | 'text' +} + +export class IFileOptions { + accept?: string + multiple: boolean + webkitdirectory: boolean +} + +export enum UploadStatus { + preLoad = 0, + uploading, + uploaded, + failed, +} + +type DynamicUploadOptionsFn = (files, uploadOptions) => IUploadOptions +type ChangeFn = (_: any) => void +type BeforeUploadFn = (file: File) => boolean | Promise<boolean> +export const uploadProps = { + uploadOptions: { + type: Object as PropType<IUploadOptions>, + required: true, + }, + fileOptions: { + type: Object as PropType<IFileOptions>, + required: true, + }, + autoUpload: { + type: Boolean, + default: false, + }, + placeholderText: { + type: String, + default: '选择文件', + }, + uploadText: { + type: String, + default: '上传', + }, + uploadedFiles: { + type: Array as PropType<File[]>, + default: () => [], + }, + withoutBtn: { + type: Boolean, + default: false, + }, + enableDrop: { + type: Boolean, + default: false, + }, + beforeUpload: { + type: Function as PropType<BeforeUploadFn>, + }, + dynamicUploadOptionsFn: { + type: Function as PropType<DynamicUploadOptionsFn>, + }, + disabled: { + type: Boolean, + default: false, + }, + showTip: { + type: Boolean, + default: false, + }, + onChange: { + type: Function as PropType<ChangeFn>, + }, + fileDrop: { + type: Function as PropType<(v: any) => void>, + default: undefined, + }, + fileOver: { + type: Function as PropType<(v: boolean) => void>, + default: undefined, + }, + fileSelect: { + type: Function as PropType<(v: File) => void>, + default: undefined, + }, + errorEvent: { + type: Function as PropType<(v: { file: File; response: any; }) => void>, + default: undefined, + }, + successEvent: { + type: Function as PropType<(v: { file: File; response: any; }[]) => void>, + default: undefined, + }, + deleteUploadedFileEvent: { + type: Function as PropType<(v: string) => void>, + default: undefined, + }, +} as const +export type UploadProps = ExtractPropTypes<typeof uploadProps> + +export const multiUploadProps = { + uploadOptions: { + type: Object as PropType<IUploadOptions>, + required: true, + }, + fileOptions: { + type: Object as PropType<IFileOptions>, + required: true, + }, + autoUpload: { + type: Boolean, + default: false, + }, + withoutBtn: { + type: Boolean, + default: false, + }, + showTip: { + type: Boolean, + default: false, + }, + uploadedFiles: { + type: Array as PropType<File[]>, + default: () => [], + }, + enableDrop: { + type: Boolean, + default: false, + }, + placeholderText: { + type: String, + default: '选择文件', + }, + uploadText: { + type: String, + default: '上传', + }, + oneTimeUpload: { + type: Boolean, + default: false, + }, + disabled: { + type: Boolean, + default: false, + }, + beforeUpload: { + type: Function as PropType<(files: any) => boolean | Promise<boolean>>, + }, + fileDrop: { + type: Function as PropType<(v: any) => void>, + default: undefined, + }, + fileOver: { + type: Function as PropType<(v: boolean) => void>, + default: undefined, + }, + fileSelect: { + type: Function as PropType<(v: File) => void>, + default: undefined, + }, + errorEvent: { + type: Function as PropType<(v: { file: File; response: any; }) => void>, + default: undefined, + }, + successEvent: { + type: Function as PropType<(v: { file: File; response: any; }[]) => void>, + default: undefined, + }, + deleteUploadedFileEvent: { + type: Function as PropType<(v: string) => void>, + default: undefined, + }, + setCustomUploadOptions: { + type: Function as PropType< + (files: File[], uploadOptions: IUploadOptions) => IUploadOptions + >, + default: undefined, + }, +} diff --git a/packages/devui-vue/devui/upload/src/upload.scss b/packages/devui-vue/devui/upload/src/upload.scss new file mode 100644 index 0000000000000000000000000000000000000000..287179cd863a6343b2f838f9c0e30067b8a88172 --- /dev/null +++ b/packages/devui-vue/devui/upload/src/upload.scss @@ -0,0 +1,219 @@ +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/mixins/index'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; + +.devui-input-group { + position: relative; + display: flex; + align-items: center; + border-collapse: separate; + width: 100%; +} + +.devui-input-group:not(.disabled):hover .devui-input-group-addon { + border-color: $devui-form-control-line-active; + background-color: $devui-dividing-line; + font-weight: bold; +} + +.devui-input-group:not(.disabled):hover .devui-form-control { + border-color: $devui-form-control-line-active; + border-right-color: $devui-form-control-line; +} + +.devui-input-group:not(.disabled) .devui-input-group-addon:active { + border-color: $devui-form-control-line-active; + border-right-color: $devui-form-control-line; + background-color: $devui-dividing-line; +} + +.devui-input-group .devui-input-group-addon { + width: 36px; + white-space: nowrap; + font-size: $devui-font-size-icon; + font-weight: normal; + line-height: 1; + color: $devui-text; + background-color: $devui-area; + border-top: 1px solid $devui-form-control-line; + border-bottom: 1px solid $devui-form-control-line; + border-right: 1px solid $devui-form-control-line; + border-radius: 0 $devui-border-radius $devui-border-radius 0; + transition: + border-color $devui-animation-duration-slow + $devui-animation-ease-in-out-smooth, + background-color $devui-animation-duration-slow + $devui-animation-ease-in-out-smooth; + cursor: pointer; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.devui-input-group .devui-form-control { + cursor: pointer; + display: block; + width: 100%; + min-height: 28px; + height: unset; + padding: 4px 8px; + font-size: $devui-font-size; + line-height: 1.5; + background-image: none; + border: 1px solid $devui-form-control-line; + border-radius: $devui-border-radius 0 0 $devui-border-radius; + transition: + border-color $devui-animation-duration-slow + $devui-animation-ease-in-out-smooth, + box-shadow $devui-animation-duration-slow + $devui-animation-ease-in-out-smooth; + + &.devui-files-list { + max-height: 52px; + padding: 2px 2px 0 2px; + overflow-x: hidden; + overflow-y: auto; + max-width: 100%; + margin: 0; + + .devui-file-item { + height: 22px; + line-height: 22px; + padding: 0 48px 0 12px; + } + + .devui-file-tag { + position: relative; + background-color: $devui-label-bg; + border-radius: $devui-border-radius; + max-width: 100%; + + .devui-filename { + height: 100%; + display: inline-block; + vertical-align: middle; + max-width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .icon { + position: absolute; + cursor: pointer; + right: 8px; + top: 50%; + transform: translateY(-50%); + + &.icon-right { + color: $devui-success; + } + + &.icon-running { + font-size: 16px; + } + + &.devui-upload-delete-file-button { + margin-right: 20px; + } + + &.devui-uploading-delete { + display: none; + } + } + + &:hover { + .devui-upload-progress, + .icon-right { + display: none; + } + + .icon-close { + display: inline-block; + } + } + } + } +} + +.devui-input-group { + &.disabled { + .devui-upload-placeholder { + color: $devui-disabled-text; + } + } + + .devui-upload-placeholder { + max-height: 28px; + max-width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: $devui-placeholder; + } +} + +.devui-input-group .devui-upload-progress { + width: 16px; + height: 16px; +} + +.devui-input-group.disabled .devui-form-control, +.devui-input-group.disabled .devui-input-group-addon { + cursor: not-allowed; + background-color: $devui-disabled-bg; + border-color: $devui-disabled-line; + color: $devui-disabled-text; +} + +.devui-form-control { + outline: none; +} + +.devui-input-group.disabled .devui-upload-delete-file-button { + cursor: not-allowed; + pointer-events: none; +} + +.devui-loading { + color: $devui-aide-text; +} + +.devui-failed-color { + color: $devui-danger; +} + +.devui-upload { + display: flex; +} + +.devui-upload-tip { + height: 18px; + margin-top: 8px; + font-size: 12px; + + .icon { + margin-right: 8px; + font-size: 16px; + vertical-align: middle; + } + + .icon-right-o { + color: $devui-success; + } + + .devui-upload-failed { + color: $devui-danger; + } + + a { + color: $devui-link; + cursor: pointer; + } +} diff --git a/packages/devui-vue/devui/upload/src/use-select-files.ts b/packages/devui-vue/devui/upload/src/use-select-files.ts new file mode 100644 index 0000000000000000000000000000000000000000..75caa61b0edeeb61d1718c44fa3bef0f777b4deb --- /dev/null +++ b/packages/devui-vue/devui/upload/src/use-select-files.ts @@ -0,0 +1,147 @@ +import { ref } from 'vue' +import { IFileOptions, IUploadOptions } from './upload-types' +import { + getNotAllowedFileTypeMsg, + getBeyondMaximalFileSizeMsg, + getAllFilesBeyondMaximalFileSizeMsg, +} from './i18n-upload' + +export const useSelectFiles = () => { + const BEYOND_MAXIMAL_FILE_SIZE_MSG = ref('') + const simulateClickEvent = (input) => { + const evt = document.createEvent('MouseEvents') + evt.initMouseEvent( + 'click', + true, + true, + window, + 1, + 0, + 0, + 0, + 0, + false, + false, + false, + false, + 0, + null + ) + input.dispatchEvent(evt) + } + const selectFiles = ({ + multiple, + accept, + webkitdirectory, + }: IFileOptions): Promise<File[]> => { + return new Promise((resolve) => { + const tempNode = document.getElementById('d-upload-temp') + if (tempNode) { + document.body.removeChild(tempNode) + } + const input = document.createElement('input') + + input.style.position = 'fixed' + input.style.left = '-2000px' + input.style.top = '-2000px' + + input.setAttribute('id', 'd-upload-temp') + input.setAttribute('type', 'file') + if (multiple) { + input.setAttribute('multiple', '') + } + if (accept) { + input.setAttribute('accept', accept) + } + + if (webkitdirectory) { + input.setAttribute('webkitdirectory', '') + } + + input.addEventListener('change', (event) => { + resolve( + Array.prototype.slice.call((event.target as HTMLInputElement).files) + ) + }) + document.body.appendChild(input) // Fix compatibility issue with Internet Explorer 11 + simulateClickEvent(input) + }) + } + + const isAllowedFileType = (accept: string, file: File) => { + if (accept) { + const acceptArr = accept.split(',') + const baseMimeType = file.type.replace(/\/.*$/, '') + return acceptArr.some((type: string) => { + const validType = type.trim() + // suffix name (e.g. '.png,.xlsx') + if (validType.startsWith('.')) { + return ( + file.name + .toLowerCase() + .indexOf( + validType.toLowerCase(), + file.name.toLowerCase().length - validType.toLowerCase().length + ) > -1 + ) + // mime type like 'image/*' + } else if (/\/\*$/.test(validType)) { + return baseMimeType === validType.replace(/\/.*$/, '') + } + // mime type like 'text/plain,application/json' + return file.type === validType + }) + } + return true + } + + const beyondMaximalSize = (fileSize, maximumSize) => { + if (maximumSize) { + return fileSize > 1024 * 1024 * maximumSize + } + return false + } + + const _validateFiles = (file, accept, uploadOptions) => { + if (!isAllowedFileType(accept, <File>file)) { + return { + checkError: true, + errorMsg: getNotAllowedFileTypeMsg((<File>file).name, accept), + } + } + if ( + uploadOptions && + beyondMaximalSize((<File>file).size, uploadOptions.maximumSize) + ) { + return { + checkError: true, + errorMsg: getBeyondMaximalFileSizeMsg( + (<File>file).name, + uploadOptions.maximumSize + ), + } + } + return { checkError: false, errorMsg: undefined } + } + + const triggerSelectFiles = (fileOptions: IFileOptions) => { + const { multiple, accept, webkitdirectory } = fileOptions + return selectFiles({ multiple, accept, webkitdirectory }) + } + const triggerDropFiles = (files: File[]) => { + return Promise.resolve(files) + } + const checkAllFilesSize = (fileSize, maximumSize) => { + if (beyondMaximalSize(fileSize, maximumSize)) { + BEYOND_MAXIMAL_FILE_SIZE_MSG.value = + getAllFilesBeyondMaximalFileSizeMsg(maximumSize) + return { checkError: true, errorMsg: BEYOND_MAXIMAL_FILE_SIZE_MSG.value } + } + } + return { + triggerSelectFiles, + _validateFiles, + triggerDropFiles, + checkAllFilesSize, + } +} diff --git a/packages/devui-vue/devui/upload/src/use-upload.ts b/packages/devui-vue/devui/upload/src/use-upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..72aa7a48d655743b091c0ad1445955aec4dddc83 --- /dev/null +++ b/packages/devui-vue/devui/upload/src/use-upload.ts @@ -0,0 +1,142 @@ +import { ref } from 'vue' +import { FileUploader } from './file-uploader' +import { UploadStatus } from './upload-types' + +export const useUpload = () => { + const fileUploaders = ref<Array<FileUploader>>([]) + const filesWithSameName = ref([]) + + const checkFileSame = (fileName) => { + let checkRel = true + + for (let i = 0; i < fileUploaders.value.length; i++) { + if (fileName === fileUploaders.value[i].file.name) { + checkRel = false + if (filesWithSameName.value.indexOf(fileName) === -1) { + filesWithSameName.value.push(fileName) + } + break + } + } + return checkRel + } + + const addFile = (file, options) => { + if (options && options.checkSameName) { + if (checkFileSame(file.name)) { + fileUploaders.value.push(new FileUploader(file, options)) + } + } else { + fileUploaders.value.push(new FileUploader(file, options)) + } + } + + const getFiles = () => { + return fileUploaders.value.map((fileUploader) => { + return fileUploader.file + }) + } + + const getFullFiles = () => { + return fileUploaders.value.map((fileUploader) => { + return fileUploader + }) + } + + const dealOneTimeUploadFiles = async (uploads) => { + if (!uploads || !uploads.length) { + return Promise.reject('no files') + } + // 触发文件上传 + let finalUploads = [] + await uploads[0].send(uploads).finally( + () => + // 根据uploads[0]的上传状态为其他file设置状态 + (finalUploads = uploads.map((file) => { + file.status = uploads[0].status + file.percentage = uploads[0].percentage + return { file: file.file, response: uploads[0].response } + })) + ) + + return finalUploads + } + + const upload = async ( + oneFile? + ): Promise< + | never + | { + file: File + response: any + }[] + > => { + let uploads: any[] = [] + if (oneFile) { + oneFile.percentage = 0 + const uploadedFile = await oneFile.send() + uploads.push(uploadedFile) + } else { + const preFiles = fileUploaders.value.filter( + (fileUploader) => fileUploader.status === UploadStatus.preLoad + ) + const failedFiles = fileUploaders.value.filter( + (fileUploader) => fileUploader.status === UploadStatus.failed + ) + const uploadFiles = preFiles.length > 0 ? preFiles : failedFiles + uploads = await Promise.all( + uploadFiles.map(async (fileUploader) => { + fileUploader.percentage = 0 + const uploadedFile = await fileUploader.send() + return uploadedFile + }) + ) + } + if (uploads.length > 0) { + return Promise.resolve(uploads) + } + + return Promise.reject('no files') + } + + const _oneTimeUpload = () => { + const uploads = fileUploaders.value.filter( + (fileUploader) => fileUploader.status !== UploadStatus.uploaded + ) + return dealOneTimeUploadFiles(uploads) + } + + const deleteFile = (file) => { + const deleteUploadFile = fileUploaders.value.find( + (fileUploader) => fileUploader.file === file + ) + deleteUploadFile.cancel() + fileUploaders.value = fileUploaders.value.filter((fileUploader) => { + return file !== fileUploader.file + }) + } + + const removeFiles = () => { + fileUploaders.value = [] + filesWithSameName.value = [] + } + const getSameNameFiles = () => { + return filesWithSameName.value.join() + } + const resetSameNameFiles = () => { + filesWithSameName.value = [] + } + + return { + fileUploaders, + getFiles, + addFile, + getFullFiles, + deleteFile, + upload, + removeFiles, + getSameNameFiles, + resetSameNameFiles, + _oneTimeUpload, + } +} diff --git a/packages/devui-vue/docs/.vitepress/config.js b/packages/devui-vue/docs/.vitepress/config.js new file mode 100644 index 0000000000000000000000000000000000000000..1fe86bc36ae40c4c3973ee4c7b64924945dab6f3 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config.js @@ -0,0 +1,4 @@ +require('esbuild-register') + +const config = require('./config/index.ts') +module.exports = config.default \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/enNav.ts b/packages/devui-vue/docs/.vitepress/config/enNav.ts new file mode 100644 index 0000000000000000000000000000000000000000..4522ec9bd14315692f7e5bdfc21b4c25c737a0f7 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/enNav.ts @@ -0,0 +1,8 @@ +const enNav = [ + { text: 'Design disciplines', link: '/en-US/design' }, + { text: 'Component', link: '/en-US/' }, + { text: 'Version history', link: '/en-US/version' }, + { text: 'Theme', link: '/en-US/theme' }, + ] + + export default enNav \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/enSidebar.ts b/packages/devui-vue/docs/.vitepress/config/enSidebar.ts new file mode 100644 index 0000000000000000000000000000000000000000..00c336177b60d0d33adc44eed92baeb417cf3224 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/enSidebar.ts @@ -0,0 +1,101 @@ +const enSidebar = { + '/en-US/': [ + { text: 'Quick Start', link: '/en-US/' }, + { + text: 'General', + children: [ + { text: 'Button', link: '/en-US/components/button/', status: 'completed' }, + { text: 'Icon', link: '/en-US/components/icon/', status: 'completed' }, + { text: 'DragDrop', link: '/en-US/components/dragdrop/' }, + { text: 'Fullscreen', link: '/en-US/components/fullscreen/' }, + { text: 'Panel', link: '/en-US/components/panel/', status: 'completed' }, + { text: 'Search', link: '/en-US/components/search/', status: 'completed' }, + { text: 'Status', link: '/en-US/components/status/', status: 'completed' }, + { text: 'Sticky', link: '/en-US/components/sticky/' }, + { text: 'Overlay', link: '/en-US/components/overlay/'} + ] + }, + { + text: 'Navigation', + children: [ + { text: 'Accordion', link: '/en-US/components/accordion/' }, + { text: 'Anchor', link: '/en-US/components/anchor/' }, + { text: 'BackTop', link: '/en-US/components/back-top/' }, + { text: 'Breadcrumb', link: '/en-US/components/breadcrumb/' }, + { text: 'Dropdown', link: '/en-US/components/dropdown/' }, + { text: 'NavSprite', link: '/en-US/components/nav-sprite/' }, + { text: 'Pagination', link: '/en-US/components/pagination/', status: 'progress' }, + { text: 'StepsGuide', link: '/en-US/components/steps-guide/' }, + { text: 'Tabs', link: '/en-US/components/tabs/', status: 'completed' }, + { text: 'Anchor', link: '/en-US/components/Anchor/' }, + ] + }, + { + text: 'Feedback', + children: [ + { text: 'Alert', link: '/components/alert/', status: 'completed' }, + { text: 'Drawer', link: '/components/drawer/' }, + { text: 'Loading', link: '/components/loading/', status: 'completed' }, + { text: 'Mention', link: '/components/mention/' }, + { text: 'Modal', link: '/components/modal/' }, + { text: 'Popover', link: '/components/popover/', status: "progress" }, + { text: 'ReadTip', link: '/components/read-tip/' }, + { text: 'Toast', link: '/components/toast/', status: 'completed' }, + { text: 'Tooltip', link: '/components/tooltip/', status: 'completed' }, + ] + }, + { + text: 'Data Entry', + children: [ + { text: 'AutoComplete', link: '/en-US/components/auto-complete/' }, + { text: 'Cascader', link: '/en-US/components/cascader/' }, + { text: 'CategorySearch', link: '/en-US/components/category-search/' }, + { text: 'Checkbox', link: '/en-US/components/checkbox/', status: 'completed' }, + { text: 'DatePicker', link: '/en-US/components/date-picker/', status: 'progress' }, + { text: 'DatePickerPro', link: '/en-US/components/date-picker-pro/' }, + { text: 'EditableSelect', link: '/en-US/components/editable-select/' }, + { text: 'Form', link: '/en-US/components/form/' }, + { text: 'Input', link: '/en-US/components/input/', status: 'completed' }, + { text: 'InputNumber', link: '/en-US/components/input-number/' }, + { text: 'MultiAutoComplete', link: '/en-US/components/multi-auto-complete/' }, + { text: 'Radio', link: '/en-US/components/radio/', status: 'completed' }, + { text: 'Select', link: '/en-US/components/select/', status: 'progress' }, + { text: 'Slider', link: '/en-US/components/slider/' }, + { text: 'Switch', link: '/en-US/components/switch/', status: 'completed' }, + { text: 'TagInput', link: '/en-US/components/tag-input/', status: 'completed' }, + { text: 'Textarea', link: '/en-US/components/textarea/' }, + { text: 'TimePicker', link: '/en-US/components/time-picker/' }, + { text: 'Transfer', link: '/en-US/components/transfer/' }, + { text: 'TreeSelect', link: '/en-US/components/tree-select/' }, + { text: 'Upload', link: '/en-US/components/upload/', status: 'progress' }, + ] + }, + { + text: 'Data Display', + children: [ + { text: 'Avatar', link: '/en-US/components/avatar/', status: 'completed' }, + { text: 'Badge', link: '/en-US/components/badge/', status: 'completed' }, + { text: 'Card', link: '/en-US/components/card/', status: 'completed' }, + { text: 'Carousel', link: '/en-US/components/carousel/', status: 'completed' }, + { text: 'DataTable', link: '/en-US/components/data-table/' }, + { text: 'Gantt', link: '/en-US/components/gantt/' }, + { text: 'ImagePreview', link: '/en-US/components/image-preview/' }, + { text: 'Progress', link: '/en-US/components/progress/', status: 'completed' }, + { text: 'QuadrantDiagram', link: '/en-US/components/quadrant-diagram/' }, + { text: 'Rate', link: '/en-US/components/rate/', status: 'completed' }, + { text: 'Tag', link: '/en-US/components/tag/' }, + { text: 'Tree', link: '/en-US/components/tree/' }, + ] + }, + { + text: 'Layout', + children: [ + { text: 'Layout', link: '/en-US/components/layout/' }, + { text: 'Splitter', link: '/en-US/components/splitter/' } + ] + }, + ] +} + +export default enSidebar + \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/head.ts b/packages/devui-vue/docs/.vitepress/config/head.ts new file mode 100644 index 0000000000000000000000000000000000000000..7791554758e86b1503c7cf8763ba7b96993ff731 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/head.ts @@ -0,0 +1,5 @@ +const head = [ + ['link', { rel: 'icon', type: 'image/svg+xml', href: '/assets/logo.svg' }], +] + +export default head \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/index.ts b/packages/devui-vue/docs/.vitepress/config/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..76ad29f0458d27bab3c8182fcc88bd245434ce72 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/index.ts @@ -0,0 +1,19 @@ +import sidebar from './sidebar' +import head from './head' +import nav from './nav' +import markdown from './markdown' +import lang from './lang' +const config = { + title: "Vue DevUI", + description: "Vue DevUI 组件库", + head, + markdown, + themeConfig: { + sidebar, + nav, + demoblock: lang, + logo: '../../assets/logo.svg' + }, +}; + +export default config; \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/lang.ts b/packages/devui-vue/docs/.vitepress/config/lang.ts new file mode 100644 index 0000000000000000000000000000000000000000..765aeb420777b38b236c71920dcc4f407ba567f8 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/lang.ts @@ -0,0 +1,14 @@ +const lang = { + '/zh': { + 'hide-text': '隐藏代码', + 'show-text': '显示代码', + 'copy-button-text': '复制代码片段' + }, + '/en': { + 'hide-text': 'Hide', + 'show-text': 'Expand', + 'copy-button-text': 'Copy' + } +} + +export default lang diff --git a/packages/devui-vue/docs/.vitepress/config/markdown.ts b/packages/devui-vue/docs/.vitepress/config/markdown.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f3376122499d8b072eaa205e23836db4c92f6fd --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/markdown.ts @@ -0,0 +1,7 @@ +const markdown = { + config: (md) => { + const { demoBlockPlugin } = require('vitepress-theme-demoblock') + md.use(demoBlockPlugin) + } +} +export default markdown diff --git a/packages/devui-vue/docs/.vitepress/config/nav.ts b/packages/devui-vue/docs/.vitepress/config/nav.ts new file mode 100644 index 0000000000000000000000000000000000000000..25c08b19632cfbb61c573155ca4cb26f1fda2a02 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/config/nav.ts @@ -0,0 +1,8 @@ +const nav = [ + { text: '设计规范', link: '/design' }, + { text: '组件', link: '/' }, + { text: '版本历程', link: '/version' }, + { text: '主题', link: '/theme' }, +] + +export default nav \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue b/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue new file mode 100644 index 0000000000000000000000000000000000000000..47ca81faae4f1cb7a970faee30f580f842a40be0 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue @@ -0,0 +1,196 @@ +<script setup lang="ts"> +import { ref, computed, watch, defineAsyncComponent } from 'vue' +import { useRoute, useData } from 'vitepress' +import { isSideBarEmpty, getSideBarConfig } from './support/sideBar' + +// components +import NavBar from './components/NavBar.vue' +import SideBar from './components/SideBar.vue' +import Page from './components/Page.vue' + +const Home = defineAsyncComponent(() => import('./components/Home.vue')) + +const NoopComponent = () => null + +const CarbonAds = __CARBON__ + ? defineAsyncComponent(() => import('./components/CarbonAds.vue')) + : NoopComponent +const BuySellAds = __BSA__ + ? defineAsyncComponent(() => import('./components/BuySellAds.vue')) + : NoopComponent +const AlgoliaSearchBox = __ALGOLIA__ + ? defineAsyncComponent(() => import('./components/AlgoliaSearchBox.vue')) + : NoopComponent + +// generic state +const route = useRoute() +const { site, page, theme, frontmatter } = useData() + +// custom layout +const isCustomLayout = computed(() => !!frontmatter.value.customLayout) +// home +const enableHome = computed(() => !!frontmatter.value.home) + +// automatic multilang check for AlgoliaSearchBox +const isMultiLang = computed( + () => Object.keys(theme.value.locales || {}).length > 0 +) + +// navbar +const showNavbar = computed(() => { + const themeConfig = theme.value + if (frontmatter.value.navbar === false || themeConfig.navbar === false) { + return false + } + return ( + site.value.title || themeConfig.logo || themeConfig.repo || themeConfig.nav + ) +}) + +// sidebar +const openSideBar = ref(false) + +const showSidebar = computed(() => { + if (frontmatter.value.home || frontmatter.value.sidebar === false) { + return false + } + + return !isSideBarEmpty( + getSideBarConfig(theme.value.sidebar, route.data.relativePath) + ) +}) + +const toggleSidebar = (to?: boolean) => { + openSideBar.value = typeof to === 'boolean' ? to : !openSideBar.value +} + +const hideSidebar = toggleSidebar.bind(null, false) +// close the sidebar when navigating to a different location +watch(route, hideSidebar) +// TODO: route only changes when the pathname changes +// listening to hashchange does nothing because it's prevented in router + +// page classes +const pageClasses = computed(() => { + return [ + { + 'no-navbar': !showNavbar.value, + 'sidebar-open': openSideBar.value, + 'no-sidebar': !showSidebar.value + } + ] +}) + +// layout组件加载,初始化国际化语言. +if (location.pathname.indexOf('-') >= 0){ + const result = location.pathname.match(/[a-zA-Z]*-[A-Z]*/) + localStorage.setItem('preferred_lang', result[0]) +}else { + localStorage.setItem('preferred_lang', navigator.language); +} +</script> + +<template> + <div class="theme" :class="pageClasses"> + <NavBar v-if="showNavbar" @toggle="toggleSidebar"> + <template #search> + <slot name="navbar-search"> + <AlgoliaSearchBox + v-if="theme.algolia" + :options="theme.algolia" + :multilang="isMultiLang" + :key="site.lang" + /> + </slot> + </template> + </NavBar> + + <SideBar :open="openSideBar"> + <template #sidebar-top> + <slot name="sidebar-top" /> + </template> + <template #sidebar-bottom> + <slot name="sidebar-bottom" /> + </template> + </SideBar> + <!-- TODO: make this button accessible --> + <div class="sidebar-mask" @click="toggleSidebar(false)" /> + + <Content v-if="isCustomLayout" /> + + <Home v-else-if="enableHome"> + <template #hero> + <slot name="home-hero" /> + </template> + <template #features> + <slot name="home-features" /> + </template> + <template #footer> + <slot name="home-footer" /> + </template> + </Home> + + <Page v-else> + <template #top> + <slot name="page-top-ads"> + <div + id="ads-container" + v-if="theme.carbonAds && theme.carbonAds.carbon" + > + <CarbonAds + :key="'carbon' + page.relativePath" + :code="theme.carbonAds.carbon" + :placement="theme.carbonAds.placement" + /> + </div> + </slot> + <slot name="page-top" /> + </template> + <template #bottom> + <slot name="page-bottom" /> + <slot name="page-bottom-ads"> + <BuySellAds + v-if="theme.carbonAds && theme.carbonAds.custom" + :key="'custom' + page.relativePath" + :code="theme.carbonAds.custom" + :placement="theme.carbonAds.placement" + /> + </slot> + </template> + </Page> + </div> + + <Debug v-if="false" /> +</template> + +<style> +#ads-container { + margin: 0 auto; +} + +@media (min-width: 420px) { + #ads-container { + position: relative; + right: 0; + float: right; + margin: -8px -8px 24px 24px; + width: 146px; + } +} + +@media (max-width: 420px) { + #ads-container { + /* Avoid layout shift */ + height: 105px; + margin: 1.75rem 0; + } +} + +@media (min-width: 1400px) { + #ads-container { + position: fixed; + right: 8px; + bottom: 8px; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/NotFound.vue b/packages/devui-vue/docs/.vitepress/devui-theme/NotFound.vue new file mode 100644 index 0000000000000000000000000000000000000000..9016e0e67cfc5f40a9e124e366f5b7b1ccc4f1e2 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/NotFound.vue @@ -0,0 +1,22 @@ +<template> + <div class="theme"> + <h1>404</h1> + <blockquote>{{ getMsg() }}</blockquote> + <a :href="site.base" aria-label="go to home">Take me home.</a> + </div> +</template> + +<script setup lang="ts"> +import { useData } from 'vitepress' +const { site } = useData() +const msgs = [ + `There's nothing here.`, + `How did we get here?`, + `That's a Four-Oh-Four.`, + `Looks like we've got some broken links.`, +] + +function getMsg() { + return msgs[Math.floor(Math.random() * msgs.length)] +} +</script> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/AlgoliaSearchBox.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/AlgoliaSearchBox.vue new file mode 100644 index 0000000000000000000000000000000000000000..89023a2eaea277d8fe5373a5354d6e02348dae05 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/AlgoliaSearchBox.vue @@ -0,0 +1,178 @@ +<script setup lang="ts"> +import '@docsearch/css' +import docsearch from '@docsearch/js' +import { useRoute, useRouter, useData } from 'vitepress' +import { getCurrentInstance, onMounted, watch } from 'vue' +import type { DefaultTheme } from '../config' +import type { DocSearchHit } from '@docsearch/react/dist/esm/types' + +const props = defineProps<{ + options: DefaultTheme.AlgoliaSearchOptions + multilang?: boolean +}>() + +const vm = getCurrentInstance() +const route = useRoute() +const router = useRouter() + +watch( + () => props.options, + (value) => { + update(value) + } +) + +onMounted(() => { + initialize(props.options) +}) + +function isSpecialClick(event: MouseEvent) { + return ( + event.button === 1 || + event.altKey || + event.ctrlKey || + event.metaKey || + event.shiftKey + ) +} + +function getRelativePath(absoluteUrl: string) { + const { pathname, hash } = new URL(absoluteUrl) + + return pathname + hash +} + +function update(options: any) { + if (vm && vm.vnode.el) { + vm.vnode.el.innerHTML = + '<div class="algolia-search-box" id="docsearch"></div>' + initialize(options) + } +} + +const { lang } = useData() + +function initialize(userOptions: any) { + // if the user has multiple locales, the search results should be filtered + // based on the language + const facetFilters = props.multilang ? ['language:' + lang.value] : [] + + docsearch( + Object.assign({}, userOptions, { + container: '#docsearch', + + searchParameters: Object.assign({}, userOptions.searchParameters, { + // pass a custom lang facetFilter to allow multiple language search + // https://github.com/algolia/docsearch-configs/pull/3942 + facetFilters: facetFilters.concat( + userOptions.searchParameters?.facetFilters || [] + ) + }), + + navigator: { + navigate: ({ suggestionUrl }: { suggestionUrl: string }) => { + const { pathname: hitPathname } = new URL( + window.location.origin + suggestionUrl + ) + + // Router doesn't handle same-page navigation so we use the native + // browser location API for anchor navigation + if (route.path === hitPathname) { + window.location.assign(window.location.origin + suggestionUrl) + } else { + router.go(suggestionUrl) + } + } + }, + + transformItems: (items: DocSearchHit[]) => { + return items.map((item) => { + return Object.assign({}, item, { + url: getRelativePath(item.url) + }) + }) + }, + + hitComponent: ({ + hit, + children + }: { + hit: DocSearchHit + children: any + }) => { + const relativeHit = hit.url.startsWith('http') + ? getRelativePath(hit.url as string) + : hit.url + + return { + type: 'a', + ref: undefined, + constructor: undefined, + key: undefined, + props: { + href: hit.url, + onClick: (event: MouseEvent) => { + if (isSpecialClick(event)) { + return + } + + // we rely on the native link scrolling when user is already on + // the right anchor because Router doesn't support duplicated + // history entries + if (route.path === relativeHit) { + return + } + + // if the hits goes to another page, we prevent the native link + // behavior to leverage the Router loading feature + if (route.path !== relativeHit) { + event.preventDefault() + } + + router.go(relativeHit) + }, + children + } + } + } + }) + ) +} +</script> + +<template> + <div class="algolia-search-box" id="docsearch" /> +</template> + +<style> +.algolia-search-box { + padding-top: 1px; +} + +@media (min-width: 720px) { + .algolia-search-box { + padding-left: 8px; + } +} + +@media (min-width: 751px) { + .algolia-search-box { + min-width: 176.3px; /* avoid layout shift */ + } + + .algolia-search-box .DocSearch-Button-Placeholder { + padding-left: 8px; + font-size: 0.9rem; + font-weight: 500; + } +} + +.DocSearch { + --docsearch-primary-color: var(--c-brand); + --docsearch-highlight-color: var(--docsearch-primary-color); + --docsearch-searchbox-shadow: inset 0 0 0 2px var(--docsearch-primary-color); + --docsearch-text-color: var(--c-text-light); + --docsearch-muted-color: var(--c-text-lighter); + --docsearch-searchbox-background: #f2f2f2; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue new file mode 100644 index 0000000000000000000000000000000000000000..77ad149f2adc20316f84c9ea9237fe04a1e44373 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue @@ -0,0 +1,102 @@ +<template> + <transition name="fade"> + <svg + v-if="show" + class="go-to-top" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 49.484 28.284" + @click="scrollToTop" + > + <g transform="translate(-229 -126.358)"> + <rect + fill="currentColor" + width="35" + height="5" + rx="2" + transform="translate(229 151.107) rotate(-45)" + /> + <rect + fill="currentColor" + width="35" + height="5" + rx="2" + transform="translate(274.949 154.642) rotate(-135)" + /> + </g> + </svg> + </transition> +</template> + +<script lang="ts"> +import { debounce } from 'lodash-es' +import { defineComponent, onMounted, computed, ref } from 'vue' +export default defineComponent({ + name: 'BackToTop', + props: { + threshold: { + type: Number, + default: 300, + }, + }, + setup(props) { + const scrollTop = ref<number | null>(null) + const show = computed(() => { + return scrollTop.value! > props.threshold + }) + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }) + scrollTop.value = 0 + } + const getScrollTop = () => { + return ( + window.pageYOffset || + document.documentElement.scrollTop || + document.body.scrollTop || + 0 + ) + } + onMounted(() => { + scrollTop.value = getScrollTop() + window.addEventListener( + 'scroll', + debounce(() => { + scrollTop.value = getScrollTop() + }, 100) + ) + }) + + return { + show, + scrollToTop, + } + }, +}) +</script> + +<style lang="scss" scoped> +.go-to-top { + cursor: pointer; + position: fixed; + bottom: 2rem; + right: 2.5rem; + width: 2rem; + color: var(--devui-brand); + z-index: 1; +} +.go-to-top:hover { + color: var(--devui-brand-hover); +} +@media (max-width: 959px) { + .go-to-top { + display: none; + } +} +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.3s; +} +.fade-enter, +.fade-leave-to { + opacity: 0; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/BuySellAds.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/BuySellAds.vue new file mode 100644 index 0000000000000000000000000000000000000000..60e1a692301c93b676757d10e7c90269198a111f --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/BuySellAds.vue @@ -0,0 +1,148 @@ +<script setup lang="ts"> +import { onMounted } from 'vue' + +// global _bsa +const ID = 'bsa-cpc-script' + +declare global { + var _bsa: BSA | undefined + + interface BSA { + init( + name: string, + code: string, + placement: string, + options: { + target: string + align: string + disable_css?: 'true' | 'false' + } + ): void + } +} + +const { code, placement } = defineProps<{ + code: string + placement: string +}>() + +onMounted(() => { + if (!document.getElementById(ID)) { + const s = document.createElement('script') + + s.id = ID + s.src = '//m.servedby-buysellads.com/monetization.js' + + document.head.appendChild(s) + + s.onload = () => { + load() + } + } else { + load() + } +}) + +function load() { + if (typeof _bsa !== 'undefined' && _bsa) { + _bsa.init('default', code, `placement:${placement}`, { + target: '.bsa-cpc', + align: 'horizontal', + disable_css: 'true' + }) + } +} +</script> + +<template> + <div class="buy-sell-ads"> + <div class="bsa-cpc" /> + </div> +</template> + +<style scoped> +.buy-sell-ads { + margin: 0 auto; + padding-top: 2rem; + font-size: 0.85rem; +} + +.bsa-cpc { + border-radius: 6px; + background-color: var(--c-bg-accent); +} + +.bsa-cpc ::v-deep(a._default_) { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + margin-bottom: 20px; + padding: 12px; + text-decoration: none; + line-height: 1.4; + font-weight: 400; + color: var(--c-text-light); +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(a._default_) { + flex-wrap: nowrap; + } +} + +.bsa-cpc ::v-deep(.default-ad) { + display: none; +} + +.bsa-cpc ::v-deep(a._default_ .default-image) { + flex-shrink: 0; + margin-right: 12px; + width: 24px; +} + +.bsa-cpc ::v-deep(a._default_ .default-image img) { + border-radius: 4px; + height: 24px; + vertical-align: middle; +} + +.bsa-cpc ::v-deep(._default_::after) { + border: 1px solid #1c90f3; + border-radius: 4px; + margin-top: 8px; + margin-left: 36px; + padding: 0 8px; + line-height: 22px; + font-size: 0.85em; + font-weight: 500; + color: #1c90f3; + content: 'Sponsored'; +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(._default_::after) { + margin-top: 0px; + margin-left: 12px; + } +} + +.bsa-cpc ::v-deep(.default-text) { + flex-grow: 1; + align-self: center; + width: calc(100% - 36px); +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(.default-text) { + width: auto; + } +} + +.bsa-cpc ::v-deep(.default-title) { + font-weight: 600; +} + +.bsa-cpc ::v-deep(.default-description) { + padding-left: 8px; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/CarbonAds.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/CarbonAds.vue new file mode 100644 index 0000000000000000000000000000000000000000..09a39bddb0373626e5a9e746a5cdf819fbeba96e --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/CarbonAds.vue @@ -0,0 +1,99 @@ +<script setup lang="ts"> +import { ref, onMounted } from 'vue' + +const { code, placement } = defineProps<{ + code: string + placement: string +}>() + +const el = ref() + +onMounted(() => { + const s = document.createElement('script') + s.id = '_carbonads_js' + s.src = `//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}` + el.value.appendChild(s) +}) +</script> + +<template> + <div class="carbon-ads" ref="el" /> +</template> + +<style scoped> +.carbon-ads { + border-radius: 4px; + margin: 0 auto; + max-width: 280px; + font-size: 0.75rem; + background-color: var(--c-bg-accent); + min-height: 105.38px; /* avoid layout shift on mobile */ +} + +.carbon-ads::after { + clear: both; + display: block; + content: ''; +} + +@media (min-width: 420px) { + .carbon-ads { + z-index: 1; + float: right; + margin: -8px -8px 24px 24px; + padding: 8px; + width: 146px; + max-width: 100%; + min-height: 200px; + } +} + +@media (min-width: 1400px) { + .carbon-ads { + right: 8px; + float: none; + margin: 0; + } +} + +.carbon-ads :deep(.carbon-img) { + float: left; + margin-right: 0.75rem; + max-width: 110px; + border: 1px solid var(--c-divider); +} + +@media (min-width: 420px) { + .carbon-ads :deep(.carbon-img) { + float: none; + display: block; + margin-right: 0; + max-width: 130px; + } +} + +.carbon-ads :deep(.carbon-img img) { + display: block; + width: 100%; + height: auto; +} + +@media (min-width: 420px) { + .carbon-ads :deep(.carbon-text) { + padding-top: 8px; + } +} + +.carbon-ads :deep(.carbon-text) { + display: block; + font-weight: 400; + color: var(--c-text-light); +} + +.carbon-ads :deep(.carbon-poweredby) { + display: block; + padding-top: 2px; + font-weight: 400; + color: var(--c-text-lighter); +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/EditLink.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/EditLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..ffdab5ea9f5ee471008c36be198ee5909b8ac707 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/EditLink.vue @@ -0,0 +1,38 @@ +<script setup lang="ts"> +import { useEditLink } from '../composables/editLink' +import OutboundLink from './icons/OutboundLink.vue' + +const { url, text } = useEditLink() +</script> + +<template> + <div class="edit-link"> + <a + v-if="url" + class="link" + :href="url" + target="_blank" + rel="noopener noreferrer" + > + {{ text }} <OutboundLink class="icon" /> + </a> + </div> +</template> + +<style scoped> +.link { + display: inline-block; + font-size: 1rem; + font-weight: 500; + color: var(--c-text-light); +} + +.link:hover { + text-decoration: none; + color: var(--c-brand); +} + +.icon { + margin-left: 4px; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/Home.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/Home.vue new file mode 100644 index 0000000000000000000000000000000000000000..f9ba63ddd03155e00084b0f3fed55bb34b57c170 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/Home.vue @@ -0,0 +1,38 @@ +<script setup lang="ts"> +import HomeHero from './HomeHero.vue' +import HomeFeatures from './HomeFeatures.vue' +import HomeFooter from './HomeFooter.vue' +</script> + +<template> + <main class="home" aria-labelledby="main-title"> + <HomeHero /> + <slot name="hero" /> + <HomeFeatures /> + <div class="home-content"> + <Content /> + </div> + <slot name="features" /> + <HomeFooter /> + <slot name="footer" /> + </main> +</template> + +<style scoped> +.home { + padding-top: var(--header-height); +} + +.home-content { + max-width: 960px; + margin: 0px auto; + padding: 0 1.5rem; +} + +@media (max-width: 720px) { + .home-content { + max-width: 392px; + padding: 0; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFeatures.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFeatures.vue new file mode 100644 index 0000000000000000000000000000000000000000..c435248ea7ee32223788aab7708cb26737ac7639 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFeatures.vue @@ -0,0 +1,143 @@ +<script setup lang="ts"> +import { computed } from 'vue' +import { useData } from 'vitepress' + +const { frontmatter } = useData() + +const hasFeatures = computed(() => { + return frontmatter.value.features && frontmatter.value.features.length > 0 +}) + +interface Feature { + title?: string + details?: string +} + +const features = computed<Feature[]>(() => { + return frontmatter.value.features ? frontmatter.value.features : [] +}) +</script> + +<template> + <div v-if="hasFeatures" class="home-features"> + <div class="wrapper"> + <div class="container"> + <div class="features"> + <section + v-for="(feature, index) in features" + :key="index" + class="feature" + > + <h2 class="title" v-if="feature.title">{{ feature.title }}</h2> + <p class="details" v-if="feature.details">{{ feature.details }}</p> + </section> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +.home-features { + margin: 0 auto; + padding: 2.5rem 0 2.75rem; + max-width: 960px; +} + +.home-hero + .home-features { + padding-top: 0; +} + +@media (min-width: 420px) { + .home-features { + padding: 3.25rem 0 3.5rem; + } + + .home-hero + .home-features { + padding-top: 0; + } +} + +@media (min-width: 720px) { + .home-features { + padding-right: 1.5rem; + padding-left: 1.5rem; + } +} + +.wrapper { + padding: 0 1.5rem; +} + +.home-hero + .home-features .wrapper { + border-top: 1px solid var(--c-divider); + padding-top: 2.5rem; +} + +@media (min-width: 420px) { + .home-hero + .home-features .wrapper { + padding-top: 3.25rem; + } +} + +@media (min-width: 720px) { + .wrapper { + padding-right: 0; + padding-left: 0; + } +} + +.container { + margin: 0 auto; + max-width: 392px; +} + +@media (min-width: 720px) { + .container { + max-width: 960px; + } +} + +.features { + display: flex; + flex-wrap: wrap; + margin: -20px -24px; +} + +.feature { + flex-shrink: 0; + padding: 20px 24px; + width: 100%; +} + +@media (min-width: 720px) { + .feature { + width: calc(100% / 3); + } +} + +.title { + margin: 0; + border-bottom: 0; + line-height: 1.4; + font-size: 1.25rem; + font-weight: 500; +} + +@media (min-width: 420px) { + .title { + font-size: 1.4rem; + } +} + +.details { + margin: 0; + line-height: 1.6; + font-size: 1rem; + color: var(--c-text-light); +} + +.title + .details { + padding-top: 0.25rem; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFooter.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFooter.vue new file mode 100644 index 0000000000000000000000000000000000000000..55f27af4c785e2ade5a9d85bef9172781937dd56 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeFooter.vue @@ -0,0 +1,50 @@ +<script setup lang="ts"> +import { useData } from 'vitepress' + +const { frontmatter } = useData() +</script> + +<template> + <footer v-if="frontmatter.footer" class="footer"> + <div class="container"> + <p class="text">{{ frontmatter.footer }}</p> + </div> + </footer> +</template> + +<style scoped> +.footer { + margin: 0 auto; + max-width: 960px; +} + +@media (min-width: 720px) { + .footer { + padding: 0 1.5rem; + } +} + +.container { + padding: 2rem 1.5rem 2.25rem; +} + +.home-hero + .footer .container, +.home-features + .footer .container, +.home-content + .footer .container { + border-top: 1px solid var(--c-divider); +} + +@media (min-width: 420px) { + .container { + padding: 3rem 1.5rem 3.25rem; + } +} + +.text { + margin: 0; + text-align: center; + line-height: 1.4; + font-size: 0.9rem; + color: var(--c-text-light); +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeHero.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeHero.vue new file mode 100644 index 0000000000000000000000000000000000000000..9ff14a759cabfb810407358af910d756afdaabeb --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/HomeHero.vue @@ -0,0 +1,165 @@ +<script setup lang="ts"> +import { computed } from 'vue' +import { useData, withBase } from 'vitepress' +import NavLink from './NavLink.vue' + +const { site, frontmatter } = useData() + +const showHero = computed(() => { + const { + heroImage, + heroText, + tagline, + actionLink, + actionText + } = frontmatter.value + return heroImage || heroText || tagline || (actionLink && actionText) +}) + +const heroText = computed(() => frontmatter.value.heroText || site.value.title) +</script> + +<template> + <header v-if="showHero" class="home-hero"> + <figure v-if="frontmatter.heroImage" class="figure"> + <img + class="image" + :src="withBase(frontmatter.heroImage)" + :alt="frontmatter.heroAlt" + /> + </figure> + + <h1 v-if="heroText" id="main-title" class="title">{{ heroText }}</h1> + <p v-if="frontmatter.tagline" class="description"> + {{ frontmatter.tagline }} + </p> + + <NavLink + v-if="frontmatter.actionLink && frontmatter.actionText" + :item="{ link: frontmatter.actionLink, text: frontmatter.actionText }" + class="action" + /> + + <NavLink + v-if="frontmatter.altActionLink && frontmatter.altActionText" + :item="{ + link: frontmatter.altActionLink, + text: frontmatter.altActionText + }" + class="action alt" + /> + </header> +</template> + +<style scoped> +.home-hero { + margin: 2.5rem 0 2.75rem; + padding: 0 1.5rem; + text-align: center; +} + +@media (min-width: 420px) { + .home-hero { + margin: 3.5rem 0; + } +} + +@media (min-width: 720px) { + .home-hero { + margin: 4rem 0 4.25rem; + } +} + +.figure { + padding: 0 1.5rem; +} + +.image { + display: block; + margin: 0 auto; + width: auto; + max-width: 100%; + max-height: 280px; +} + +.title { + margin-top: 1.5rem; + font-size: 2rem; +} + +@media (min-width: 420px) { + .title { + font-size: 3rem; + } +} + +@media (min-width: 720px) { + .title { + margin-top: 2rem; + } +} + +.description { + margin: 0; + margin-top: 0.25rem; + line-height: 1.3; + font-size: 1.2rem; + color: var(--c-text-light); +} + +@media (min-width: 420px) { + .description { + line-height: 1.2; + font-size: 1.6rem; + } +} + +.action { + margin-top: 1.5rem; + display: inline-block; +} + +.action.alt { + margin-left: 1.5rem; +} + +@media (min-width: 420px) { + .action { + margin-top: 2rem; + display: inline-block; + } +} + +.action :deep(.item) { + display: inline-block; + border-radius: 6px; + padding: 0 20px; + line-height: 44px; + font-size: 1rem; + font-weight: 500; + color: var(--c-bg); + background-color: var(--c-brand); + border: 2px solid var(--c-brand); + transition: background-color 0.1s ease; +} + +.action.alt :deep(.item) { + background-color: var(--c-bg); + color: var(--c-brand); +} + +.action :deep(.item:hover) { + text-decoration: none; + color: var(--c-bg); + background-color: var(--c-brand-light); +} + +@media (min-width: 420px) { + .action :deep(.item) { + padding: 0 24px; + line-height: 52px; + font-size: 1.2rem; + font-weight: 500; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/LastUpdated.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/LastUpdated.vue new file mode 100644 index 0000000000000000000000000000000000000000..ab888fbc222e5dba6b60fcab08972fe29c61b5fc --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/LastUpdated.vue @@ -0,0 +1,58 @@ +<script setup lang="ts"> +import { ref, computed, onMounted } from 'vue' +import { useData } from 'vitepress' + +const { theme, page } = useData() + +const hasLastUpdated = computed(() => { + const lu = theme.value.lastUpdated + + return lu !== undefined && lu !== false +}) + +const prefix = computed(() => { + const p = theme.value.lastUpdated + return p === true ? 'Last Updated' : p +}) + +const datetime = ref('') +onMounted(() => { + // locale string might be different based on end user + // and will lead to potential hydration mismatch if calculated at build time + datetime.value = new Date(page.value.lastUpdated).toLocaleString('en-US') +}) +</script> + +<template> + <p v-if="hasLastUpdated" class="last-updated"> + <span class="prefix">{{ prefix }}:</span> + <span class="datetime">{{ datetime }}</span> + </p> +</template> + +<style scoped> +.last-updated { + display: inline-block; + margin: 0; + line-height: 1.4; + font-size: 0.9rem; + color: var(--c-text-light); +} + +@media (min-width: 960px) { + .last-updated { + font-size: 1rem; + } +} + +.prefix { + display: inline-block; + font-weight: 500; +} + +.datetime { + display: inline-block; + margin-left: 6px; + font-weight: 400; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue new file mode 100644 index 0000000000000000000000000000000000000000..a1fc72290c4fe3620b4305260ccacf2df4a1cb9f --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue @@ -0,0 +1,99 @@ +<script setup lang="ts"> +import { ref, watch } from 'vue' +import Theme from '@devui/theme/theme' +import { Switch as DSwitch } from '@devui/switch' +import NavBarTitle from './NavBarTitle.vue' +import NavLinks from './NavLinks.vue' +import ToggleSideBarButton from './ToggleSideBarButton.vue' + +const theme = new Theme("light"); + +const darkMode = ref(false); +const switchText = ref("浅色"); + +const defaultLanguage = ref(localStorage.getItem('preferred_lang')) +function useTranslation (target){ + defaultLanguage.value = target + localStorage.setItem('preferred_lang', target) + if (target === 'en-US'){ + location.pathname = `/en-US${location.pathname}` + }else if (target === 'zh-CN'){ + location.pathname = `${location.pathname.split('/en-US')[1]}` + } +} + +watch( + () => darkMode.value, + (darkMode, prevDarkMode) => { + theme.applyTheme(darkMode ? 'dark' : 'light') + switchText.value = darkMode ? '深色' : '浅色' + } +) + + +defineEmits(['toggle']) +</script> + +<template> + <header class="nav-bar"> + <ToggleSideBarButton @toggle="$emit('toggle')" /> + + <NavBarTitle /> + + <div class="flex-grow" /> + + <div class="flex items-center"> + <div class="nav"> + <NavLinks /> + </div> + + <div class="flex items-center ml-xs mt-xxs"> + <d-switch v-model:checked="darkMode" size="sm"></d-switch> + <span style="font-size:0.9rem;" class="mb-xxs">{{ switchText }}</span> + </div> + <div style="margin-left: 10px" @click="() => useTranslation( defaultLanguage === 'zh-CN' ? 'en-US' : 'zh-CN' )"> + {{defaultLanguage === 'zh-CN' ? '中文' : 'English'}} + </div> + </div> + + <slot name="search" /> + </header> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; + +.nav-bar { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: var(--z-index-navbar); + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid $devui-dividing-line; + padding: 0.7rem 1.5rem 0.7rem 4rem; + height: var(--header-height); + background-color: $devui-base-bg; + &:hover { + cursor: pointer; + } +} + +@media (min-width: 720px) { + .nav-bar { + padding: 0.7rem 1.5rem; + } +} + +.nav { + display: none; +} + +@media (min-width: 720px) { + .nav { + display: block; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue new file mode 100644 index 0000000000000000000000000000000000000000..4c54558a1a6253da09f3f4d4d4ff6d3b122ad53a --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue @@ -0,0 +1,40 @@ +<script setup lang="ts"> +import { withBase, useData } from 'vitepress' +const { site, theme, localePath } = useData() +</script> + +<template> + <a + class="nav-bar-title" + :href="localePath" + :aria-label="`${site.title}, back to home`" + > + <img + v-if="theme.logo" + class="logo" + :src="withBase(theme.logo)" + alt="Logo" + /> + {{ site.title }} + </a> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; + +.nav-bar-title { + font-size: 1.3rem; + font-weight: 600; + color: $devui-text; +} + +.nav-bar-title:hover { + text-decoration: none; +} + +.logo { + margin-right: 0.75rem; + height: 1.3rem; + vertical-align: bottom; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLink.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..eb1001fd4e2951a50eaba468587113be3865370d --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLink.vue @@ -0,0 +1,135 @@ +<script setup lang="ts"> +import { ref, watch } from 'vue' +import { useRoute } from 'vitepress' +import type { DefaultTheme } from '../config' +import NavDropdownLinkItem from './NavDropdownLinkItem.vue' + +defineProps<{ + item: DefaultTheme.NavItemWithChildren +}>() + +const route = useRoute() + +const open = ref(false) + +watch( + () => route.path, + () => { + open.value = false + } +) + +function toggle() { + open.value = !open.value +} +</script> + +<template> + <div class="nav-dropdown-link" :class="{ open }"> + <button class="button" :aria-label="item.ariaLabel" @click="toggle"> + <span class="button-text">{{ item.text }}</span> + <span class="button-arrow" :class="open ? 'down' : 'right'" /> + </button> + + <ul class="dialog"> + <li v-for="item in item.items" :key="item.text" class="dialog-item"> + <NavDropdownLinkItem :item="item" /> + </li> + </ul> + </div> +</template> + +<style scoped> +.nav-dropdown-link { + position: relative; + height: 36px; + overflow: hidden; + cursor: pointer; +} + +@media (min-width: 720px) { + .nav-dropdown-link { + height: auto; + overflow: visible; + } + + .nav-dropdown-link:hover .dialog { + display: block; + } +} + +.nav-dropdown-link.open { + height: auto; +} + +.button { + display: block; + border: 0; + padding: 0 1.5rem; + width: 100%; + text-align: left; + line-height: 36px; + font-family: var(--font-family-base); + font-size: 1rem; + font-weight: 600; + color: var(--c-text); + white-space: nowrap; + background-color: transparent; + cursor: pointer; +} + +.button:focus { + outline: 0; +} + +@media (min-width: 720px) { + .button { + border-bottom: 2px solid transparent; + padding: 0; + line-height: 24px; + font-size: 0.9rem; + font-weight: 500; + } +} + +.button-arrow { + display: inline-block; + margin-top: -1px; + margin-left: 8px; + border-top: 6px solid #ccc; + border-right: 4px solid transparent; + border-bottom: 0; + border-left: 4px solid transparent; + vertical-align: middle; +} + +.button-arrow.right { + transform: rotate(-90deg); +} + +@media (min-width: 720px) { + .button-arrow.right { + transform: rotate(0); + } +} + +.dialog { + margin: 0; + padding: 0; + list-style: none; +} + +@media (min-width: 720px) { + .dialog { + display: none; + position: absolute; + top: 26px; + right: -8px; + border-radius: 6px; + padding: 12px 0; + min-width: 128px; + background-color: var(--c-bg); + box-shadow: var(--shadow-3); + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLinkItem.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLinkItem.vue new file mode 100644 index 0000000000000000000000000000000000000000..36a8ba03d63225d9cb89dbc7770ccae833d82fc9 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavDropdownLinkItem.vue @@ -0,0 +1,78 @@ +<script setup lang="ts"> +import { toRefs } from 'vue' +import type { DefaultTheme } from '../config' +import { useNavLink } from '../composables/navLink' +import OutboundLink from './icons/OutboundLink.vue' + +const props = defineProps<{ + item: DefaultTheme.NavItemWithLink +}>() + +const propsRefs = toRefs(props) + +const { props: linkProps, isExternal } = useNavLink(propsRefs.item) +</script> + +<template> + <div class="nav-dropdown-link-item"> + <a class="item" v-bind="linkProps"> + <span class="arrow" /> + <span class="text">{{ item.text }}</span> + <span class="icon"><OutboundLink v-if="isExternal" /></span> + </a> + </div> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; + +.item { + display: block; + padding: 0 1.5rem 0 2.5rem; + line-height: 32px; + font-size: 0.9rem; + font-weight: 500; + color: $devui-text; + white-space: nowrap; +} + +@media (min-width: 720px) { + .item { + padding: 0 24px 0 12px; + line-height: 32px; + font-size: 0.85rem; + font-weight: 500; + color: $devui-text; + white-space: nowrap; + } + + .item.active .arrow { + opacity: 1; + } +} + +.item:hover, +.item.active { + text-decoration: none; + color: $devui-brand; +} + +.item.external:hover { + border-bottom-color: transparent; + color: $devui-text; +} + +@media (min-width: 720px) { + .arrow { + display: inline-block; + margin-right: 8px; + border-top: 6px solid #ccc; + border-right: 4px solid transparent; + border-bottom: 0; + border-left: 4px solid transparent; + vertical-align: middle; + opacity: 0; + transform: translateY(-2px) rotate(-90deg); + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLink.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..734fa3309d3f268424476499c58cef61332cd052 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLink.vue @@ -0,0 +1,63 @@ +<script setup lang="ts"> +import { toRefs } from 'vue' +import type { DefaultTheme } from '../config' +import { useNavLink } from '../composables/navLink' +import OutboundLink from './icons/OutboundLink.vue' + +const props = defineProps<{ + item: DefaultTheme.NavItemWithLink +}>() + +const propsRefs = toRefs(props) + +const { props: linkProps, isExternal } = useNavLink(propsRefs.item) +</script> + +<template> + <div class="nav-link"> + <a class="item" v-bind="linkProps"> + {{ item.text }} <OutboundLink v-if="isExternal" /> + </a> + </div> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; + +.item { + display: block; + padding: 0 1.5rem; + line-height: 36px; + font-size: 1rem; + font-weight: 600; + color: $devui-text; + white-space: nowrap; +} + +.item:hover, +.item.active { + text-decoration: none; + color: $devui-brand; +} + +.item.external:hover { + border-bottom-color: transparent; + color: $devui-text; +} + +@media (min-width: 720px) { + .item { + border-bottom: 2px solid transparent; + padding: 0; + line-height: 24px; + font-size: 0.9rem; + font-weight: 500; + } + + .item:hover, + .item.active { + border-bottom-color: $devui-brand; + color: $devui-text; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLinks.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLinks.vue new file mode 100644 index 0000000000000000000000000000000000000000..d341e9adb5924a23ba8a7bccb2c58bd549bff575 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavLinks.vue @@ -0,0 +1,55 @@ +<script setup lang="ts"> +import { computed } from 'vue' +import { useData } from 'vitepress' +import { useLocaleLinks } from '../composables/nav' +import { useRepo } from '../composables/repo' +import NavLink from './NavLink.vue' +import NavDropdownLink from './NavDropdownLink.vue' +import enNav from '../../config/enNav' + +const { theme } = useData() +const localeLinks = useLocaleLinks() +const repo = useRepo() +const show = computed(() => theme.value.nav || repo.value || localeLinks.value) +let translationTheme = computed( () => localStorage.getItem('preferred_lang') === 'zh-CN' ? theme.value.nav : enNav ) +</script> + +<template> + <nav v-if="show" class="nav-links"> + <template v-if="translationTheme"> + <!-- <div v-for="item in theme.nav" :key="item.text" class="item"> --> + <div v-for="item in translationTheme" :key="item.text" class="item"> + <NavDropdownLink v-if="item.items" :item="item" /> + <NavLink v-else :item="item" /> + </div> + </template> + + <div v-if="localeLinks" class="item"> + <NavDropdownLink :item="localeLinks" /> + </div> + + <div v-if="repo" class="item"> + <NavLink :item="repo" /> + </div> + </nav> +</template> + +<style scoped> +.nav-links { + padding: 0.75rem 0; + border-bottom: 1px solid var(--c-divider); +} + +@media (min-width: 720px) { + .nav-links { + display: flex; + padding: 3px 0 0; + align-items: center; + border-bottom: 0; + } + + .item + .item { + padding-left: 24px; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NextAndPrevLinks.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NextAndPrevLinks.vue new file mode 100644 index 0000000000000000000000000000000000000000..e826aca45fad7b8730abb224dba41935cf74bd7f --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NextAndPrevLinks.vue @@ -0,0 +1,88 @@ +<script setup lang="ts"> +import { withBase } from 'vitepress' +import { useNextAndPrevLinks } from '../composables/nextAndPrevLinks' +import ArrowLeft from './icons/ArrowLeft.vue' +import ArrowRight from './icons/ArrowRight.vue' + +const { hasLinks, prev, next } = useNextAndPrevLinks() +</script> + +<template> + <div v-if="hasLinks" class="next-and-prev-link"> + <div class="container"> + <div class="prev"> + <a v-if="prev" class="link" :href="withBase(prev.link)"> + <ArrowLeft class="icon icon-prev" /> + <span class="text">{{ prev.text }}</span> + </a> + </div> + <div class="next"> + <a v-if="next" class="link" :href="withBase(next.link)"> + <span class="text">{{ next.text }}</span> + <ArrowRight class="icon icon-next" /> + </a> + </div> + </div> + </div> +</template> + +<style scoped> +.next-and-prev-link { + padding-top: 1rem; +} + +.container { + display: flex; + justify-content: space-between; + border-top: 1px solid var(--c-divider); + padding-top: 1rem; +} + +.prev, +.next { + display: flex; + flex-shrink: 0; + width: 50%; +} + +.prev { + justify-content: flex-start; + padding-right: 12px; +} + +.next { + justify-content: flex-end; + padding-left: 12px; +} + +.link { + display: inline-flex; + align-items: center; + max-width: 100%; + font-size: 1rem; + font-weight: 500; +} + +.text { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.icon { + display: block; + flex-shrink: 0; + width: 16px; + height: 16px; + fill: var(--c-text); + transform: translateY(1px); +} + +.icon-prev { + margin-right: 8px; +} +.icon-next { + margin-left: 8px; +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/Page.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/Page.vue new file mode 100644 index 0000000000000000000000000000000000000000..3051cb1784189c621c3bc95cf87898e3140b0a3e --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/Page.vue @@ -0,0 +1,62 @@ +<script setup lang="ts"> +import { computed } from 'vue' +import { useRoute } from 'vitepress' +import PageFooter from "./PageFooter.vue" +import NextAndPrevLinks from "./NextAndPrevLinks.vue" +import PageToc from "./PageToc.vue" +import BackToTop from './BackToTop.vue' +const isComponents = computed(() => useRoute().path.indexOf('components') > -1) + +</script> + +<template> + <main class="page"> + <div class="container"> + <slot name="top" /> + + <Content class="content" /> + <PageFooter /> + <NextAndPrevLinks /> + + <slot name="bottom" /> + <BackToTop /> + <PageToc v-if="isComponents" class="toc-warpper" /> + </div> + </main> +</template> + +<style scoped> +.page { + padding-top: var(--header-height); +} + +@media (min-width: 720px) { + .page { + margin-left: 16.4rem; + margin-right: 40px; + } +} + +@media (min-width: 960px) { + .page { + margin-left: 20rem; + } +} + +.container { + margin: 0 auto; + padding: 0 1.5rem 4rem; + max-width: 48rem; +} + +.content { + padding-bottom: 1.5rem; +} + +@media (max-width: 420px) { + .content { + /* fix carbon ads display */ + clear: both; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/PageFooter.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageFooter.vue new file mode 100644 index 0000000000000000000000000000000000000000..41e1dded014f74b04e06fe2c5dc9c5675d7ca5d6 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageFooter.vue @@ -0,0 +1,41 @@ +<script setup lang="ts"> +import EditLink from './EditLink.vue' +import LastUpdated from './LastUpdated.vue' +</script> + +<template> + <footer class="page-footer"> + <div class="edit"> + <EditLink /> + </div> + <div class="updated"> + <LastUpdated /> + </div> + </footer> +</template> + +<style scoped> +.page-footer { + padding-top: 1rem; + padding-bottom: 1rem; + overflow: auto; +} + +@media (min-width: 960px) { + .page-footer { + display: flex; + justify-content: space-between; + align-items: center; + } +} + +.updated { + padding-top: 4px; +} + +@media (min-width: 960px) { + .updated { + padding-top: 0; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/PageToc.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageToc.vue new file mode 100644 index 0000000000000000000000000000000000000000..ecd6c29a7224997545cc58de04ca5650fd35e086 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageToc.vue @@ -0,0 +1,115 @@ +<script setup lang="ts"> +import { ref, computed } from 'vue' +import { useToc } from '../composables/useToc' +import { useActiveSidebarLinks } from '../composables/activeBar' + +const headers = useToc() +const marker = ref() +const container = ref() +// 滚动监听 +useActiveSidebarLinks(container, marker) +</script> + +<template> + <aside ref="container"> + <nav class="devui-content-nav"> + <h3 class="devui-fast-forward">快速前往</h3> + <ul class="devui-step-nav"> + <li + v-for="{ link, text } in headers" + :key="link" + class="devui-item" + > + <a class="devui-link" :href="link">{{ text }}</a> + </li> + </ul> + <div ref="marker" class="devui-marker"></div> + </nav> + </aside> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; +//内容区导航样式 +.devui-content-nav { + width: 240px; + position: fixed; + top: 50px; + right: 0; + height: 90%; + z-index: 1; + + .devui-fast-forward { + width: 130px; + font-size: $devui-font-size-card-title; + color: $devui-text; + line-height: 24px; + font-weight: bold; + padding-bottom: 10px; + margin-left: 20px; + border-bottom: 1px solid $devui-dividing-line; + } + + .devui-step-nav { + margin-top: 10px; + + & > li { + list-style: none; + // padding-left: 20px; + cursor: pointer; + height: 30px; + line-height: 30px; + font-size: $devui-font-size; + color: $devui-text; + position: relative; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + a { + display: block; + width: 110px; + overflow: hidden; + color: $devui-text; + white-space: nowrap; + text-overflow: ellipsis; + -webkit-transition: all .3s ease; + transition: all .3s ease; + + } + a.current { + color: $devui-link; + } + } + } +} + +.active { + color: $devui-link !important; +} + +@media (max-width: 1800px) { + .devui-content-nav { + width: 150px; + } + + .devui-content-layout { + padding: 0 15% 0 8%; + } +} + + +@media (max-width: 1250px) { + .devui-content-nav { + display: none; + } +} + +@media (max-width: 1024px) { + .devui-content-layout { + width: 100%; + margin-left: 0; + transition: all 0.2s ease-out; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/SearchBox.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/SearchBox.vue new file mode 100644 index 0000000000000000000000000000000000000000..85f71692070d3397df7f97c4695f519cf702390a --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/SearchBox.vue @@ -0,0 +1,290 @@ +<template> + <div class="search-box"> + <input + ref="input" + aria-label="Search" + :value="query" + :class="{ focused: focused }" + :placeholder="placeholder" + autocomplete="off" + spellcheck="false" + @input="query = $event.target.value" + @focus="focused = true" + @blur="focused = false" + @keyup.enter="go(focusIndex)" + @keyup.up="onUp" + @keyup.down="onDown" + /> + <ul + v-if="showSuggestions" + class="suggestions" + :class="{ 'align-right': alignRight }" + @mouseleave="unfocus" + > + <li + v-for="(s, i) in suggestions" + :key="i" + class="suggestion" + :class="{ focused: i === focusIndex }" + @mousedown="go(i)" + @mouseenter="focus(i)" + > + <a :href="s.path" @click.prevent> + <span class="page-title">{{ s.title || s.path }}</span> + <span v-if="s.header" class="header">> {{ s.header.title }}</span> + </a> + </li> + </ul> + </div> +</template> + +<script> +import matchQuery from './match-query' + +/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */ +export default { + name: 'SearchBox', + + data() { + return { + query: '', + focused: false, + focusIndex: 0, + placeholder: undefined + } + }, + + computed: { + showSuggestions() { + return this.focused && this.suggestions && this.suggestions.length + }, + + suggestions() { + const query = this.query.trim().toLowerCase() + if (!query) { + return + } + + const { pages } = this.$site + const max = + this.$site.themeConfig.searchMaxSuggestions || SEARCH_MAX_SUGGESTIONS + const localePath = this.$localePath + const res = [] + for (let i = 0; i < pages.length; i++) { + if (res.length >= max) break + const p = pages[i] + // filter out results that do not match current locale + if (this.getPageLocalePath(p) !== localePath) { + continue + } + + // filter out results that do not match searchable paths + if (!this.isSearchable(p)) { + continue + } + + if (matchQuery(query, p)) { + res.push(p) + } else if (p.headers) { + for (let j = 0; j < p.headers.length; j++) { + if (res.length >= max) break + const h = p.headers[j] + if (h.title && matchQuery(query, p, h.title)) { + res.push( + Object.assign({}, p, { + path: p.path + '#' + h.slug, + header: h + }) + ) + } + } + } + } + return res + }, + + // make suggestions align right when there are not enough items + alignRight() { + const navCount = (this.$site.themeConfig.nav || []).length + const repo = this.$site.repo ? 1 : 0 + return navCount + repo <= 2 + } + }, + + mounted() { + this.placeholder = this.$site.themeConfig.searchPlaceholder || '' + document.addEventListener('keydown', this.onHotkey) + }, + + beforeDestroy() { + document.removeEventListener('keydown', this.onHotkey) + }, + + methods: { + getPageLocalePath(page) { + for (const localePath in this.$site.locales || {}) { + if (localePath !== '/' && page.path.indexOf(localePath) === 0) { + return localePath + } + } + return '/' + }, + + isSearchable(page) { + let searchPaths = SEARCH_PATHS + + // all paths searchables + if (searchPaths === null) { + return true + } + + searchPaths = Array.isArray(searchPaths) + ? searchPaths + : new Array(searchPaths) + + return ( + searchPaths.filter((path) => { + return page.path.match(path) + }).length > 0 + ) + }, + + onHotkey(event) { + if ( + event.srcElement === document.body && + SEARCH_HOTKEYS.includes(event.key) + ) { + this.$refs.input.focus() + event.preventDefault() + } + }, + + onUp() { + if (this.showSuggestions) { + if (this.focusIndex > 0) { + this.focusIndex-- + } else { + this.focusIndex = this.suggestions.length - 1 + } + } + }, + + onDown() { + if (this.showSuggestions) { + if (this.focusIndex < this.suggestions.length - 1) { + this.focusIndex++ + } else { + this.focusIndex = 0 + } + } + }, + + go(i) { + if (!this.showSuggestions) { + return + } + this.$router.push(this.suggestions[i].path) + this.query = '' + this.focusIndex = 0 + }, + + focus(i) { + this.focusIndex = i + }, + + unfocus() { + this.focusIndex = -1 + } + } +} +</script> + +<style lang="stylus"> +.search-box + display inline-block + position relative + margin-right 1rem + input + cursor text + width 10rem + height: 2rem + color lighten($textColor, 25%) + display inline-block + border 1px solid darken($borderColor, 10%) + border-radius 2rem + font-size 0.9rem + line-height 2rem + padding 0 0.5rem 0 2rem + outline none + transition all .2s ease + background #fff url(search.svg) 0.6rem 0.5rem no-repeat + background-size 1rem + &:focus + cursor auto + border-color $accentColor + .suggestions + background #fff + width 20rem + position absolute + top 2 rem + border 1px solid darken($borderColor, 10%) + border-radius 6px + padding 0.4rem + list-style-type none + &.align-right + right 0 + .suggestion + line-height 1.4 + padding 0.4rem 0.6rem + border-radius 4px + cursor pointer + a + white-space normal + color lighten($textColor, 35%) + .page-title + font-weight 600 + .header + font-size 0.9em + margin-left 0.25em + &.focused + background-color #f3f4f5 + a + color $accentColor + +@media (max-width: $MQNarrow) + .search-box + input + cursor pointer + width 0 + border-color transparent + position relative + &:focus + cursor text + left 0 + width 10rem + +// Match IE11 +@media all and (-ms-high-contrast: none) + .search-box input + height 2rem + +@media (max-width: $MQNarrow) and (min-width: $MQMobile) + .search-box + .suggestions + left 0 + +@media (max-width: $MQMobile) + .search-box + margin-right 0 + input + left 1rem + .suggestions + right 0 + +@media (max-width: $MQMobileNarrow) + .search-box + .suggestions + width calc(100vw - 4rem) + input:focus + width 8rem +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBar.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBar.vue new file mode 100644 index 0000000000000000000000000000000000000000..288c76b68ec7686c98f3aa23cb61bb32d7bf7885 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBar.vue @@ -0,0 +1,64 @@ +<script setup lang="ts"> +import NavLinks from './NavLinks.vue' +import SideBarLinks from './SideBarLinks.vue' + +defineProps({ + open: { type: Boolean, required: true } +}) +</script> + +<template> + <aside class="sidebar" :class="{ open }"> + <NavLinks class="nav" /> + + <slot name="sidebar-top" /> + + <SideBarLinks /> + + <slot name="sidebar-bottom" /> + </aside> +</template> + +<style scoped lang="scss"> +@import '@devui/styles-var/devui-var'; + +.sidebar { + position: fixed; + top: var(--header-height); + bottom: 0; + left: 0; + z-index: var(--z-index-sidebar); + border-right: 1px solid $devui-dividing-line; + width: 16.4rem; + background-color: $devui-base-bg; + overflow-y: auto; + transform: translateX(-100%); + transition: transform 0.25s ease; +} + +@media (min-width: 720px) { + .sidebar { + transform: translateX(0); + } +} + +@media (min-width: 960px) { + .sidebar { + width: 20rem; + } +} + +.sidebar.open { + transform: translateX(0); +} + +.nav { + display: block; +} + +@media (min-width: 720px) { + .nav { + display: none; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..acc55bf916c02c06793dae303e6233d416d21245 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.d.ts @@ -0,0 +1,6 @@ +import { FunctionalComponent } from 'vue'; +import { DefaultTheme } from '../config'; +export declare const SideBarLink: FunctionalComponent<{ + item: DefaultTheme.SideBarItem; + depth?: number; +}>; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.js b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.js new file mode 100644 index 0000000000000000000000000000000000000000..70488e7bffd0846c08e75828c9a9eafab71bb716 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLink.js @@ -0,0 +1,74 @@ +import { h } from 'vue'; +import { useRoute, useData } from 'vitepress'; +import { joinUrl, isActive } from '../utils'; +export const SideBarLink = (props) => { + const route = useRoute(); + const { site, frontmatter } = useData(); + const depth = props.depth || 1; + const maxDepth = frontmatter.value.sidebarDepth || Infinity; + const headers = route.data.headers; + const text = props.item.text; + const status = props.item.status; + const link = resolveLink(site.value.base, props.item.link); + const children = props.item.children; + const active = isActive(route, props.item.link); + const childItems = depth < maxDepth + ? createChildren(active, children, headers, depth + 1) + : null; + return h('li', { class: 'sidebar-link' }, [ + h(link ? 'a' : 'p', { + class: { 'sidebar-link-item': true, active }, + href: link + }, [ + text, + status && h('span', { + class: 'sidebar-link-status' + }, status), + ]), + childItems + ]); +}; +function resolveLink(base, path) { + if (path === undefined) { + return path; + } + // keep relative hash to the same page + if (path.startsWith('#')) { + return path; + } + return joinUrl(base, path); +} +function createChildren(active, children, headers, depth = 1) { + if (children && children.length > 0) { + return h('ul', { class: 'sidebar-links' }, children.map((c) => { + return h(SideBarLink, { item: c, depth }); + })); + } + return active && headers + ? createChildren(false, resolveHeaders(headers), undefined, depth) + : null; +} +function resolveHeaders(headers) { + return mapHeaders(groupHeaders(headers)); +} +function groupHeaders(headers) { + headers = headers.map((h) => Object.assign({}, h)); + let lastH2; + headers.forEach((h) => { + if (h.level === 2) { + lastH2 = h; + } + else if (lastH2) { + ; + (lastH2.children || (lastH2.children = [])).push(h); + } + }); + return headers.filter((h) => h.level === 2); +} +function mapHeaders(headers) { + return headers.map((header) => ({ + text: header.title, + link: `#${header.slug}`, + children: header.children ? mapHeaders(header.children) : undefined + })); +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLinks.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLinks.vue new file mode 100644 index 0000000000000000000000000000000000000000..3249a2e1cfd40f6836d1a6f41440bd15349e7d20 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/SideBarLinks.vue @@ -0,0 +1,12 @@ +<script setup lang="ts"> +import { useSideBar } from '../composables/sideBar' +import { SideBarLink } from './SideBarLink' + +const items = useSideBar() +</script> + +<template> + <ul v-if="items.length > 0" class="sidebar-links"> + <SideBarLink v-for="item of items" :item="item" /> + </ul> +</template> \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/ToggleSideBarButton.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/ToggleSideBarButton.vue new file mode 100644 index 0000000000000000000000000000000000000000..07448cc0cb6c5eda4d6d2baeb2fbb597c7c34532 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/ToggleSideBarButton.vue @@ -0,0 +1,46 @@ +<script lang="ts"> +export default { + emits: ['toggle'] +} +</script> + +<template> + <div class="sidebar-button" @click="$emit('toggle')"> + <svg + class="icon" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + role="img" + viewBox="0 0 448 512" + > + <path + fill="currentColor" + d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" + class + /> + </svg> + </div> +</template> + +<style> +.sidebar-button { + position: absolute; + top: 0.6rem; + left: 1rem; + display: none; + padding: 0.6rem; + cursor: pointer; +} + +.sidebar-button .icon { + display: block; + width: 1.25rem; + height: 1.25rem; +} + +@media screen and (max-width: 719px) { + .sidebar-button { + display: block; + } +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowLeft.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowLeft.vue new file mode 100644 index 0000000000000000000000000000000000000000..3f65b866a9e402815809b2f92ce3cd5c97642499 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowLeft.vue @@ -0,0 +1,7 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M19,11H7.4l5.3-5.3c0.4-0.4,0.4-1,0-1.4s-1-0.4-1.4,0l-7,7c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.1,0.5,0,0.8c0.1,0.1,0.1,0.2,0.2,0.3l7,7c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L7.4,13H19c0.6,0,1-0.4,1-1S19.6,11,19,11z" + /> + </svg> +</template> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowRight.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowRight.vue new file mode 100644 index 0000000000000000000000000000000000000000..ed89263f76efe5edcbaad14cf28535fec2c5a32d --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/ArrowRight.vue @@ -0,0 +1,7 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M19.9,12.4c0.1-0.2,0.1-0.5,0-0.8c-0.1-0.1-0.1-0.2-0.2-0.3l-7-7c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l5.3,5.3H5c-0.6,0-1,0.4-1,1s0.4,1,1,1h11.6l-5.3,5.3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l7-7C19.8,12.6,19.9,12.5,19.9,12.4z" + /> + </svg> +</template> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/OutboundLink.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/OutboundLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..4d74eeeb24d0c43350b1e205938e11f9fd26d9a5 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/icons/OutboundLink.vue @@ -0,0 +1,31 @@ +<template> + <svg + class="icon outbound" + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + x="0px" + y="0px" + viewBox="0 0 100 100" + width="15" + height="15" + > + <path + fill="currentColor" + d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z" + /> + <polygon + fill="currentColor" + points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9" + /> + </svg> +</template> + +<style> +.icon.outbound { + position: relative; + top: -1px; + display: inline-block; + vertical-align: middle; + color: var(--c-text-lighter); +} +</style> diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/match-query.js b/packages/devui-vue/docs/.vitepress/devui-theme/components/match-query.js new file mode 100644 index 0000000000000000000000000000000000000000..5678e3771edd11fd6aceda071fb041d30ee5c088 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/match-query.js @@ -0,0 +1,50 @@ +import get from 'lodash.get' + +export default (query, page, additionalStr = null) => { + let domain = get(page, 'title', '') + + if (get(page, 'frontmatter.tags')) { + domain += ` ${page.frontmatter.tags.join(' ')}` + } + + if (additionalStr) { + domain += ` ${additionalStr}` + } + + return matchTest(query, domain) +} + +const matchTest = (query, domain) => { + const escapeRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + + // eslint-disable-next-line no-control-regex + const nonASCIIRegExp = new RegExp('[^\x00-\x7F]') + + const words = query + .split(/\s+/g) + .map((str) => str.trim()) + .filter((str) => !!str) + + if (!nonASCIIRegExp.test(query)) { + // if the query only has ASCII chars, treat as English + const hasTrailingSpace = query.endsWith(' ') + const searchRegex = new RegExp( + words + .map((word, index) => { + if (words.length === index + 1 && !hasTrailingSpace) { + // The last word - ok with the word being "startswith"-like + return `(?=.*\\b${escapeRegExp(word)})` + } else { + // Not the last word - expect the whole word exactly + return `(?=.*\\b${escapeRegExp(word)}\\b)` + } + }) + .join('') + '.+', + 'gi' + ) + return searchRegex.test(domain) + } else { + // if the query has non-ASCII chars, treat as other languages + return words.some((word) => domain.toLowerCase().indexOf(word) > -1) + } +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/test.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/components/test.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f14b13f995161efa6cdacd27271aa70c6f911c14 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/test.d.ts @@ -0,0 +1,4 @@ +export interface Hello { + world: string; +} +export declare const O = 2; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/test.js b/packages/devui-vue/docs/.vitepress/devui-theme/components/test.js new file mode 100644 index 0000000000000000000000000000000000000000..8e5eabec73a3bfbc6e194496c446070ac9f38b7a --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/test.js @@ -0,0 +1 @@ +export const O = 2; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeBar.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeBar.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8d10d5c101c8c003423980b96e25f9899cddce6 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeBar.ts @@ -0,0 +1,136 @@ +import { onMounted, onUnmounted, onUpdated } from 'vue' + +import type { Ref } from 'vue' + +// 防抖节流控制 +export const throttleAndDebounce = (fn: () => any, delay: number) => { + let timeout: ReturnType<typeof setTimeout> + let called = false + return () => { + if (timeout) { + clearTimeout(timeout) + } + if (!called) { + fn() + called = true + setTimeout(() => { + called = false + }, delay) + } else { + timeout = setTimeout(fn, delay) + } + } +} + +export function useActiveSidebarLinks( + container: Ref<HTMLElement>, + marker: Ref<HTMLElement> +) { + const onScroll = throttleAndDebounce(setActiveLink, 150) + function setActiveLink() { + const sidebarLinks = getSidebarLinks() + const anchors = getAnchors(sidebarLinks) + + if ( + anchors.length && + window.scrollY + window.innerHeight === document.body.offsetHeight + ) { + activateLink(anchors[anchors.length - 1].hash) + return + } + for (let i = 0; i < anchors.length; i++) { + const anchor = anchors[i] + const nextAnchor = anchors[i + 1] + const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor) + if (isActive) { + history.replaceState( + null, + document.title, + hash ? (hash as string) : ' ' + ) + activateLink(hash as string) + return + } + } + } + + let prevActiveLink: HTMLAnchorElement | null = null + + function activateLink(hash: string) { + deactiveLink(prevActiveLink) + + const activeLink = (prevActiveLink = + hash == null + ? null + : (container.value.querySelector( + `.devui-item a[href="${decodeURIComponent(hash)}"]` + ) as HTMLAnchorElement)) + if (activeLink) { + activeLink.classList.add('active') + marker.value.style.opacity = '1' + marker.value.style.top = `${activeLink.offsetTop}px` + } else { + marker.value.style.opacity = '0' + marker.value.style.top = '33px' + } + } + + function deactiveLink(link: HTMLElement) { + link && link.classList.remove('active') + } + + onMounted(() => { + window.requestAnimationFrame(setActiveLink) + window.addEventListener('scroll', onScroll) + }) + + onUpdated(() => { + activateLink(location.hash) + }) + + onUnmounted(() => { + window.removeEventListener('scroll', onScroll) + }) +} +function getSidebarLinks() { + return Array.from( + document.querySelectorAll('.devui-content-nav .devui-link') + ) as HTMLAnchorElement[] +} +function getAnchors(sidebarLinks: HTMLAnchorElement[]) { + return ( + Array.from( + document.querySelectorAll('.content .header-anchor') + ) as HTMLAnchorElement[] + ).filter((anchor) => + sidebarLinks.some((sidebarLink) => sidebarLink.hash === anchor.hash) + ) +} +function getPageOffset() { + return (document.querySelector('.nav-bar') as HTMLElement).offsetHeight +} +function getAnchorTop(anchor: HTMLAnchorElement) { + const pageOffset = getPageOffset() + try { + return anchor.parentElement.offsetTop - pageOffset - 15 + } catch (e) { + return 0 + } +} +function isAnchorActive( + index: number, + anchor: HTMLAnchorElement, + nextAnchor: HTMLAnchorElement +) { + const scrollTop = window.scrollY + if (index === 0 && scrollTop === 0) { + return [true, null] + } + if (scrollTop < getAnchorTop(anchor)) { + return [false, null] + } + if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) { + return [true, decodeURIComponent(anchor.hash)] + } + return [false, null] +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..68d9ecbad25cfe03cc90aa48fdd43ef4f068383e --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.d.ts @@ -0,0 +1 @@ +export declare function useActiveSidebarLinks(): void; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.js new file mode 100644 index 0000000000000000000000000000000000000000..05f54c9fd2b2244289d952e7295eb6b503c09012 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/activeSidebarLink.js @@ -0,0 +1,99 @@ +import { onMounted, onUnmounted, onUpdated } from 'vue'; +export function useActiveSidebarLinks() { + let rootActiveLink = null; + let activeLink = null; + const onScroll = throttleAndDebounce(setActiveLink, 300); + function setActiveLink() { + const sidebarLinks = getSidebarLinks(); + const anchors = getAnchors(sidebarLinks); + for (let i = 0; i < anchors.length; i++) { + const anchor = anchors[i]; + const nextAnchor = anchors[i + 1]; + const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor); + if (isActive) { + history.replaceState(null, document.title, hash ? hash : ' '); + activateLink(hash); + return; + } + } + } + function activateLink(hash) { + deactiveLink(activeLink); + deactiveLink(rootActiveLink); + activeLink = document.querySelector(`.sidebar a[href="${hash}"]`); + if (!activeLink) { + return; + } + activeLink.classList.add('active'); + // also add active class to parent h2 anchors + const rootLi = activeLink.closest('.sidebar-links > ul > li'); + if (rootLi && rootLi !== activeLink.parentElement) { + rootActiveLink = rootLi.querySelector('a'); + rootActiveLink && rootActiveLink.classList.add('active'); + } + else { + rootActiveLink = null; + } + } + function deactiveLink(link) { + link && link.classList.remove('active'); + } + onMounted(() => { + setActiveLink(); + window.addEventListener('scroll', onScroll); + }); + onUpdated(() => { + // sidebar update means a route change + activateLink(decodeURIComponent(location.hash)); + }); + onUnmounted(() => { + window.removeEventListener('scroll', onScroll); + }); +} +function getSidebarLinks() { + return [].slice.call(document.querySelectorAll('.sidebar a.sidebar-link-item')); +} +function getAnchors(sidebarLinks) { + return [].slice + .call(document.querySelectorAll('.header-anchor')) + .filter((anchor) => sidebarLinks.some((sidebarLink) => sidebarLink.hash === anchor.hash)); +} +function getPageOffset() { + return document.querySelector('.nav-bar').offsetHeight; +} +function getAnchorTop(anchor) { + const pageOffset = getPageOffset(); + return anchor.parentElement.offsetTop - pageOffset - 15; +} +function isAnchorActive(index, anchor, nextAnchor) { + const scrollTop = window.scrollY; + if (index === 0 && scrollTop === 0) { + return [true, null]; + } + if (scrollTop < getAnchorTop(anchor)) { + return [false, null]; + } + if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) { + return [true, decodeURIComponent(anchor.hash)]; + } + return [false, null]; +} +function throttleAndDebounce(fn, delay) { + let timeout; + let called = false; + return () => { + if (timeout) { + clearTimeout(timeout); + } + if (!called) { + fn(); + called = true; + setTimeout(() => { + called = false; + }, delay); + } + else { + timeout = setTimeout(fn, delay); + } + }; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f7abc19802df171fafeddb0688446550b70f973 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.d.ts @@ -0,0 +1,4 @@ +export declare function useEditLink(): { + url: import("vue").ComputedRef<string | null>; + text: import("vue").ComputedRef<any>; +}; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.js new file mode 100644 index 0000000000000000000000000000000000000000..9ba67c9d7ad8ae1c9772acf5a50af31485f54ce2 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/editLink.js @@ -0,0 +1,47 @@ +import { computed } from 'vue'; +import { useData } from 'vitepress'; +import { endingSlashRE, isExternal } from '../utils'; +const bitbucketRE = /bitbucket.org/; +export function useEditLink() { + const { page, theme, frontmatter } = useData(); + const url = computed(() => { + const { repo, docsDir = '', docsBranch = 'master', docsRepo = repo, editLinks } = theme.value; + const showEditLink = frontmatter.value.editLink || editLinks; + const { relativePath } = page.value; + if (!showEditLink || !relativePath || !repo) { + return null; + } + return createUrl(repo, docsRepo, docsDir, docsBranch, relativePath); + }); + const text = computed(() => { + return theme.value.editLinkText || 'Edit this page'; + }); + return { + url, + text + }; +} +function createUrl(repo, docsRepo, docsDir, docsBranch, path) { + return bitbucketRE.test(repo) + ? createBitbucketUrl(repo, docsRepo, docsDir, docsBranch, path) + : createGitHubUrl(repo, docsRepo, docsDir, docsBranch, path); +} +function createGitHubUrl(repo, docsRepo, docsDir, docsBranch, path) { + const base = isExternal(docsRepo) + ? docsRepo + : `https://github.com/${docsRepo}`; + return (base.replace(endingSlashRE, '') + + `/edit` + + `/${docsBranch}/` + + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') + + path); +} +function createBitbucketUrl(repo, docsRepo, docsDir, docsBranch, path) { + const base = isExternal(docsRepo) ? docsRepo : repo; + return (base.replace(endingSlashRE, '') + + `/src` + + `/${docsBranch}/` + + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') + + path + + `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`); +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0abff6864462de7656a82f75cc5dba52bf773a3 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.d.ts @@ -0,0 +1,2 @@ +import type { DefaultTheme } from '../config'; +export declare function useLocaleLinks(): import("vue").ComputedRef<DefaultTheme.NavItemWithChildren | null>; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.js new file mode 100644 index 0000000000000000000000000000000000000000..22ac0dd12100502b1533bc2e4d7cf6ea89b05689 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nav.js @@ -0,0 +1,45 @@ +import { computed } from 'vue'; +import { useRoute, useData, inBrowser } from 'vitepress'; +export function useLocaleLinks() { + const route = useRoute(); + const { site } = useData(); + return computed(() => { + const theme = site.value.themeConfig; + const locales = theme.locales; + if (!locales) { + return null; + } + const localeKeys = Object.keys(locales); + if (localeKeys.length <= 1) { + return null; + } + // handle site base + const siteBase = inBrowser ? site.value.base : '/'; + const siteBaseWithoutSuffix = siteBase.endsWith('/') + ? siteBase.slice(0, -1) + : siteBase; + // remove site base in browser env + const routerPath = route.path.slice(siteBaseWithoutSuffix.length); + const currentLangBase = localeKeys.find((key) => { + return key === '/' ? false : routerPath.startsWith(key); + }); + const currentContentPath = currentLangBase + ? routerPath.substring(currentLangBase.length - 1) + : routerPath; + const candidates = localeKeys.map((v) => { + const localePath = v.endsWith('/') ? v.slice(0, -1) : v; + return { + text: locales[v].label, + link: `${localePath}${currentContentPath}` + }; + }); + const currentLangKey = currentLangBase ? currentLangBase : '/'; + const selectText = locales[currentLangKey].selectText + ? locales[currentLangKey].selectText + : 'Languages'; + return { + text: selectText, + items: candidates + }; + }); +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..881bc11494e1e449a2d84d201c6038015d589f7f --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.d.ts @@ -0,0 +1,15 @@ +import { Ref } from 'vue'; +import type { DefaultTheme } from '../config'; +export declare function useNavLink(item: Ref<DefaultTheme.NavItemWithLink>): { + props: import("vue").ComputedRef<{ + class: { + active: boolean; + isExternal: boolean; + }; + href: string; + target: string | null; + rel: string | null; + 'aria-label': string | undefined; + }>; + isExternal: boolean; +}; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.js new file mode 100644 index 0000000000000000000000000000000000000000..9cc42c3f765ef8f4befa9a20d786dd5c06a2943f --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/navLink.js @@ -0,0 +1,42 @@ +import { computed } from 'vue'; +import { useRoute, withBase } from 'vitepress'; +import { isExternal as isExternalCheck } from '../utils'; +export function useNavLink(item) { + const route = useRoute(); + const isExternal = isExternalCheck(item.value.link); + const props = computed(() => { + const routePath = normalizePath(`/${route.data.relativePath}`); + let active = false; + if (item.value.activeMatch) { + active = new RegExp(item.value.activeMatch).test(routePath); + } + else { + const itemPath = normalizePath(withBase(item.value.link)); + active = + itemPath === '/' + ? itemPath === routePath + : routePath.startsWith(itemPath); + } + return { + class: { + active, + isExternal + }, + href: isExternal ? item.value.link : withBase(item.value.link), + target: item.value.target || isExternal ? `_blank` : null, + rel: item.value.rel || isExternal ? `noopener noreferrer` : null, + 'aria-label': item.value.ariaLabel + }; + }); + return { + props, + isExternal + }; +} +function normalizePath(path) { + return path + .replace(/#.*$/, '') + .replace(/\?.*$/, '') + .replace(/\.(html|md)$/, '') + .replace(/\/index$/, '/'); +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe9c8407a96d1cad50fd8cca0996e4e28041d974 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.d.ts @@ -0,0 +1,5 @@ +export declare function useNextAndPrevLinks(): { + next: import("vue").ComputedRef<import("../config").DefaultTheme.SideBarLink | undefined>; + prev: import("vue").ComputedRef<import("../config").DefaultTheme.SideBarLink | undefined>; + hasLinks: import("vue").ComputedRef<boolean>; +}; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.js new file mode 100644 index 0000000000000000000000000000000000000000..8ed32d7910b63d658ec2cf55e71c5ad2e983426d --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/nextAndPrevLinks.js @@ -0,0 +1,37 @@ +import { computed } from 'vue'; +import { useData } from 'vitepress'; +import { isArray, ensureStartingSlash, removeExtention } from '../utils'; +import { getSideBarConfig, getFlatSideBarLinks } from '../support/sideBar'; +export function useNextAndPrevLinks() { + const { page, theme } = useData(); + const path = computed(() => { + return removeExtention(ensureStartingSlash(page.value.relativePath)); + }); + const candidates = computed(() => { + const config = getSideBarConfig(theme.value.sidebar, path.value); + return isArray(config) ? getFlatSideBarLinks(config) : []; + }); + const index = computed(() => { + return candidates.value.findIndex((item) => { + return item.link === path.value; + }); + }); + const next = computed(() => { + if (theme.value.nextLinks !== false && + index.value > -1 && + index.value < candidates.value.length - 1) { + return candidates.value[index.value + 1]; + } + }); + const prev = computed(() => { + if (theme.value.prevLinks !== false && index.value > 0) { + return candidates.value[index.value - 1]; + } + }); + const hasLinks = computed(() => !!next.value || !!prev.value); + return { + next, + prev, + hasLinks + }; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..abd93bbe2c78df1446da3d57ea059df7eae19d94 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.d.ts @@ -0,0 +1,5 @@ +export declare const platforms: (readonly [string, RegExp])[]; +export declare function useRepo(): import("vue").ComputedRef<{ + text: string; + link: string; +} | null>; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.js new file mode 100644 index 0000000000000000000000000000000000000000..a3c79ee304f81172b738eeece99ee38099a658f7 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/repo.js @@ -0,0 +1,37 @@ +import { computed } from 'vue'; +import { useData } from 'vitepress'; +export const platforms = ['GitHub', 'GitLab', 'Bitbucket'].map((platform) => { + return [platform, new RegExp(platform, 'i')]; +}); +export function useRepo() { + const { site } = useData(); + return computed(() => { + const theme = site.value.themeConfig; + const name = theme.docsRepo || theme.repo; + if (!name) { + return null; + } + const link = getRepoUrl(name); + const text = getRepoText(link, theme.repoLabel); + return { text, link }; + }); +} +function getRepoUrl(repo) { + // if the full url is not provided, default to GitHub repo + return /^https?:/.test(repo) ? repo : `https://github.com/${repo}`; +} +function getRepoText(url, text) { + if (text) { + return text; + } + // if no label is provided, deduce it from the repo url + const hosts = url.match(/^https?:\/\/[^/]+/); + if (!hosts) { + return 'Source'; + } + const platform = platforms.find(([_p, re]) => re.test(hosts[0])); + if (platform && platform[0]) { + return platform[0]; + } + return 'Source'; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec7544f882064084dd105591c4dbcdf76095aa4d --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.d.ts @@ -0,0 +1,2 @@ +import { DefaultTheme } from '../config'; +export declare function useSideBar(): import("vue").ComputedRef<DefaultTheme.SideBarItem[]>; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.js b/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.js new file mode 100644 index 0000000000000000000000000000000000000000..cbd13ca2e451549a3a5d4bba58621c64e528fb21 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/sideBar.js @@ -0,0 +1,59 @@ +import { computed } from 'vue'; +import { useRoute, useData } from 'vitepress'; +import { useActiveSidebarLinks } from '../composables/activeSidebarLink'; +import { getSideBarConfig } from '../support/sideBar'; +import enSidebar from '../../config/enSidebar' +import sidebar from '../../config/sidebar' +export function useSideBar() { + const route = useRoute(); + const { site } = useData(); + useActiveSidebarLinks(); + return computed(() => { + // at first, we'll check if we can find the sidebar setting in frontmatter. + const headers = route.data.headers; + const frontSidebar = route.data.frontmatter.sidebar; + const sidebarDepth = route.data.frontmatter.sidebarDepth; + // if it's `false`, we'll just return an empty array here. + if (frontSidebar === false) { + return []; + } + // if it's `atuo`, render headers of the current page + if (frontSidebar === 'auto') { + return resolveAutoSidebar(headers, sidebarDepth); + } + // now, there's no sidebar setting at frontmatter; let's see the configs + const themeSidebar = getSideBarConfig(localStorage.getItem('preferred_lang') === 'zh-CN' ? sidebar : enSidebar , route.data.relativePath); + if (themeSidebar === false) { + return []; + } + if (themeSidebar === 'auto') { + return resolveAutoSidebar(headers, sidebarDepth); + } + return themeSidebar; + }); +} +function resolveAutoSidebar(headers, depth) { + const ret = []; + if (headers === undefined) { + return []; + } + let lastH2 = undefined; + headers.forEach(({ level, title, slug }) => { + if (level - 1 > depth) { + return; + } + const item = { + text: title, + link: `#${slug}` + }; + if (level === 2) { + lastH2 = item; + ret.push(item); + } + else if (lastH2) { + ; + (lastH2.children || (lastH2.children = [])).push(item); + } + }); + return ret; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/composables/useToc.ts b/packages/devui-vue/docs/.vitepress/devui-theme/composables/useToc.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffb2689db24acecd70f1ef5e872f25561e128d11 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/composables/useToc.ts @@ -0,0 +1,57 @@ +import { computed } from 'vue' +import { useData } from 'vitepress' +import { joinUrl } from '../utils' + +import type { PageData } from 'vitepress' + +type EnhanceArrayElement<T, P> = T extends Array<infer U> ? (U & P)[] : never + +type Headers = EnhanceArrayElement< + PageData['headers'], + { + children?: Headers + } +> + +export const useToc = () => { + const { page } = useData() + + return computed(() => resolveHeaders(page.value.headers)) +} + +export const resolveLink = (base: string, path: string) => { + if (path === undefined) { + return path + } + // keep relative hash to the same page + if (path.startsWith('#')) { + return path + } + return joinUrl(base, path) +} + +export const resolveHeaders = (headers: PageData['headers']) => { + return mapHeaders(groupHeaders(headers)) +} + +export function groupHeaders(headers: PageData['headers']) { + headers = headers.map((h) => Object.assign({}, h)) + let lastH2 + + headers.forEach((h) => { + if (h.level === 3) { + lastH2 = h + } else if (lastH2) { + ;(lastH2.children || (lastH2.children = [])).push(h) + } + }) + return headers.filter((h) => h.level === 3) +} + +export function mapHeaders(headers: Headers) { + return headers.map((header) => ({ + text: header.title, + link: `#${header.slug}`, + children: header.children ? mapHeaders(header.children) : undefined, + })) +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/config.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/config.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..be96e467e55075bc435a5c4d0ee4088e812d10cf --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/config.d.ts @@ -0,0 +1,112 @@ +export declare namespace DefaultTheme { + interface Config { + logo?: string; + nav?: NavItem[] | false; + sidebar?: SideBarConfig | MultiSideBarConfig; + /** + * GitHub repository following the format <user>/<project>. + * + * @example `"vuejs/vue-next"` + */ + repo?: string; + /** + * Customize the header label. Defaults to GitHub/Gitlab/Bitbucket + * depending on the provided repo. + * + * @example `"Contribute!"` + */ + repoLabel?: string; + /** + * If your docs are in a different repository from your main project. + * + * @example `"vuejs/docs-next"` + */ + docsRepo?: string; + /** + * If your docs are not at the root of the repo. + * + * @example `"docs"` + */ + docsDir?: string; + /** + * If your docs are in a different branch. Defaults to `master`. + * + * @example `"next"` + */ + docsBranch?: string; + /** + * Enable links to edit pages at the bottom of the page. + */ + editLinks?: boolean; + /** + * Custom text for edit link. Defaults to "Edit this page". + */ + editLinkText?: string; + /** + * Show last updated time at the bottom of the page. Defaults to `false`. + * If given a string, it will be displayed as a prefix (default value: + * "Last Updated"). + */ + lastUpdated?: string | boolean; + prevLinks?: boolean; + nextLinks?: boolean; + locales?: Record<string, LocaleConfig & Omit<Config, 'locales'>>; + algolia?: AlgoliaSearchOptions; + carbonAds?: { + carbon: string; + custom?: string; + placement: string; + }; + } + type NavItem = NavItemWithLink | NavItemWithChildren; + interface NavItemBase { + text: string; + target?: string; + rel?: string; + ariaLabel?: string; + activeMatch?: string; + } + interface NavItemWithLink extends NavItemBase { + link: string; + } + interface NavItemWithChildren extends NavItemBase { + items: NavItemWithLink[]; + } + type SideBarConfig = SideBarItem[] | 'auto' | false; + interface MultiSideBarConfig { + [path: string]: SideBarConfig; + } + type SideBarItem = SideBarLink | SideBarGroup; + interface SideBarLink { + text: string; + link: string; + } + interface SideBarGroup { + text: string; + link?: string; + /** + * @default false + */ + collapsable?: boolean; + children: SideBarItem[]; + } + interface AlgoliaSearchOptions { + appId?: string; + apiKey: string; + indexName: string; + placeholder?: string; + searchParameters?: any; + disableUserPersonalization?: boolean; + initialQuery?: string; + } + interface LocaleConfig { + /** + * Text for the language dropdown. + */ + selectText?: string; + /** + * Label for this locale in the language dropdown. + */ + label?: string; + } +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/config.js b/packages/devui-vue/docs/.vitepress/devui-theme/config.js new file mode 100644 index 0000000000000000000000000000000000000000..cb0ff5c3b541f646105198ee23ac0fc3d805023e --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/config.js @@ -0,0 +1 @@ +export {}; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/index.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c15d1ed1b8639a3d997472f925073793f1a4f597 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/index.d.ts @@ -0,0 +1,8 @@ +import './styles/vars.scss'; +import './styles/layout.scss'; +import './styles/code.scss'; +import './styles/custom-blocks.scss'; +import './styles/sidebar-links.scss'; +import { Theme } from 'vitepress'; +declare const theme: Theme; +export default theme; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/index.js b/packages/devui-vue/docs/.vitepress/devui-theme/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ac71b6a9f3b5b4fb683387f8b539623fe217fbeb --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/index.js @@ -0,0 +1,9 @@ +import './styles/index.scss'; +import '@devui-design/icons/icomoon/devui-icon.css'; +import Layout from './Layout.vue'; +import NotFound from './NotFound.vue'; +const theme = { + Layout, + NotFound +}; +export default theme; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/base.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/base.scss new file mode 100644 index 0000000000000000000000000000000000000000..e5b3900541e5dc5a27908f19c2dc88f88ea84fcb --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/base.scss @@ -0,0 +1,128 @@ +// 间距 +$direction: ( + t: top, + r: right, + b: bottom, + l: left +); + +// DevUI规范的间距都是4的倍数 +$size: ( + xxs: 4px, + xs: 8px, + s: 12px, + m: 16px, + l: 20px, + xl: 24px, + xxl: 32px, +); + +@each $dir-key, $dir-value in $direction { + @each $size-key, $size-value in $size { + .m#{$dir-key}-#{$size-key} { + margin-#{$dir-value}: $size-value; + } + .p#{$dir-key}-#{$size-key} { + padding-#{$dir-value}: $size-value; + } + .#{$dir-value}-#{$size-key} { + #{$dir-value}: $size-value; + } + } +} + +.text-left { + text-align: left; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.relative { + position: relative; +} + +.absolute { + position: absolute; +} + +.fixed { + position: fixed; +} + +.sticky { + position: sticky; +} + +.hidden { + display: none; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.flex-row { + flex-direction: row; +} + +.flex-col { + flex-direction: column; +} + +.flex-grow { + flex-grow: 1; +} + +.items-start { + align-items: flex-start; +} + +.items-end { + align-items: flex-end; +} + +.items-center { + align-items: center; +} + +.items-baseline { + align-items: baseline; +} + +.items-stretch { + align-items: stretch; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.justify-evently { + justify-content: space-evenly; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/code.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/code.scss new file mode 100644 index 0000000000000000000000000000000000000000..93312a9eba871d748c26bedd191d18bbfee8b5db --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/code.scss @@ -0,0 +1,300 @@ +@import '@devui/styles-var/devui-var'; + +code { + margin: 0; + border-radius: 3px; + padding: 0.25rem 0.5rem; + font-family: var(--code-font-family); + font-size: 0.85em; + color: var(--c-text-light); + background-color: $devui-area !important; +} + +code .token.deleted { + color: #ec5975; +} + +code .token.inserted { + color: var(--c-brand); +} + +div[class*='language-'] { + position: relative; + margin: 1rem -1.5rem; + background-color: $devui-area !important; + overflow-x: auto; +} + +li > div[class*='language-'] { + border-radius: 6px 0 0 6px; + margin: 1rem -1.5rem 1rem -1.25rem; +} + +@media (min-width: 420px) { + div[class*='language-'] { + margin: 1rem 0; + border-radius: 6px; + } + + li > div[class*='language-'] { + margin: 1rem 0 1rem 0rem; + border-radius: 6px; + } +} + +[class*='language-'] pre, +[class*='language-'] code { + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +[class*='language-'] pre { + position: relative; + z-index: 1; + margin: 0; + padding: 1.25rem 1.5rem; + background: transparent; + overflow-x: auto; +} + +[class*='language-'] code { + padding: 0; + line-height: var(--code-line-height); + font-size: var(--code-font-size); + color: #eee; +} + +/* Line highlighting */ + +.highlight-lines { + position: absolute; + top: 0; + bottom: 0; + left: 0; + padding: 1.25rem 0; + width: 100%; + line-height: var(--code-line-height); + font-family: var(--code-font-family); + font-size: var(--code-font-size); + user-select: none; + overflow: hidden; +} + +.highlight-lines .highlighted { + background-color: rgba(0, 0, 0, 0.66); +} + +/* Line numbers mode */ + +div[class*='language-'].line-numbers-mode { + padding-left: 3.5rem; +} + +.line-numbers-wrapper { + position: absolute; + top: 0; + bottom: 0; + left: 0; + z-index: 3; + border-right: 1px solid rgba(0, 0, 0, 0.5); + padding: 1.25rem 0; + width: 3.5rem; + text-align: center; + line-height: var(--code-line-height); + font-family: var(--code-font-family); + font-size: var(--code-font-size); + color: #888; +} + +/* Language marker */ + +div[class*='language-']:before { + position: absolute; + top: 0.6em; + right: 1em; + z-index: 2; + font-size: 0.8rem; + color: #888; +} + +div[class~='language-html']:before, +div[class~='language-markup']:before { + content: 'html'; +} + +div[class~='language-md']:before, +div[class~='language-markdown']:before { + content: 'md'; +} + +div[class~='language-css']:before { + content: 'css'; +} + +div[class~='language-sass']:before { + content: 'sass'; +} + +div[class~='language-scss']:before { + content: 'scss'; +} + +div[class~='language-less']:before { + content: 'less'; +} + +div[class~='language-stylus']:before { + content: 'styl'; +} + +div[class~='language-js']:before, +div[class~='language-javascript']:before { + content: 'js'; +} + +div[class~='language-ts']:before, +div[class~='language-typescript']:before { + content: 'ts'; +} + +div[class~='language-json']:before { + content: 'json'; +} + +div[class~='language-rb']:before, +div[class~='language-ruby']:before { + content: 'rb'; +} + +div[class~='language-py']:before, +div[class~='language-python']:before { + content: 'py'; +} + +div[class~='language-sh']:before, +div[class~='language-bash']:before { + content: 'sh'; +} + +div[class~='language-php']:before { + content: 'php'; +} + +div[class~='language-go']:before { + content: 'go'; +} + +div[class~='language-rust']:before { + content: 'rust'; +} + +div[class~='language-java']:before { + content: 'java'; +} + +div[class~='language-c']:before { + content: 'c'; +} + +div[class~='language-yaml']:before { + content: 'yaml'; +} + +div[class~='language-dockerfile']:before { + content: 'dockerfile'; +} + +div[class~='language-vue']:before { + content: 'vue'; +} + +/** + * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML. + * Based on https://github.com/chriskempson/tomorrow-theme + * + * @author Rose Pritchard + */ +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #999; +} + +.token.punctuation { + color: #ccc; +} + +.token.tag, +.token.attr-name, +.token.namespace, +.token.deleted { + color: #e2777a; +} + +.token.function-name { + color: #6196cc; +} + +.token.boolean, +.token.number, +.token.function { + color: #f08d49; +} + +.token.property, +.token.class-name, +.token.constant, +.token.symbol { + color: #f8c555; +} + +.token.selector, +.token.important, +.token.atrule, +.token.keyword, +.token.builtin { + color: #cc99cd; +} + +.token.string, +.token.char, +.token.attr-value, +.token.regex, +.token.variable { + color: #7ec699; +} + +.token.operator, +.token.entity, +.token.url { + color: #67cdcc; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.inserted { + color: green; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/custom-blocks.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/custom-blocks.scss new file mode 100644 index 0000000000000000000000000000000000000000..ee52d4c04864ac1d53c64bd2750de3a18bc05c38 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/custom-blocks.scss @@ -0,0 +1,70 @@ +.custom-block.tip, +.custom-block.warning, +.custom-block.danger { + margin: 1rem 0; + border-left: 0.5rem solid; + padding: 0.1rem 1.5rem; + overflow-x: auto; +} + +.custom-block.tip { + background-color: #f3f5f7; + border-color: var(--c-brand); +} + +.custom-block.warning { + border-color: #e7c000; + color: #6b5900; + background-color: rgba(255, 229, 100, 0.3); +} + +.custom-block.warning .custom-block-title { + color: #b29400; +} + +.custom-block.warning a { + color: var(--c-text); +} + +.custom-block.danger { + border-color: #c00; + color: #4d0000; + background-color: #ffe6e6; +} + +.custom-block.danger .custom-block-title { + color: #900; +} + +.custom-block.danger a { + color: var(--c-text); +} + +.custom-block.details { + position: relative; + display: block; + border-radius: 2px; + margin: 1.6em 0; + padding: 1.6em; + background-color: #eee; +} + +.custom-block.details h4 { + margin-top: 0; +} + +.custom-block.details figure:last-child, +.custom-block.details p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +.custom-block.details summary { + outline: none; + cursor: pointer; +} + +.custom-block-title { + margin-bottom: -0.4rem; + font-weight: 600; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/demo-block.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/demo-block.scss new file mode 100644 index 0000000000000000000000000000000000000000..facd32f70602369c4a4a63da17179b36131600b1 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/demo-block.scss @@ -0,0 +1,33 @@ +@import '@devui/styles-var/devui-var.scss'; + +.demo-block { + border: solid 1px $devui-dividing-line !important; + + &.hover { + box-shadow: $devui-shadow-length-base $devui-shadow !important; + } +} + +.demo-block-control { + background-color: $devui-base-bg !important; + border-top: solid 1px $devui-dividing-line !important; + + &:hover { + color: $devui-brand !important; + } + + .control-button { + color: $devui-brand !important; + } +} + +.meta { + border-top: solid 1px $devui-dividing-line !important; + background-color: $devui-area !important; +} + +.description { + border: solid 1px $devui-dividing-line !important; + color: $devui-text !important; + background-color: $devui-base-bg !important; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/index.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..c3ef9e40dfe9b2439adbb04f764f4cda4b34c35b --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/index.scss @@ -0,0 +1,7 @@ +@import './base.scss'; +@import './vars.scss'; +@import './layout.scss'; +@import './code.scss'; +@import './custom-blocks.scss'; +@import './sidebar-links.scss'; +@import './demo-block.scss'; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/layout.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/layout.scss new file mode 100644 index 0000000000000000000000000000000000000000..2c5b027aafb22ee82e0756b463c84dc2b87bfea2 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/layout.scss @@ -0,0 +1,242 @@ +@import '@devui/styles-var/devui-var'; + +*, +::before, +::after { + box-sizing: border-box; +} + +html { + line-height: 1.4; + font-size: 16px; + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + width: 100%; + min-width: 320px; + min-height: 100vh; + line-height: 1.4; + font-family: var(--font-family-base); + font-size: 16px; + font-weight: 400; + color: $devui-text; + background-color: $devui-base-bg; + direction: ltr; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +main { + display: block; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + line-height: 1.25; +} + +h1, +h2, +h3, +h4, +h5, +h6, +strong, +b { + font-weight: 600; +} + +h1:hover .header-anchor, +h1:focus .header-anchor, +h2:hover .header-anchor, +h2:focus .header-anchor, +h3:hover .header-anchor, +h3:focus .header-anchor, +h4:hover .header-anchor, +h4:focus .header-anchor, +h5:hover .header-anchor, +h5:focus .header-anchor, +h6:hover .header-anchor, +h6:focus .header-anchor { + opacity: 1; +} + +h1 { + margin-top: 1.5rem; + font-size: 1.9rem; +} + +@media screen and (min-width: 420px) { + h1 { + font-size: 2.2rem; + } +} + +h2 { + margin-top: 2.25rem; + margin-bottom: 1.25rem; + border-bottom: 1px solid var(--c-divider); + padding-bottom: 0.3rem; + line-height: 1.25; + font-size: 1.65rem; + /* overflow-x: auto; */ +} + +h2 + h3 { + margin-top: 1.5rem; +} + +h3 { + margin-top: 2rem; + font-size: 1.35rem; +} + +h4 { + font-size: 1.15rem; +} + +p, +ol, +ul { + margin: 1rem 0; + line-height: 1.7; +} + +a, +area, +button, +[role='button'], +input, +label, +select, +summary, +textarea { + touch-action: manipulation; +} + +a { + text-decoration: none; + color: $devui-brand; +} + +a:hover { + text-decoration: underline; +} + +a.header-anchor { + float: left; + margin-top: 0.125em; + margin-left: -0.87em; + padding-right: 0.23em; + font-size: 0.85em; + opacity: 0; +} + +a.header-anchor:hover, +a.header-anchor:focus { + text-decoration: none; +} + +figure { + margin: 0; +} + +img { + max-width: 100%; +} + +ul, +ol { + padding-left: 1.25em; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li > ul, +li > ol { + margin: 0; +} + +table { + display: block; + border-collapse: collapse; + margin: 1rem 0; + overflow-x: auto; +} + +tr { + border-top: 1px solid $devui-dividing-line; +} + +th, +td { + border: 1px solid $devui-dividing-line; + padding: 0.6em 1em; +} + +blockquote { + margin: 1rem 0; + border-left: 0.2rem solid $devui-dividing-line; + padding: 0.25rem 0 0.25rem 1rem; + font-size: 1rem; + color: #999; +} + +blockquote > p { + margin: 0; +} + +form { + margin: 0; +} + +.theme.sidebar-open .sidebar-mask { + display: block; +} + +.theme.no-navbar > h1, +.theme.no-navbar > h2, +.theme.no-navbar > h3, +.theme.no-navbar > h4, +.theme.no-navbar > h5, +.theme.no-navbar > h6 { + margin-top: 1.5rem; + padding-top: 0; +} + +.theme.no-navbar aside { + top: 0; +} + +@media screen and (min-width: 720px) { + .theme.no-sidebar aside { + display: none; + } + + .theme.no-sidebar main { + margin-left: 0; + } +} + +.sidebar-mask { + position: fixed; + z-index: 2; + display: none; + width: 100vw; + height: 100vh; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/sidebar-links.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/sidebar-links.scss new file mode 100644 index 0000000000000000000000000000000000000000..7e08ff0a9c978dabb2ae228522b40bb5146488af --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/sidebar-links.scss @@ -0,0 +1,120 @@ +@import '@devui/styles-var/devui-var'; + +.sidebar-links { + margin: 0; + padding: 0; + list-style: none; +} + +.sidebar-link-item { + display: block; + margin: 0; + border-left: 0.25rem solid transparent; + color: $devui-text; +} + +a.sidebar-link-item:hover { + text-decoration: none; + color: $devui-brand; +} + +a.sidebar-link-item.active { + color: $devui-brand; +} + +.sidebar > .sidebar-links { + padding: 0.75rem 0 5rem; +} + +@media (min-width: 720px) { + .sidebar > .sidebar-links { + padding: 1.5rem 0; + } +} + +.sidebar > .sidebar-links > .sidebar-link + .sidebar-link { + padding-top: 0.5rem; +} + +@media (min-width: 720px) { + .sidebar > .sidebar-links > .sidebar-link + .sidebar-link { + padding-top: 1.25rem; + } +} + +.sidebar > .sidebar-links > .sidebar-link > .sidebar-link-item { + padding: 0.35rem 1.5rem 0.35rem 1.25rem; + font-size: 1.1rem; + font-weight: 700; +} + +.sidebar > .sidebar-links > .sidebar-link > a.sidebar-link-item.active { + border-left-color: $devui-brand; + font-weight: 600; +} + +.sidebar + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-link-item { + display: block; + padding: 0.35rem 1.5rem 0.35rem 2rem; + line-height: 1.4; + font-size: 1rem; + font-weight: 400; +} + +.sidebar + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > a.sidebar-link-item.active { + border-left-color: $devui-brand; + font-weight: 600; +} + +.sidebar + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-link-item { + display: block; + padding: 0.3rem 1.5rem 0.3rem 3rem; + line-height: 1.4; + font-size: 0.9rem; + font-weight: 400; +} + +.sidebar + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-links + > .sidebar-link + > .sidebar-link-item { + display: block; + padding: 0.3rem 1.5rem 0.3rem 4rem; + line-height: 1.4; + font-size: 0.9rem; + font-weight: 400; +} + +.sidebar .sidebar-link-status { + display: inline-block; + min-height: 20px; + margin: 0 8px; + padding: 0 8px; + border: solid 1px $devui-brand; + border-radius: 2px; + color: $devui-brand; + font-size: 12px; +} \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/styles/vars.scss b/packages/devui-vue/docs/.vitepress/devui-theme/styles/vars.scss new file mode 100644 index 0000000000000000000000000000000000000000..78ec1203d9ea24c15b470a29429eb2cf2e3dd940 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/styles/vars.scss @@ -0,0 +1,74 @@ +/** Base Styles */ +:root { + /** + * Colors + * --------------------------------------------------------------------- */ + + --c-white: #ffffff; + --c-white-dark: #f8f8f8; + --c-black: #000000; + + --c-divider-light: rgba(60, 60, 67, 0.12); + --c-divider-dark: rgba(84, 84, 88, 0.48); + + --c-text-light-1: #2c3e50; + --c-text-light-2: #476582; + --c-text-light-3: #90a4b7; + + --c-brand: #3eaf7c; + --c-brand-light: #4abf8a; + + /** + * Typography + * --------------------------------------------------------------------- */ + + --font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + --font-family-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; + + /** + * Z Indexes + * + * Algolia SearchBox has a z-index of 200, so make sure not to go above + * that value. + * --------------------------------------------------------------------- */ + + --z-index-navbar: 10; + --z-index-sidebar: 6; + + /** + * Shadows + * --------------------------------------------------------------------- */ + + --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06); + --shadow-2: 0 3px 12px rgba(0, 0, 0, 0.07), 0 1px 4px rgba(0, 0, 0, 0.07); + --shadow-3: 0 12px 32px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.08); + --shadow-4: 0 14px 44px rgba(0, 0, 0, 0.12), 0 3px 9px rgba(0, 0, 0, 0.12); + --shadow-5: 0 18px 56px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.16); + + /** + * Sizes + * --------------------------------------------------------------------- */ + + --header-height: 3.6rem; +} + +/** Fallback Styles */ +:root { + --c-divider: var(--c-divider-light); + + --c-text: var(--c-text-light-1); + --c-text-light: var(--c-text-light-2); + --c-text-lighter: var(--c-text-light-3); + + --c-bg: var(--c-white); + --c-bg-accent: var(--c-white-dark); + + --code-line-height: 24px; + --code-font-family: var(--font-family-mono); + --code-font-size: 14px; + --code-inline-bg-color: rgba(27, 31, 35, 0.05); + --code-bg-color: #282c34; +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d8cc85a5b688f42bbe526686ad916f800dfdb36 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.d.ts @@ -0,0 +1,18 @@ +import { DefaultTheme } from '../config'; +export declare function isSideBarConfig(sidebar: DefaultTheme.SideBarConfig | DefaultTheme.MultiSideBarConfig): sidebar is DefaultTheme.SideBarConfig; +export declare function isSideBarGroup(item: DefaultTheme.SideBarItem): item is DefaultTheme.SideBarGroup; +export declare function isSideBarEmpty(sidebar?: DefaultTheme.SideBarConfig): boolean; +/** + * Get the `SideBarConfig` from sidebar option. This method will ensure to get + * correct sidebar config from `MultiSideBarConfig` with various path + * combinations such as matching `guide/` and `/guide/`. If no matching config + * was found, it will return `auto` as a fallback. + */ +export declare function getSideBarConfig(sidebar: DefaultTheme.SideBarConfig | DefaultTheme.MultiSideBarConfig, path: string): DefaultTheme.SideBarConfig; +/** + * Get flat sidebar links from the sidebar items. This method is useful for + * creating the "next and prev link" feature. It will ignore any items that + * don't have `link` property and removes `.md` or `.html` extension if a + * link contains it. + */ +export declare function getFlatSideBarLinks(sidebar: DefaultTheme.SideBarItem[]): DefaultTheme.SideBarLink[]; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.js b/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.js new file mode 100644 index 0000000000000000000000000000000000000000..54c95bea18e10fd6922e8b9d7f2a9471dc512dfa --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/support/sideBar.js @@ -0,0 +1,46 @@ +import { isArray, ensureStartingSlash, removeExtention } from '../utils'; +export function isSideBarConfig(sidebar) { + return sidebar === false || sidebar === 'auto' || isArray(sidebar); +} +export function isSideBarGroup(item) { + return item.children !== undefined; +} +export function isSideBarEmpty(sidebar) { + return isArray(sidebar) ? sidebar.length === 0 : !sidebar; +} +/** + * Get the `SideBarConfig` from sidebar option. This method will ensure to get + * correct sidebar config from `MultiSideBarConfig` with various path + * combinations such as matching `guide/` and `/guide/`. If no matching config + * was found, it will return `auto` as a fallback. + */ +export function getSideBarConfig(sidebar, path) { + if (isSideBarConfig(sidebar)) { + return sidebar; + } + path = ensureStartingSlash(path); + for (const dir in sidebar) { + // make sure the multi sidebar key starts with slash too + if (path.startsWith(ensureStartingSlash(dir))) { + return sidebar[dir]; + } + } + return 'auto'; +} +/** + * Get flat sidebar links from the sidebar items. This method is useful for + * creating the "next and prev link" feature. It will ignore any items that + * don't have `link` property and removes `.md` or `.html` extension if a + * link contains it. + */ +export function getFlatSideBarLinks(sidebar) { + return sidebar.reduce((links, item) => { + if (item.link) { + links.push({ text: item.text, link: removeExtention(item.link) }); + } + if (isSideBarGroup(item)) { + links = [...links, ...getFlatSideBarLinks(item.children)]; + } + return links; + }, []); +} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/utils.d.ts b/packages/devui-vue/docs/.vitepress/devui-theme/utils.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..68258968c2d28456c79e43e46992781d54764b76 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/utils.d.ts @@ -0,0 +1,25 @@ +import { Route } from 'vitepress'; +export declare const hashRE: RegExp; +export declare const extRE: RegExp; +export declare const endingSlashRE: RegExp; +export declare const outboundRE: RegExp; +export declare function isNullish(value: any): value is null | undefined; +export declare function isArray(value: any): value is any[]; +export declare function isExternal(path: string): boolean; +export declare function isActive(route: Route, path?: string): boolean; +export declare function normalize(path: string): string; +export declare function joinUrl(base: string, path: string): string; +/** + * get the path without filename (the last segment). for example, if the given + * path is `/guide/getting-started.html`, this method will return `/guide/`. + * Always with a trailing slash. + */ +export declare function getPathDirName(path: string): string; +export declare function ensureSlash(path: string): string; +export declare function ensureStartingSlash(path: string): string; +export declare function ensureEndingSlash(path: string): string; +/** + * Remove `.md` or `.html` extention from the given path. It also converts + * `index` to slush. + */ +export declare function removeExtention(path: string): string; diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/utils.js b/packages/devui-vue/docs/.vitepress/devui-theme/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..51ad485ce435d54ccdca1d1e9a5da2da9f4235c5 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/devui-theme/utils.js @@ -0,0 +1,63 @@ +export const hashRE = /#.*$/; +export const extRE = /(index)?\.(md|html)$/; +export const endingSlashRE = /\/$/; +export const outboundRE = /^[a-z]+:/i; +export function isNullish(value) { + return value === null || value === undefined; +} +export function isArray(value) { + return Array.isArray(value); +} +export function isExternal(path) { + return outboundRE.test(path); +} +export function isActive(route, path) { + if (path === undefined) { + return false; + } + const routePath = normalize(`/${route.data.relativePath}`); + const pagePath = normalize(path); + return routePath === pagePath; +} +export function normalize(path) { + return decodeURI(path).replace(hashRE, '').replace(extRE, ''); +} +export function joinUrl(base, path) { + const baseEndsWithSlash = base.endsWith('/'); + const pathStartsWithSlash = path.startsWith('/'); + if (baseEndsWithSlash && pathStartsWithSlash) { + return base.slice(0, -1) + path; + } + if (!baseEndsWithSlash && !pathStartsWithSlash) { + return `${base}/${path}`; + } + return base + path; +} +/** + * get the path without filename (the last segment). for example, if the given + * path is `/guide/getting-started.html`, this method will return `/guide/`. + * Always with a trailing slash. + */ +export function getPathDirName(path) { + const segments = path.split('/'); + if (segments[segments.length - 1]) { + segments.pop(); + } + return ensureEndingSlash(segments.join('/')); +} +export function ensureSlash(path) { + return ensureEndingSlash(ensureStartingSlash(path)); +} +export function ensureStartingSlash(path) { + return /^\//.test(path) ? path : `/${path}`; +} +export function ensureEndingSlash(path) { + return /(\.html|\/)$/.test(path) ? path : `${path}/`; +} +/** + * Remove `.md` or `.html` extention from the given path. It also converts + * `index` to slush. + */ +export function removeExtention(path) { + return path.replace(/(index)?(\.(md|html))?$/, '') || '/'; +} diff --git a/packages/devui-vue/docs/.vitepress/theme/index.ts b/packages/devui-vue/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..91c2acd34caebde08b3001d6950caf767ad11eac --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/theme/index.ts @@ -0,0 +1,14 @@ +import DevUI from '../../../devui/vue-devui' +import Theme from '../devui-theme' +import 'vitepress-theme-demoblock/theme/styles/index.css' +import { registerComponents } from './register-components.js' +import { insertBaiduScript } from './insert-baidu-script' + +export default { + ...Theme, + enhanceApp({ app }) { + app.use(DevUI) + registerComponents(app) + insertBaiduScript() + } +} \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/theme/insert-baidu-script.ts b/packages/devui-vue/docs/.vitepress/theme/insert-baidu-script.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c5ba9bff912063a24538281181f7ca78db85a99 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/theme/insert-baidu-script.ts @@ -0,0 +1,15 @@ +export function insertBaiduScript() { + if (typeof document === 'undefined') return + const baiduScript = document.createElement('script') + const baiduScriptStr = ` + var _hmt = _hmt || []; + (function() { + var hm = document.createElement("script"); + hm.src = "https://hm.baidu.com/hm.js?0c8e27d8ae0d13fbef28c934b5464d5d"; + var s = document.getElementsByTagName("script")[0]; + s.parentNode.insertBefore(hm, s); + })(); + ` + baiduScript.textContent = baiduScriptStr + document.body.append(baiduScript) +} \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/theme/register-components.js b/packages/devui-vue/docs/.vitepress/theme/register-components.js new file mode 100644 index 0000000000000000000000000000000000000000..4d1f7521a0a098dab7327cab145b9442bf90a690 --- /dev/null +++ b/packages/devui-vue/docs/.vitepress/theme/register-components.js @@ -0,0 +1,6 @@ +import Demo from 'vitepress-theme-demoblock/components/Demo.vue' +import DemoBlock from 'vitepress-theme-demoblock/components/DemoBlock.vue' +export function registerComponents(app) { + app.component('Demo', Demo) + app.component('DemoBlock', DemoBlock) +} diff --git a/packages/devui-vue/docs/assets/logo.svg b/packages/devui-vue/docs/assets/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..31fed46a6872e56683a387bf2eaf1953684c2f63 --- /dev/null +++ b/packages/devui-vue/docs/assets/logo.svg @@ -0,0 +1,30 @@ +<svg width="80px" height="80px" viewBox="0 0 26 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient x1="89.5364583%" y1="21.60078%" x2="7.57349918%" y2="65.7395747%" id="linearGradient-1"> + <stop stop-color="#2954C8" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="89.5364583%" y1="21.4573588%" x2="7.57349918%" y2="65.8190624%" id="linearGradient-2"> + <stop stop-color="#2954C8" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="-11.5260417%" y1="24.3907324%" x2="87.1145833%" y2="74.8850926%" id="linearGradient-3"> + <stop stop-color="#89D2FF" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="0%" y1="18.4813953%" x2="75.9513522%" y2="81.5186047%" id="linearGradient-4"> + <stop stop-color="#89D2FF" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + </defs> + <g id="Devui-Logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Group-2" transform="translate(3.000000, 0.000000)"> + <g> + <path d="M4.28576801,9.22873192 L9.32098286,6.02205882 L13.1143389,8.49673203 L0.010890596,17.0193525 L0.010890596,17.0193525 C0.010890596,13.8625823 1.62310848,10.9244448 4.28576801,9.22873192 Z" id="Path-39-Copy-3" fill="url(#linearGradient-1)"></path> + <path d="M8.76945593,17.4828869 L14.1939212,14.0196078 L18.2867527,16.6963836 L4.14882163,25.9150327 L4.14882163,25.9150327 C4.14882163,22.4998846 5.89095741,19.3206798 8.76945593,17.4828869 Z" id="Path-39-Copy-2" fill="url(#linearGradient-2)" transform="translate(11.217787, 19.967320) scale(-1, 1) translate(-11.217787, -19.967320) "></path> + <path d="M0.183304389,2.48689958e-13 L13.1143389,8.49673203 L9.42310099,10.9017055 L9.42310099,10.9017055 C4.36778167,11.0371959 0.159798979,7.04888649 0.0243085926,1.99356717 C0.00937841938,1.43650334 0.0453320846,0.879239543 0.13172203,0.32871271 L0.183304389,2.48689958e-13 Z" id="Path-38-Copy-3" fill="url(#linearGradient-3)"></path> + <path d="M4.54131151,6.55708742 L19.8945577,16.6535948 L16.2033199,19.0585682 L11.1830136,17.9470593 C6.34348625,16.8755752 3.2888836,12.0837536 4.36036765,7.24422626 C4.41158805,7.01288123 4.47194996,6.78365535 4.54131151,6.55708742 L4.54131151,6.55708742 Z" id="Path-38-Copy-2" fill="url(#linearGradient-4)" transform="translate(12.021690, 12.807828) scale(-1, 1) translate(-12.021690, -12.807828) "></path> + </g> + </g> + </g> +</svg> \ No newline at end of file diff --git a/packages/devui-vue/docs/components/accordion/index.md b/packages/devui-vue/docs/components/accordion/index.md new file mode 100644 index 0000000000000000000000000000000000000000..da243f871636e81b076c0b41e0ff3a824253a8d9 --- /dev/null +++ b/packages/devui-vue/docs/components/accordion/index.md @@ -0,0 +1,4 @@ +# Accordion 手风琴 +为页面提供导航的组件。 +### 何时使用 +需要通过分组组织菜单的时候使用。 \ No newline at end of file diff --git a/packages/devui-vue/docs/components/alert/index.md b/packages/devui-vue/docs/components/alert/index.md new file mode 100644 index 0000000000000000000000000000000000000000..d773f90c664a24b702d69d0a2781f06f7d71f53c --- /dev/null +++ b/packages/devui-vue/docs/components/alert/index.md @@ -0,0 +1,120 @@ +# Alert 警告 + +显示警告信息,需要用户关注的信息的组件。 + +### 何时使用 + +当页面需要向用户发出警告信息时。 + +### 基本用法 + +共有四种样式:success、danger、warning、info。 + +:::demo + +```vue +<template> + <div class="alert-demo-1"> + <d-alert type="success" :closeable="false"> success </d-alert> + <d-alert type="danger" :closeable="false"> danger </d-alert> + <d-alert type="warning" :closeable="false"> warning </d-alert> + <d-alert type="info" :closeable="false"> info </d-alert> + <d-alert type="simple" :closeable="false"> simple </d-alert> + </div> +</template> +<style> +.alert-demo-1 .devui-alert { + margin-bottom: 20px; +} +</style> +``` + +::: + +### 可关闭的提示 + +显示关闭按钮,点击可关闭提示。 + +:::demo + +```vue +<template> + <div class="alert-demo-2"> + <d-alert type="success" @close="handleClose"> success </d-alert> + <d-alert type="danger" @close="handleClose"> danger </d-alert> + <d-alert type="warning" @close="handleClose"> warning </d-alert> + <d-alert type="info" @close="handleClose"> info </d-alert> + <d-alert type="simple" @close="handleClose"> simple </d-alert> + </div> +</template> +<script> +export default { + setup() { + const handleClose = ($event) => { + console.log($event) + } + return { + handleClose, + } + }, +} +</script> +<style> +.alert-demo-2 .devui-alert { + margin-bottom: 20px; +} +</style> +``` + +::: + +### 不使用默认图标 + +不使用默认的类型图标。 + +:::demo + +```vue +<template> + <div class="alert-demo-3"> + <d-alert type="success" :showIcon="false"> success </d-alert> + <d-alert type="danger" :showIcon="false"> danger </d-alert> + <d-alert type="warning" :showIcon="false"> warning </d-alert> + <d-alert type="info" :showIcon="false"> info </d-alert> + <d-alert type="simple" :showIcon="false"> simple </d-alert> + </div> +</template> +<style> +.alert-demo-3 .devui-alert { + margin-bottom: 20px; +} +</style> +``` + +::: + +### API + +### d-alert 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :-----------------------: | :----: | :-------------------------------------: | :-------------------------------- | +| type | [`AlertType`](#AlertType) | 'info' | 必选,指定警告提示的样式 | [基本用法](#基本用法) | +| cssClass | `string` | -- | 可选,自定义 class 名 | +| closeable | `boolean` | true | 可选,默认显示关闭按钮 | [基本用法](#可关闭的提示) | +| dismissTime | `number` | -- | 可选,自动关闭 alert 的延迟时间(`ms`) | +| showIcon | `boolean` | true | 可选,是否使用默认的类型图标 | [不使用默认图标](#不使用默认图标) | + +### d-alert 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| :---: | :----------------------------: | :------------------------- | ----------------------------- | +| close | `(event?: MouseEvent) => void` | 可选,关闭时触发的回调函数 | [可关闭的提示](#可关闭的提示) | + +### AlertType + +默认值为'info', 指定 alert 警告提示的类型 + +```ts +export type AlertType = 'success' | 'danger' | 'warning' | 'info' | 'simple' +``` diff --git a/packages/devui-vue/docs/components/anchor/demo.tsx b/packages/devui-vue/docs/components/anchor/demo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d87cc00cee9d87e05961c61c1a8d52b202e5a851 --- /dev/null +++ b/packages/devui-vue/docs/components/anchor/demo.tsx @@ -0,0 +1,35 @@ +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'DAnchor', + props: { + }, + setup() { + return () => { + return ( + <div v-d-anchor-box className="scrollTarget"> + <ul> + <li v-d-anchor-link="anchorlink-one">anchorlink-one</li> + <li v-d-anchor-link="anchorlink-two">anchorlink-two</li> + <li v-d-anchor-link="anchorlink-three">anchorlink-three</li> + <li v-d-anchor-link="anchorlink-four">anchorlink-four</li> + </ul> + <div> + <div v-d-anchor="anchorlink-one"> + anchorlink-one + </div> + <div v-d-anchor="anchorlink-two"> + anchorlink-two + </div> + <div v-d-anchor="anchorlink-three"> + anchorlink-three + </div> + <div v-d-anchor="anchorlink-four"> + anchorlink-four + </div> + </div> + </div> + ) + } + } +}) \ No newline at end of file diff --git a/packages/devui-vue/docs/components/anchor/index.md b/packages/devui-vue/docs/components/anchor/index.md new file mode 100644 index 0000000000000000000000000000000000000000..1a3ad44ad8f8adbe90bd5d684f2d0121065685f1 --- /dev/null +++ b/packages/devui-vue/docs/components/anchor/index.md @@ -0,0 +1,87 @@ +# Anchor 锚点 + +跳转到页面指定位置的组件。 + +### 何时使用 + +需要在页面的各个部分之间实现快速跳转时。 + +<script lang="ts"> + import { defineComponent } from 'vue' + import Anchor from './demo' + export default defineComponent({ + components: { + Anchor + } + }) +</script> +<anchor /> + +### 基本用法 + + +在页面中使用: + +```html +<!-- class="scrollTarget" 加上这个类名是局部滚动,不加是全局滚动 --> +<div v-d-anchor-box className="scrollTarget"> + <ul> + <li v-d-anchor-link="anchorlink-one">anchorlink-one</li> + <li v-d-anchor-link="anchorlink-two">anchorlink-two</li> + <li v-d-anchor-link="anchorlink-three">anchorlink-three</li> + <li v-d-anchor-link="anchorlink-four">anchorlink-four</li> + </ul> + <div> + <div v-d-anchor="anchorlink-one"> + anchorlink-one1 + </div> + <div v-d-anchor="anchorlink-two"> + anchorlink-two + </div> + <div v-d-anchor="anchorlink-three"> + anchorlink-three + </div> + <div v-d-anchor="anchorlink-four"> + anchorlink-four + </div> + </div> +</div> +``` + +### dAnchor + +定义一个锚点。 +### dAnchor 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo |全局配置项| +| :----------------: | :----------: | :------: | :--: | :---------------------------------------------------: | ---------------------------- | +| dAnchor | `string` | -- | 必选,设置一个锚点的名字 | [基本用法](#基本用法) | +| anchorActive | `string` | -- | 可选,锚点处于激活状态的时候,模块生效对应的 css 类名 | [基本用法](#基本用法) | + +### dAnchor 锚点激活事件 + +自动会给锚点加上以下类对应不同激活的对象。 + +| css 类名 | 代表意义 | +| :---------------------------: | :--------------------: | +| anchor-active-by-anchor-link | 点击锚点链接激活 | +| anchor-active-by-scroll | 容器滚动到锚点位置激活 | +| anchor-active-by-click-inside | 点击锚点内部内容激活 | +| anchor-active-by-initial | 初始化滚动条位置激活 | + +### dAnchorLink + +定义一个锚点的链接,点击链接会滑动到锚点,锚点处于页面顶部的时候也会激活链接的 class。 + +### dAnchorLink 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo |全局配置项| +| :----------------: | :----------: | :------: | :--: | :---------------------------------------------------: | ---------------------------- | +| dAnchorLink | `string` | -- | 必选,点击滑动的目标锚点的名字 | [基本用法](#基本用法) | +| anchorActive | `string` | -- | 可选,锚点处于激活状态的时候,链接生效对应的 css 类名 | [基本用法](#基本用法) | + +### dAnchorBox + +必须有一个容器,否则功能无法使用。 + +定义一个扫描锚点的容器,放在 dAnchor 与 dAnchorLink 的公共父节点上,用于锚点和链接之间的通信。 diff --git a/packages/devui-vue/docs/components/avatar/index.md b/packages/devui-vue/docs/components/avatar/index.md new file mode 100644 index 0000000000000000000000000000000000000000..013806da87fbd9766087c1bec52c2f2960c28daa --- /dev/null +++ b/packages/devui-vue/docs/components/avatar/index.md @@ -0,0 +1,127 @@ +# Avatar 头像 + +显示用户头像的组件。 + +### 何时使用 + +当需要显示用户头像时。 + +### 头像显示的基本规则 + +头像组件传入'name'属性时,会根据一定的规则显示头像的字段,具体规则参见 API。 + +:::demo + +```vue +<template> + <div class="avatar-demo-1"> + <d-avatar + style="text-align: right" + gender="Female" + name="组件头像" + ></d-avatar> + <d-avatar name="MyAvatar"></d-avatar> + <d-avatar name="Avatar1 Avatar2"></d-avatar> + <d-avatar name="1Avatar"></d-avatar> + </div> +</template> + +<style> +.avatar-demo-1 .devui-avatar { + margin-right: 10px; +} +</style> +``` + +::: + +### 头像的基础配置 + +头像组件可设置宽度,高度,是否为圆形头像,同时可自定义头像的显示字段,传入自定义图片等。 + +:::demo + +```vue +<template> + <div class="avatar-demo-2"> + <d-avatar name="Avatar" :width="28" :height="28"></d-avatar> + <d-avatar + customText="DevUI" + :width="80" + :height="80" + :isRound="false" + ></d-avatar> + <d-avatar + imgSrc="/../../assets/logo.svg" + :width="100" + :height="100" + :isRound="false" + ></d-avatar> + </div> +</template> + +<style> +.avatar-demo-2 { + display: flex; + align-items: center; +} +.avatar-demo-2 .devui-avatar { + margin-right: 10px; +} +</style> +``` + +::: + +### 头像的特殊显示 + +头像组件会对一些特殊情况进行处理,具体表现为用户不存在或展示默认头像,详细规则参见 API。 + +:::demo + +```vue +<template> + <div class="avatar-demo-3"> + <d-avatar></d-avatar> + <d-avatar name=""></d-avatar> + </div> +</template> + +<style> +.avatar-demo-3 .devui-avatar { + margin-right: 10px; +} +</style> +``` + +::: + +### API + +### d-avatar 参数 + +| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | +| :--------: | :------------------------: | :----: | :-----------------------------------------------------------------------------: | :---------------------------------------- | +| name | `string` | -- | 必选,传入字符串用于制作头像 | [头像显示的基本规则](#头像显示的基本规则) | +| gender | `string \| male \| female` | -- | 可选,根据性别区分头像颜色,传入 string,可以是`female \| male`的任意大小写形式 | [头像显示的基本规则](#头像显示的基本规则) | +| width | `number` | 40 | 可选,设定头像的宽度, 单位为`px` | [头像的基础配置](#头像的基础配置) | +| height | `number` | 40 | 可选,设定头像的高度,单位为`px` | [头像的基础配置](#头像的基础配置) | +| isRound | `boolean` | true | 可选,是否显示为圆形头像 | [头像的基础配置](#头像的基础配置) | +| imgSrc | `string` | -- | 可选,传入自定义图片作为头像 | [头像的基础配置](#头像的基础配置) | +| customText | `string` | -- | 可选,传入自定义显示文字 | [头像的基础配置](#头像的基础配置) | + +### 头像显示基本规则 + +- `中文开头`:取传入字符串的最后两个字符 +- `英文开头`:取传入字符串的前面两个字符 +- `多个英文名连用`:取传入字符串的前两个英文名首字母 +- `非中英文开头`:取传入字符串的前两个字符 + +### 头像特殊显示规则 + +- 未传入`name`,`customText`,`imgSrc`,视为使用该头像的用户不存在 +- 传入`name`,`customText`,`imgSrc`的值为空,视为使用该头像的用户无昵称,使用默认头像 + +### 显示优先级排序 + +imgSrc > customText > name diff --git a/packages/devui-vue/docs/components/back-top/index.md b/packages/devui-vue/docs/components/back-top/index.md new file mode 100644 index 0000000000000000000000000000000000000000..f2be59b9ed7b38c1fab6fe7f25fb189add33c192 --- /dev/null +++ b/packages/devui-vue/docs/components/back-top/index.md @@ -0,0 +1,92 @@ +# BackTop 回到顶部 + +返回页面顶部的操作按钮。 + +### 何时使用 + +当页面内容区域比较长时;当用户需要频繁返回顶部查看相关内容时。 + +### 基本用法 + +回到顶部按钮的默认样式,距离底部 50px,右侧 30px。 + +:::demo + +```vue +<template> + <div> + <div>这里看不到我嘿嘿,下滑试试</div> + <d-back-top /> + <d-back-top bottom="100px"> + <d-icon name="chevron-up"></d-icon> + </d-back-top> + </div> +</template> + +<script> +import { defineComponent } from 'vue' + +export default defineComponent({ + setup() { + return { + msg: 'BackTop 回到顶部 组件文档示例' + } + } +}) +</script> + +<style></style> +``` + +::: + +### 自定义 + +回到顶部组件可自定义按钮样式,限制宽高:40px \* 40px。同时可通过 class 个性化设置按钮样式。 + +:::demo + +```vue +<template> + <div> + <div>这里看不到我嘿嘿,下滑试试</div> + <d-back-top bottom="100px"> + <d-icon name="chevron-up" color="#fff"></d-icon> + </d-back-top> + </div> +</template> + +<script> +import { defineComponent } from 'vue' + +export default defineComponent({ + setup() {} +}) +</script> + +<style> +.devui-back-top .devui-backtop-custom { + background-color: #5e7ce0; +} +</style> +``` + +::: + +### d-back-top + +d-back-top 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :----: | :------: | :----: | :------------------------: | :---------------: | +| bottom | `string` | "50px" | 可选,按钮距离页面底部位置 | [示例](#基本用法) | +| right | `string` | "30px" | 可选,按钮距离页面右边距 | [示例](#基本用法) | +| | | | | | + +d-back-top 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | diff --git a/packages/devui-vue/docs/components/badge/index.md b/packages/devui-vue/docs/components/badge/index.md new file mode 100644 index 0000000000000000000000000000000000000000..3084859c548f20c59ae4ee1651f8942f7b676a3f --- /dev/null +++ b/packages/devui-vue/docs/components/badge/index.md @@ -0,0 +1,146 @@ +# Badge 徽标 + +图标右上角的圆形徽标数字。 + +### 何时使用 + +出现在图标右上角或列表项右方,通过不同的状态色加数字提示用户有消息需要处理时。 + +### 基本徽章 + +::: demo 基本徽章类型,当有包裹元素时在右上角显示徽章和数目。 +```vue +<template> + <d-badge :count='6' status="danger" class="devui-badge-item">未读消息</d-badge> + <d-badge :count='7' status="waiting" class="devui-badge-item">未读消息</d-badge> + <d-badge :count='8' status="success" class="devui-badge-item">未读消息</d-badge> + <d-badge :count='100' status="info" class="devui-badge-item">未读消息</d-badge> +</template> + +``` +::: + +### 点状徽章 + +:::demo 点状徽章类型,当有包裹元素且 showDot 参数为 true 时为点状徽章,默认在右上角展示小点不显示数目。 +```vue +<template> + <d-badge status="danger" showDot class="devui-badge-item">未读消息</d-badge> + <d-badge status="waiting" showDot class="devui-badge-item">未读消息</d-badge> + <d-badge status="warning" showDot class="devui-badge-item"> + <d-icon name="like" /> + </d-badge> + <d-badge status="info" showDot class="devui-badge-item"> + <d-icon name="like" /> + </d-badge> +</template> + +``` +::: + +### 计数徽章 + +:::demo 当徽章独立使用且不包裹任何元素时,只展示徽章状态色和数目。 +```vue +<template> + <ul class="devui-badge-list"> + <li class="devui-badge-list-item"> + <span>系统消息</span> + <d-badge status="danger" :count="50"></d-badge> + </li> + <li class="devui-badge-list-item"> + <span>个人消息</span> + <d-badge status="info" :count="500"></d-badge> + </li> + </ul> +</template> + +``` +::: + +### 状态徽章 + +:::demo 当徽章独立使用、不包裹任何元素且 showDot 参数为 true 时为状态徽章,不同状态展示不同色点。 +```vue +<template> + <d-badge status="danger" showDot></d-badge> danger <br /> + <d-badge status="warning" showDot></d-badge> warning <br /> + <d-badge status="waiting" showDot></d-badge> waiting <br /> + <d-badge status="info" showDot></d-badge> info <br /> + <d-badge status="success" showDot></d-badge> success <br /> +</template> + +``` +::: + +### 徽章位置 + +:::demo 通过 badgePos 参数设置徽章位置。 +```vue +<template> + <d-badge :count='6' status="danger" badgePos="top-left" class="devui-badge-item">未读消息</d-badge> + <d-badge :count='7' status="waiting" badgePos="top-right" class="devui-badge-item">未读消息</d-badge> + <d-badge :count='8' status="success" badgePos="bottom-left" class="devui-badge-item"> + <d-icon name="emoji" /></d-badge> + <d-badge :count='100' status="info" badgePos="bottom-right" class="devui-badge-item"> + <d-icon name="notice" /> + </d-badge> +</template> + +``` +::: + +### 自定义 + +:::demo 通过 bgColor 参数设置徽章展示状态色(此时 status 参数设置的徽章状态色失效),通过 offsetXY 参数可设置相对于 badgePos 的徽章偏移量。通过 textColor、bgColor 自定义文字、背景颜色。 +```vue +<template> + <d-badge :count="666" status="success" style="margin-right: 20px"> + <d-icon name="notice" /> + </d-badge> + <d-badge :count="666" status="success" style="margin-right: 30px" :offsetXY='[-10, 0]'> + <d-icon name="notice" /> + </d-badge> + <d-badge count="6" style="margin-right: 20px" :offsetXY='[0, -10]' >未读消息</d-badge> + <d-badge count="6" bgColor="red" textColor="#fff" style="margin-right: 20px">未读消息</d-badge> + <d-badge count="2.3k" bgColor="#000" textColor="#fff"></d-badge> +</template> + +``` +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | +| :-------: | :-----------------: | :---------: | :--------------------------------------------------------------------------------------------------------------------------- | +| count | `Number` | -- | 可选,设置基本徽章和计数徽章中显示的数目 | +| maxCount | `Number` | 99 | 可选,设置基本徽章和计数徽章最大可显示数目,当 count > maxCount 时显示 maxCount+ | +| showDot | `Boolean` | false | 可选,true 时为点状徽章(有包裹)或状态徽章(无包裹),false 时为基本徽章(有包裹)或计数徽章(无包裹) | +| status | `BadgeStatusType` | -- | 可选,状态色 danger\| warning \| waiting \| success \| info | +| badgePos | `BadgePositionType` | 'top-right' | 可选,徽标位置 top-left\| top-right \| bottom-left \| bottom-right | +| bgColor | `String` | -- | 可选,自定义徽标色,此时 status 参数设置的徽章状态色失效 | +| textColor | `String` | -- | 可选, 可自定义徽标文字颜色 | +| offsetXY | `[number, number] ` | -- | 可选,可选,有包裹时徽标位置偏移量,格式为[x,y],单位为 px。x 为相对 right 或 left 的偏移量,y 为相对 top 或 bottom 的偏移量 | + +<style lang="scss"> +@import '@devui-design/icons/icomoon/devui-icon.css'; +.devui-badge-item { + background: #f3f6f8; + margin-right:20px; + border-radius: 8px; + padding: 4px 10px; + font-size: 14px; +} +.devui-badge-list { + width: 180px; + padding: 4px 20px; + background: #f3f6f8; + font-size: 14px; + border-radius: 8px; + .devui-badge-list-item { + display: flex; + justify-content: space-between; + align-items: center; + } +} +</style> diff --git a/packages/devui-vue/docs/components/breadcrumb/index.md b/packages/devui-vue/docs/components/breadcrumb/index.md new file mode 100644 index 0000000000000000000000000000000000000000..243c160b98357b89d99788830ec172e90f96cdc4 --- /dev/null +++ b/packages/devui-vue/docs/components/breadcrumb/index.md @@ -0,0 +1,116 @@ +# Breadcrumb 面包屑 + +显示当前页面层级的组件。 + +### 何时使用 + +1. 用户需要了解当前出于什么层级时; +2. 用户需要快速返回之前的层级时; +3. 用户需要导航至与指定层级相同的任意页面时。 + +### 基础面包屑 + +:::demo +```vue +<template> + <d-breadcrumb> + <d-breadcrumb-item to="{ path: '/' }">Homepage</d-breadcrumb-item> + <d-breadcrumb-item> + <a href="/">DevUI</a> + </d-breadcrumb-item> + <d-breadcrumb-item> + <span>Breadcrumb</span> + </d-breadcrumb-item> + </d-breadcrumb> +</template> +``` +::: + +### 传入source + +:::demo +```vue +<template> + <d-breadcrumb :source="source"></d-breadcrumb> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + name: "DBreadcrumbDemoSourceConfig", + setup() { + const source = reactive([ + { title: 'DevUI', link: '/', linkType: 'routerLink', replace: true }, + { title: 'Breadcrumb', link: 'components/breadcrumb/', noNavigation: true } + ]) + return { + source, + } + }, +}) +</script> +``` +::: + +### 可下拉的面包屑【TODO】 +### 自定义分隔符的面包屑 + +:::demo +```vue +<template> + <div> + <d-breadcrumb separatorIcon=">"> + <d-breadcrumb-item> + <a routerLink="/components/zh-cn/get-start">DevUI</a> + </d-breadcrumb-item> + <d-breadcrumb-item> + <span>Breadcrumb</span> + </d-breadcrumb-item> + </d-breadcrumb> + </div> + <div> + <d-breadcrumb> + <template v-slot:separatorIcon> + <span style="color: red">></span> + </template> + <d-breadcrumb-item> + <a routerLink="/components/zh-cn/get-start">DevUI</a> + </d-breadcrumb-item> + <d-breadcrumb-item> + <span>Breadcrumb</span> + </d-breadcrumb-item> + </d-breadcrumb> + </div> +</template> +``` +::: +### API + +### d-breadcrumb 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :-----------: | :------------------------------------: | :--: | :------------------------------------------------- | --------------------------------------------- | +| separatorIcon | [`string`](#自定义分隔符的面包屑) | '/' | 可选,自定义分隔符样式 | [自定义分隔符的面包屑](#自定义分隔符的面包屑) | +| source | [`Array<SourceConfig>`](#SourceConfig) | [] | 可选,面包屑根据配置的 source 按照默认渲染方式显示 | [传入source](#传入source) | + +### d-breadcrumb-item 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :------: | :--------------------------------: | :---: | :-----------------------------------------------------: | :-------------------------------- | +|to | `string/object` | — | 路由跳转对象,同 vue-router 的 to | [基础面包屑](#基础面包屑) | +|replace| `boolean` | false | 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 | [基础面包屑](#基础面包屑) | + +### 接口 & 类型定义 + +### SourceConfig + +```ts +export interface SourceConfig { + title: string; // 显示的名称 + link?: string; // 跳转的路径 + target?: string // 规定在何处打开链接文档 + noNavigation?: boolean; // 链接是否不可跳转,一般用于当前所处位置不可跳转的配置 + linkType?: 'hrefLink' | 'routerLink'; // 链接类型,默认为'hrefLink'方式,可选'hrefLink' 或 'routerLink' + replace: Boolean // 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 +} +``` \ No newline at end of file diff --git a/packages/devui-vue/docs/components/button/index.md b/packages/devui-vue/docs/components/button/index.md new file mode 100644 index 0000000000000000000000000000000000000000..3aa254acc163735d6d6e27b5c5b168b9b3259832 --- /dev/null +++ b/packages/devui-vue/docs/components/button/index.md @@ -0,0 +1,167 @@ +# Button 按钮 + +按钮用于开始一个即时操作。 + +### 何时使用 + +标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。 + +### 主要按钮 + +:::demo + +```vue +<template> + <d-button id="primaryBtn" style="margin-right: 8px">Primary</d-button> + <d-button :disabled="true">Disabled</d-button> +</template> +``` +::: +### 次要按钮 + +:::demo + +```vue +<template> + <d-button btnStyle="common" style="margin-right: 8px">Common</d-button> + <d-button btnStyle="common" :disabled="true">Disabled</d-button> +</template> +``` +::: + +### 左按钮与右按钮 + +:::demo +```vue +<template> + <d-button btnStyle="primary" bsPosition="left">Left</d-button> + <d-button btnStyle="common" bsPosition="right">Right</d-button> +</template> +``` +::: + + +### 警示按钮 +用于标识系统中的关键操作,例如购买场景。 +:::demo +```vue +<template> + <d-button btnStyle="danger" type="submit">Buy</d-button> +</template> +``` +::: + +### 文字按钮 +用于标识系统中的关键操作,例如购买场景。 +:::demo +```vue +<template> + <d-button btnStyle="text" style="margin-right: 20px">Text</d-button> + <d-button btnStyle="text-dark" style="margin-right: 20px">Text dark</d-button> + <d-button btnStyle="text" :disabled="true">Disabled</d-button> +</template> +``` +::: + +### 加载中状态 +(该功能正在开发中) +:::demo +```vue +<template> + <d-button> click me! </d-button> +</template> +``` +::: + +### 自动获得焦点 +通过autofocus设置按钮自动获得焦点。 +:::demo +```vue +<template> + <d-button btnStyle="primary" :bordered="true" :autofocus="true" style="margin-right: 8px"> Confirm </d-button> + <d-button btnStyle="common"> Cancel </d-button> +</template> +``` +::: + +### 图标 + +:::demo +```vue +<template> + <div class="btn-group"> + <d-button icon="add" btnStyle="primary"> New </d-button> + <d-button icon="filter" btnStyle="common"> Filter </d-button> + </div> + <div class="btn-group"> + <d-button icon="add" btnStyle="primary" :disabled="true"> New(disabled) </d-button> + <d-button icon="filter" btnStyle="common" :disabled="true"> Filter(disabled) </d-button> + </div> + <div class="btn-group"> + <d-button icon="connect" btnStyle="text-dark" style="margin-right: 4px"> Link </d-button> + <d-button icon="run" btnStyle="text-dark"> Run </d-button> + </div> + <div class="btn-group"> + <d-button icon="connect" btnStyle="text-dark" style="margin-right: 4px" :disabled="true"> Link(disabled) </d-button> + <d-button icon="run" btnStyle="text-dark" :disabled="true"> Run(disabled) </d-button> + </div> + <div class="btn-group"> + <d-button icon="add" btnStyle="text-dark" title="add"></d-button> + <d-button icon="delete" btnStyle="text-dark" title="delete"></d-button> + </div> + <div class="btn-group"> + <d-button icon="add" btnStyle="text-dark" :disabled="true" title="add"></d-button> + <d-button icon="delete" btnStyle="text-dark" :disabled="true" title="delete"></d-button> + </div> + <div class="btn-group"> + <d-button btnStyle="common" class="rightIcon" bsSize="xs"> + Click me + <span class="icon-chevron-down"></span> + </d-button> + </div> + <div class="btn-group"> + <d-button btnStyle="text-dark" class="rightIcon"> + Click me + <span class="icon-chevron-down"></span> + </d-button> + </div> +</template> +<style> +.btn-group { + margin-bottom: 20px; +} + +.btn-group .devui-btn-host { + margin-right: 8px; +} + +.icon-chevron-down { + display: inline-block; + vertical-align: middle; + position: relative; + top: -0.1em; +} + +</style> +``` +::: + +### API +d-button 参数 +| 参数 | 类型 | 默认 | 说明 | +| :-------: | :----------------------------------------------------------: | :-------: | :------------------------------- | +| type | `'button' \| 'submit' \| 'reset'` | 'button' | 可选,按钮类型 | +| btnStyle | `'common' \| 'primary' \| 'text' \| 'text-dark' \| 'danger'` | 'primary' | 可选,按钮风格 | +| position | `'left' \| 'right' \| 'default'` | 'default' | 可选,按钮位置 | +| size | `'lg' \| 'md' \| 'sm' \| 'xs'` | 'md' | 可选,按钮大小 | +| bordered | `boolean` | false | 可选,是否有边框 | +| icon | `string` | -- | 可选,点击背景触发的事件 | +| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | +| disabled | `boolean` | false | 可选,是否禁用button | +| autofocus | `boolean` | false | 可选,按钮加载时是否自动获得焦点 | + +d-button 事件 +| 参数 | 类型 | 默认 | 说明 | +| :-----: | :---------------------------: | :---: | :------------- | +| onClick | `(event: MouseEvent) => void` | -- | 可选,点击事件 | + diff --git a/packages/devui-vue/docs/components/card/index.md b/packages/devui-vue/docs/components/card/index.md new file mode 100644 index 0000000000000000000000000000000000000000..e29350a2526ecc9ed487273c85a3045a615bc904 --- /dev/null +++ b/packages/devui-vue/docs/components/card/index.md @@ -0,0 +1,309 @@ +# Card 卡片 + +通用卡片容器。 + +### 何时使用 + +基础卡片容器,其中可包含文字,列表,图片,段落,用于概览展示时。 + + +### 基本用法 + +:::demo +```vue +<template> + <d-card class="d-card"> + <template #cardAvatar> + <d-avatar name="DevUI"></d-avatar> + </template> + <template #cardTitle> + DEVUI Course + </template> + <template #cardSubtitle class="icon"> + <d-icon name="company-member"></d-icon><span>DevUI</span> + </template> + <template #cardContent> + DEVUI is a free open-source and common solution for the front end of enterprise mid- and back-end products. Its design values are basedon... + </template> + <template #cardActions> + <div class="card-block"> + <d-icon name="like"></d-icon ><span>12</span> + </div> + <div class="card-block"> + <d-icon name="star-o"></d-icon ><span>8</span> + </div> + <div class="card-block"> + <d-icon name="message"></d-icon ><span>8</span> + </div> + </template> + </d-card> +</template> +<style lang="scss"> +@import '@devui-design/icons/icomoon/devui-icon.css' +.icon { + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; +} +.icon + span { + vertical-align: middle; +} +.card-block { + margin-right: 16px; + i{ + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + i + span { + vertical-align: middle; + } +} +.d-card { + cursor: pointer; + transition: + box-shadow .3s cubic-bezier(.645,.045,.355,1), + transform .3s cubic-bezier(.645,.045,.355,1); + &:hover { + box-shadow: 0 4px 16px 0 rgba(0,0,0,.1); + transform: translateY(-5px); + } +} +.card-container { + width: 350px; +} +.action-text { + color: #8a8e99; +} +</style> +``` +::: + +### 使用图片 + +:::demo +```vue + +<template> + <d-card class="d-card" :src="'https://devui.design/components/assets/image1.png'"> + <template #cardAvatar> + <d-avatar name="DevUI"></d-avatar> + </template> + <template #cardTitle> + DEVUI Course + </template> + <template #cardSubtitle class="icon"> + <d-icon name="company-member"></d-icon><span>DevUI</span> + </template> + <template #cardContent> + DEVUI is a free open-source and common solution for the front end of enterprise mid- and back-end products. Its design values are basedon... + </template> + <template #cardActions> + <div class="card-block"> + <d-icon name="like"></d-icon ><span>12</span> + </div> + <div class="card-block"> + <d-icon name="star-o"></d-icon ><span>8</span> + </div> + <div class="card-block"> + <d-icon name="message"></d-icon ><span>8</span> + </div> + </template> + </d-card> +</template> +<style lang="scss"> + @import '@devui-design/icons/icomoon/devui-icon.css' + .icon { + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + .icon + span { + vertical-align: middle; + } + .card-block { + margin-right: 16px; + i{ + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + i + span { + vertical-align: middle; + } + } + .d-card { + cursor: pointer; + transition: + box-shadow .3s cubic-bezier(.645,.045,.355,1), + transform .3s cubic-bezier(.645,.045,.355,1); + &:hover { + box-shadow: 0 4px 16px 0 rgba(0,0,0,.1); + transform: translateY(-5px); + } + } + .card-container { + width: 350px; + } + img { + max-width: none; + } + .action-text { + color: #8a8e99; + } +</style> + +``` +::: + +### 自定义区域 + +通过align可设置操作区域对齐方式:起始对齐、尾部对齐、拉伸对齐。 + +:::demo +```vue +<template> + <d-card class="d-card" :align="'spaceBetween'"> + <div class="custom-avatar"> + <d-avatar imgSrc="https://devui.design/components/assets/logo.svg" width=48 height=48 :isRound="false"></d-avatar> + <div class="icon-star-o custom-star-action"></div> + </div> + <template v-slot:cardTitle> + DEVUI Course + </template> + <template v-slot:cardActions> + <div class="action-text">Updated at Otc 15 16:20</div> + <div> + <d-icon name="like"></d-icon > + <d-icon name="more-operate"></d-icon > + </div> + </template> + </d-card> +</template> +<style lang="scss"> + @import '@devui-design/icons/icomoon/devui-icon.css' + .icon { + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + .icon + span { + vertical-align: middle; + } + .card-block { + margin-right: 16px; + i{ + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + i + span { + vertical-align: middle; + } + } + .d-card { + cursor: pointer; + transition: + box-shadow .3s cubic-bezier(.645,.045,.355,1), + transform .3s cubic-bezier(.645,.045,.355,1); + &:hover { + box-shadow: 0 4px 16px 0 rgba(0,0,0,.1); + transform: translateY(-5px); + } + } + .card-container { + width: 350px; + } + img { + max-width: none; + } + .action-text { + color: #8a8e99; + } + .custom-avatar { + display: flex; + justify-content: space-between; + margin-bottom: 16px; + .custom-star-action { + font-size: 20px; + cursor: pointer; + } + } +</style> +``` +::: + +<style lang="scss"> +@import '@devui-design/icons/icomoon/devui-icon.css'; +.icon { + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; +} +.icon + span { + vertical-align: middle; +} +.card-block { + margin-right: 16px; + i{ + cursor: pointer; + font-size: 16px; + margin-right: 8px; + vertical-align: middle; + } + i + span { + vertical-align: middle; + } +} +.d-card { + cursor: pointer; + transition: + box-shadow .3s cubic-bezier(.645,.045,.355,1), + transform .3s cubic-bezier(.645,.045,.355,1); + &:hover { + box-shadow: 0 4px 16px 0 rgba(0,0,0,.1); + transform: translateY(-5px); + } +} +.card-container { + width: 350px; +} +img { + max-width: none; +} +.action-text { + color: #8a8e99; +} +.custom-avatar { + display: flex; + justify-content: space-between; + margin-bottom: 16px; + .custom-star-action { + font-size: 20px; + cursor: pointer; + } +} +</style> + +### 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :----------------------- | -------------------------------- | +| src | `string` | '' | 可选,图片路径 | [使用图片](#使用图片) | +| align | `'start'\|'end'\|'spaceBetween'\|` | `'start'` | 可选,操作区域对齐方式,分别对应起始对齐,尾部对齐,拉伸对齐 | [自定义区域](#自定义区域) | + +### 插槽 +两种方式使用:`v-slot:cardTitle` 或者具名插槽`#cardTitle` +| 名称 | 描述 | +| :---------: | :------: | +| cardAvatar | 头像区域,用作头像等图片展示 | +| cardTitle | 卡片的主要内容描述,一般定义为卡片名称 | +| cardSubtitle | 对标题的补充,可包含标签等信息 | +| cardActions | 决策作用,可以包含操作文本或者操作图标 | diff --git a/packages/devui-vue/docs/components/carousel/index.md b/packages/devui-vue/docs/components/carousel/index.md new file mode 100644 index 0000000000000000000000000000000000000000..c1f645078840da51f8b7ca494f2237527bec32da --- /dev/null +++ b/packages/devui-vue/docs/components/carousel/index.md @@ -0,0 +1,192 @@ +# Carousel 走马灯 + +一组轮播的区域。 + +### 何时使用 + +1. 用于展示图片或者卡片。 + +### 基本用法 + +:::demo + +```vue +<template> + <d-carousel height="200px"> + <d-carousel-item v-for="item in items" :key="item">{{ item }}</d-carousel-item> + </d-carousel> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const items = ref<string[]>(['page 1', 'page 2', 'page 3', 'page 4']) + return { + items + } + } +}) +</script> +<style> +.d-carousel-item { + text-align: center; + line-height: 200px; + background: var(--devui-global-bg, #f3f6f8); +} +</style> +``` + +::: + +### 指示器&切换箭头 + +arrowTrigger 设为 always 可以使箭头永久显示,dotTrigger 设为 hover 可以使 hover 到点上就切换。 + +:::demo + +```vue +<template> + <d-carousel height="200px" arrowTrigger="always" dotTrigger="hover"> + <d-carousel-item v-for="item in items" :key="item">{{ item }}</d-carousel-item> + </d-carousel> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const items = ref<string[]>(['page 1', 'page 2', 'page 3', 'page 4']) + return { + items + } + } +}) +</script> +<style> +.d-carousel-item { + text-align: center; + line-height: 200px; + background: var(--devui-global-bg, #f3f6f8); +} +</style> +``` + +::: + +### 自动轮播 + +:::demo + +```vue +<template> + <d-carousel height="200px" autoplay :autoplaySpeed="3000"> + <d-carousel-item v-for="item in items" :key="item">{{ item }}</d-carousel-item> + </d-carousel> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const items = ref<string[]>(['page 1', 'page 2', 'page 3', 'page 4']) + return { + items + } + } +}) +</script> +<style> +.d-carousel-item { + text-align: center; + line-height: 200px; + background: var(--devui-global-bg, #f3f6f8); +} +</style> +``` + +::: + +### 自定义操作 + +:::demo + +```vue +<template> + <d-carousel ref="carousel" height="200px" arrowTrigger="never"> + <d-carousel-item v-for="item in items" :key="item">{{ item }}</d-carousel-item> + </d-carousel> + <div class="carousel-demo-operate"> + <d-button bsStyle="common" @click="onPrev">上一张</d-button> + <d-button bsStyle="primary" @click="onNext">下一张</d-button> + <d-button bsStyle="common" @click="onGoFirst">第一张</d-button> + </div> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const items = ref<string[]>(['page 1', 'page 2', 'page 3', 'page 4']) + const carousel = ref() + const onPrev = () => { + carousel.value?.prev?.() + } + const onNext = () => { + carousel.value?.next?.() + } + const onGoFirst = () => { + carousel.value?.goto?.(0) + } + return { + items, + carousel, + onPrev, + onNext, + onGoFirst + } + } +}) +</script> +<style> +.carousel-demo-operate { + margin-top: 10px; + display: flex; + align-items: center; +} +.carousel-demo-operate .devui-btn-host { + margin-right: 20px; +} +</style> +``` + +::: + +### API + +#### 参数 + +| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | +| :-----------: | :--------------------------: | :------: | :----------------------------------------------------------------- | ----------------------------------- | +| arrowTrigger | `'hover'\|'never'\|'always'` | 'hover' | 可选,指定切换箭头显示方式 | [指示器&切换箭头](#指示器-切换箭头) | +| autoplay | `boolean` | false | 可选,是否自动轮播 | [自动轮播](#自动轮播) | +| autoplaySpeed | `number` | 3000 | 可选,配合`autoplay`使用,自动轮播速度,单位 ms | [自动轮播](#自动轮播) | +| height | `string` | '100%' | 可选,轮播容器高度 | [基本用法](#基本用法) | +| showDots | `boolean` | true | 可选,是否显示面板指示器 | [自动轮播](#自动轮播) | +| dotPosition | `'top'\|'bottom'` | 'bottom' | 可选,面板指示器位置 | [指示器&切换箭头](#指示器-切换箭头) | +| dotTrigger | `'click'\|'hover'` | 'click' | 可选,指示器触发轮播方式 | [指示器&切换箭头](#指示器-切换箭头) | +| activeIndex | `number` | 0 | 可选,初始化激活卡片索引,从 0 开始,支持`[(activeIndex)]`双向绑定 | [基本用法](#基本用法) | + +#### 事件 + +| 事件 | 类型 | 描述 | 跳转 Demo | +| :---------------: | :--------------------: | :---------------------------------------: | --------------------- | +| activeIndexChange | `EventEmitter<number>` | 卡片切换时,返回当前卡片的索引,从 0 开始 | [基本用法](#基本用法) | + +#### 方法 + +| 方法 | 描述 | 跳转 Demo | +| :---------: | :---------------------------------- | :------------------------ | +| prev() | 切换到上一张卡片 | [自定义操作](#自定义操作) | +| next() | 切换到下一张卡片 | [自定义操作](#自定义操作) | +| goTo(index) | 切换到指定索引的卡片,索引从 0 开始 | [自定义操作](#自定义操作) | diff --git a/packages/devui-vue/docs/components/cascader/index.md b/packages/devui-vue/docs/components/cascader/index.md new file mode 100644 index 0000000000000000000000000000000000000000..1c310e940526131358058a60a2b1f1b369876ce8 --- /dev/null +++ b/packages/devui-vue/docs/components/cascader/index.md @@ -0,0 +1,151 @@ +# Cascader 级联菜单 + +下拉级联菜单。 + +### 何时使用 + +1. 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。 +2. 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。 + +### 基本用法 +:::demo + +```vue +<template> + <d-cascader :options="options" placeholder="请选择" style="width: 200px"></d-cascader> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + setup() { + const options = reactive([ + { + label: 'option1', + value : 1, + children: [ + { + label: 'option1-1', + value : 4, + children: [ + { + label: 'option1-1-1', + value : 8, + children: [] + }, + { + label: 'option1-1-2', + value : 9, + children: [ + { + label: 'option1-1-2-1', + value : 81, + isLeaf: true + } + ], + } + ] + }, + { + label: 'option1-2', + value : 41, + isLeaf: true + }, + { + label: 'option1-3', + value : 42, + isLeaf: true + }, + { + label: 'option1-4', + value : 43, + isLeaf: true + } + ], + }, + { + label: 'option2', + value : 2, + children: [ + { + label: 'option2-1', + value : 5, + children: [ + { + label: 'option2-1-1', + value : 51, + isLeaf: true + }, + { + label: 'option2-1-2', + value : 61, + isLeaf: true, + disabled: true + } + ] + }, + { + label: 'option2-2', + value : 6, + children: [ + { + label: 'option2-2-1', + value : 512, + isLeaf: true + }, + { + label: 'option2-2-2', + value : 611, + isLeaf: true + } + ] + }, + { + label: 'option2-3', + value : 712, + isLeaf: true + } + ] + }, + { + label: 'option3', + value : 3, + children: [], + isLeaf: true, + disabled: true + } + ]) + return { + options + } + }, +}) +</script> +``` + +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :--------: | :------: | :-------: | :---------------------- | --------------------------------- | --------- | +| options | [`CascaderItem[]`](#CascaderItem) | [] | 必选,级联器的菜单信息 | [基本用法](#基本用法) | | +| placeholder | `string` | '' | 可选,没有选择时的输入框展示信息 | [基本用法](#基本用法) | | + +### 接口 & 类型定义 + +- + +#### CascaderItem +```ts +interface CascaderItem { + label: string; + value: number | string; + isLeaf?: boolean; + children?: CascaderItem[]; + disabled?: boolean; + icon?: string; + // 用户可以传入自定义属性,并在dropDownItemTemplate中使用 + [prop: string]: any; +} +``` \ No newline at end of file diff --git a/packages/devui-vue/docs/components/checkbox/index.md b/packages/devui-vue/docs/components/checkbox/index.md new file mode 100644 index 0000000000000000000000000000000000000000..c54b533366b2cfce131eaf766d7250763f81c7b7 --- /dev/null +++ b/packages/devui-vue/docs/components/checkbox/index.md @@ -0,0 +1,382 @@ +# CheckBox 复选框 + +多选框。 + +### 何时使用 + +1. 在一组选项中进行多项选择; +2. 单独使用可以表示在两个状态之间切换,可以和提交操作结合。 + +### 基本用法 + +:::demo + +```vue +<template> + <div class="checkbox-basic-demo"> + <d-checkbox label="Checked" :isShowTitle="false" v-model="checked" /> + <d-checkbox label="Not checked" :isShowTitle="false" v-model="unchecked" /> + <d-checkbox + label="Custom title" + :isShowTitle="true" + title="my title" + v-model="unchecked2" + /> + <d-checkbox + label="No Animation" + :isShowTitle="false" + v-model="checked2" + :showAnimation="false" + /> + <d-checkbox + label="Disabled" + :isShowTitle="false" + v-model="checked" + :disabled="true" + /> + <d-checkbox + label="Disabled" + :isShowTitle="false" + v-model="unchecked" + :disabled="true" + /> + <d-checkbox + label="Half-checked" + :isShowTitle="false" + :halfchecked="halfCheck" + v-model="allCheck" + @change="onHalfCheckboxChange" + /> + <d-checkbox + label="Half-checked" + :isShowTitle="false" + :halfchecked="halfCheck" + v-model="allCheck" + @change="onHalfCheckboxChange" + :disabled="true" + /> + <d-checkbox + label="Custom color" + :isShowTitle="false" + v-model="customCheck" + color="RGB(255, 193, 7)" + /> + <d-checkbox + label="Half-checked" + :isShowTitle="false" + :halfchecked="halfCheck2" + v-model="allCheck2" + @change="onHalfCheckboxChange2" + color="RGB(255, 193, 7)" + /> + <d-checkbox :isShowTitle="false" v-model="unchecked3"> + <div class="inline-row" style="display: inline-flex"> + <d-select + v-model="value1" + :options="[1, 2, 3, 4]" + size="sm" + @click="handleChange" + ></d-select> + <span>Custom label template</span> + </div> + </d-checkbox> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup() { + const checked = ref(true) + const checked2 = ref(true) + const unchecked = ref(false) + const unchecked2 = ref(false) + const unchecked3 = ref(false) + const halfCheck = ref(true) + const halfCheck2 = ref(true) + const allCheck = ref(false) + const allCheck2 = ref(false) + const customCheck = ref(true) + const value1 = ref(null) + + const onHalfCheckboxChange = (value) => { + halfCheck.value = !allCheck.value + console.log('halfCheckbox checked:', value) + } + const onHalfCheckboxChange2 = (value) => { + halfCheck2.value = !allCheck2.value + console.log('halfCheckbox checked:', value) + } + const handleChange = ($event) => { + $event.preventDefault() + $event.stopPropagation() + } + return { + checked, + checked2, + unchecked, + unchecked2, + unchecked3, + halfCheck, + halfCheck2, + allCheck, + allCheck2, + onHalfCheckboxChange, + customCheck, + onHalfCheckboxChange2, + handleChange, + value1, + } + }, +}) +</script> +<style> +.checkbox-basic-demo .devui-checkbox { + margin-bottom: 10px; +} +.checkbox-basic-demo .inline-row .devui-select { + width: 150px; + margin-right: 10px; +} +</style> +``` + +::: + +### 使用 CheckBoxGroup + +:::demo + +```vue +<template> + <div class="checkbox-group-demo"> + <h4 class="title">Input Object Array</h4> + <d-checkbox-group + v-model="values1" + :options="options1" + direction="row" + ></d-checkbox-group> + + <h4 class="title">Input String Array</h4> + <d-checkbox-group + v-model="values2" + :options="options2" + :isShowTitle="false" + direction="row" + ></d-checkbox-group> + + <h4 class="title">Disabled Group</h4> + <d-checkbox-group + v-model="values2" + :options="options2" + :isShowTitle="false" + direction="row" + :disabled="true" + ></d-checkbox-group> + + <h4 class="title">Custom Selected Color</h4> + <d-checkbox-group + v-model="values3" + :options="options3" + :isShowTitle="false" + direction="row" + color="RGB(255, 193, 7)" + ></d-checkbox-group> + + <h4 class="title">Set showAnimation false</h4> + <d-checkbox-group + v-model="values4" + :options="options3" + :isShowTitle="false" + direction="row" + :showAnimation="false" + ></d-checkbox-group> + + <h4 class="title">Multi-line Checkbox</h4> + <d-checkbox-group + v-model="values5" + :options="options5" + :isShowTitle="false" + direction="row" + :itemWidth="94" + ></d-checkbox-group> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const options1 = ref([ + { name: 'data1', disabled: 'true', value: 1, id: 1 }, + { name: 'data2', value: 2, id: 2 }, + { name: 'data3', value: 3, id: 3 }, + ]) + const values1 = ref([{ name: 'data2', value: 2, id: 2 }]) + const options2 = ref([ + 'data1', + 'data2', + 'data3', + 'data4', + 'data5', + 'data6', + 'data7', + ]) + const values2 = ref(['data1', 'data2']) + const options3 = ref([ + 'data1', + 'data2', + 'data3', + 'data4', + 'data5', + 'data6', + 'data7', + ]) + const values3 = ref(['data1', 'data2']) + const values4 = ref(['data2', 'data3']) + const options5 = ref([ + 'data00000000000000001', + 'data2', + 'data3', + 'data4', + 'data5', + 'data6', + 'data7', + 'data8', + 'data9', + 'data10', + 'data11', + 'data12', + 'data13', + 'data14', + 'data15', + ]) + const values5 = ref(['data2', 'data3']) + return { + options1, + values1, + options2, + values2, + options3, + values3, + values4, + options5, + values5, + } + }, +}) +</script> +<style> +.checkbox-group-demo .title { + margin: 20px 0; +} +</style> +``` + +::: + +### checkbox 根据条件终止切换状态 + +根据条件判断,label 为'条件判断回调禁止选中'的 checkbox 终止切换状态。 +:::demo + +```vue +<template> + <div style="margin-bottom: 10px"> + <d-checkbox + label="Conditional Callback Allowed" + :isShowTitle="false" + v-model="checked1" + @change="onCheckbox1Change" + :beforeChange="beforeChange" + /> + </div> + <div> + <d-checkbox + label="Conditional Judgment Callback Interception Selected" + :isShowTitle="false" + v-model="checked2" + @change="onCheckbox1Change" + :beforeChange="beforeChange" + /> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup() { + const checked1 = ref(true) + const checked2 = ref(false) + + const onCheckbox1Change = (value) => { + console.log('checkbox1 checked:', value) + } + + const beforeChange = (isChecked, label) => { + return label === 'Conditional Callback Allowed' + } + return { + checked1, + checked2, + onCheckbox1Change, + beforeChange, + } + }, +}) +</script> +``` + +::: + +### checkbox-group 根据条件终止切换状态 + +选项包含'拦截'字段的 checkbox 无法切换状态。 +:::demo + +```vue +<template> + <div> + <d-checkbox-group + v-model="values" + :options="options" + :isShowTitle="false" + direction="row" + @change="onCheckbox1Change" + :beforeChange="beforeChange" + /> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const options = ref([ + 'data1', + 'data2', + 'intercept', + 'intercept2', + 'data5', + 'data6', + 'data7', + ]) + const values = ref(['data2', 'intercept']) + const onCheckbox1Change = (value) => { + console.log('checkbox1 checked:', value) + } + + const beforeChange = (isChecked, label) => { + return !label.includes('intercept') + } + + return { + options, + values, + onCheckbox1Change, + beforeChange, + } + }, +}) +</script> +``` + +::: diff --git a/packages/devui-vue/docs/components/date-picker/index.md b/packages/devui-vue/docs/components/date-picker/index.md new file mode 100644 index 0000000000000000000000000000000000000000..bbc53a7a363c1e079092e051a70ad47bfe83926e --- /dev/null +++ b/packages/devui-vue/docs/components/date-picker/index.md @@ -0,0 +1,125 @@ +# DatePicker 日期选择器 + +输入或选择日期的组件。 + +### 何时使用 + +当用户需要输入一个日期时;需要点击标准输入框,弹出日期面板进行选择时。 + +<script lang="ts"> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup() { + + const eventValue = ref<string>('') + const handleEventValue = (val: string) => { + eventValue.value = val + } + + return { + eventValue, + handleEventValue, + } + } +}) +</script> + +### 属性 auto-close + +|项目|说明| +|----|----| +|名称|auto-close / autoClose| +|类型|boolean| +|必填|否| +|默认|false| +|说明|选择日期后,是否自动关闭日期面板| + +```vue +<!-- 开启 --> +<d-datepicker auto-close /> +<d-datepicker :auto-close="true" /> + +<!-- 关闭 --> +<d-datepicker /> +<d-datepicker :auto-close="false" /> +``` + +<d-datepicker auto-close /> +<d-datepicker /> + +### 属性 range + +|项目|说明| +|----|----| +|名称|range| +|类型|boolean| +|必填|否| +|默认|false| +|说明|是否开启区间选择| + +```vue +<!-- 开启 --> +<d-datepicker range /> +<d-datepicker :range="true" /> + +<!-- 关闭 --> +<d-datepicker /> +<d-datepicker :range="false" /> +``` + +<d-datepicker range /> + +### 属性 format + +|项目|类型| +|----|----| +|名称|format| +|类型|string| +|必填|否| +|默认|y/MM/dd| +|说明|日期值格式| + +<d-datepicker format="yyyy-MM-dd hh:mm:ss" /> +<d-datepicker format="yy-MM-dd" range /> + +```vue +<d-datepicker format="yyyy-MM-dd hh:mm:ss" /> +<d-datepicker format="yy-MM-dd" range /> +``` + +**日期格式化字符** + +|字符|说明|规则| +|----|----|----| +|y, yy, yyyy|year|使用`yy`时,只显示后2位年份,其他情况显示4位年份。比如`yy/MM/dd -> 21/01/02`, `y/MM/dd -> 2021/01/02`| +|M,MM|month|使用`MM`时,一位数数字左侧自动补`0`。比如`y/MM/dd -> 2021/01/02`,`y/M/d -> 2021/1/2`| +|d,dd|date|规则同`M`| +|h,hh|hour|规则同`M`;使用24小时表示。| +|m,mm|minute|规则同`M`| +|s,ss|second|规则同`M`| + +### 属性 range-spliter + +|项目|类型| +|----|----| +|名称|range-spliter / rangeSpliter| +|类型|string| +|必填|否| +|默认|-| +|说明|在区间选择模式下,分隔起止时间的字符。| + +```vue +<d-datepicker range range-spliter="至" /> +``` + +<d-datepicker range range-spliter="至" /> + +### 事件 selectedDateChange + +```vue +<input :value="eventValue" readonly> +<d-datepicker :selected-date-change="handleEventValue" /> +``` + +<input :value="eventValue" readonly> +<d-datepicker :selected-date-change="handleEventValue" /> \ No newline at end of file diff --git a/packages/devui-vue/docs/components/dragdrop/index.md b/packages/devui-vue/docs/components/dragdrop/index.md new file mode 100644 index 0000000000000000000000000000000000000000..f37a25bf6a4c2eb7eb87088f440b4b4bed5343d5 --- /dev/null +++ b/packages/devui-vue/docs/components/dragdrop/index.md @@ -0,0 +1,117 @@ +# Dragdrop 拖拽 + +拖拽组件。 + +### 何时使用 + +当需要使用数个操作步骤,且步骤的顺序需要灵活调整时。 + +### 基本用法 + +:::demo 从一个container拖动到另外一个container。 + +```vue +<template> + <div class="dragdrop-card-container"> + <div class="dragdrop-card"> + <div class="dragdrop-card-header">Draggable Item</div> + <div class="dragdrop-card-block"> + <div id="draggable-item" class="draggable-item" v-d-draggable="{ + dragScope: 'default-css', + dragData: { item: 'item', parent: 'list1' }, + }">VSCode</div> + </div> + </div> + <div class="dragdrop-card" v-d-droppable> + <div class="dragdrop-card-header">Drop Area</div> + <div class="dragdrop-card-block"> + + </div> + </div> + </div> +</template> + +<script> +import { defineComponent } from 'vue' + +export default defineComponent({ + setup() { + return { + msg: 'Dragdrop 拖拽 组件文档示例' + } + } +}) +</script> + +<style> +.dragdrop-card-container { + display: flex; +} + +.dragdrop-card { + padding: 12px; + margin-right: 12px; + border: 1px solid #dfe1e6; + border: 1px solid var(--devui-dividing-line,#dfe1e6); +} + +.dragdrop-card .dragdrop-card-header { + padding-bottom: 12px; + font-size: 12px; + font-size: var(--devui-font-size,12px); +} + +.draggable-item { + padding: 0 16px; + height: 30px; + border: 1px solid #5e7ce0; + border: 1px solid var(--devui-brand,#5e7ce0); + color: #fff; + color: var(--devui-light-text,#fff); + margin-bottom: 5px; + line-height: 1.5; + background-color: #5e7ce0; + background-color: var(--devui-brand,#5e7ce0); + display: flex; + align-items: center; +} +</style> +``` + +::: + +### d-draggable 指令 + +d-draggable 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| dragData | any | -- | 可选,转递给 DropEvent事件的数据 | [基本用法](#基本用法) | | +| dragScope | string \| Array\<string\> | 'default' | 可选,限制 drop 的位置,必须匹配对应的 dropScope | [基本用法](#基本用法) | | + +d-draggable 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| dragStartEvent | EventEmitter\<DragEvent\> | 开始拖动的 DragStart 事件 | [基本用法](#基本用法) | +| dragEndEvent | EventEmitter\<DragEvent\> | 拖动结束的 DragEnd 事件 | [基本用法](#基本用法) | +| dropEndEvent | EventEmitter\<DragEvent\> | 放置结束的 Drop 事件 | [基本用法](#基本用法) | + +### d-droppable 指令 + +d-droppable 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| dropScope | string | Array\<string\> | 'default' | 可选,限制 drop 的区域,对应 dragScope | [基本用法](#基本用法) | | + +d-droppable 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| dragEnterEvent | EventEmitter\<DragEvent\> | drag 元素进入的 dragenter 事件 | [基本用法](#基本用法) | +| dragOverEvent | EventEmitter\<DragEvent\> | drag 元素在 drop 区域上的 dragover 事件 | [基本用法](#基本用法) | +| dragLeaveEvent | EventEmitter\<DragEvent\> | drag 元素离开的 dragleave 事件 | [基本用法](#基本用法) | +| dropEvent | EventEmitter\<DropEvent\> | 放置一个元素, 接收的事件,其中 nativeEvent 表示原生的 drop 事件,其他见定义注释 | [基本用法](#基本用法) | + + diff --git a/packages/devui-vue/docs/components/drawer/index.md b/packages/devui-vue/docs/components/drawer/index.md new file mode 100644 index 0000000000000000000000000000000000000000..55e0bd5aebe3ae82a1ce528afceeff0db013c35f --- /dev/null +++ b/packages/devui-vue/docs/components/drawer/index.md @@ -0,0 +1,80 @@ +# Drawer 抽屉板 + +屏幕边缘滑出的浮层面板组件。 + +### 何时使用 + +1. 抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到到原任务。 +2. 当需要一个附加的面板来控制父窗体内容,这个面板在需要时呼出。比如,控制界面展示样式,往界面中添加内容。 +3. 当需要在当前任务流中插入临时任务,创建或预览附加内容。比如展示协议条款,创建子对象。 + +### 基本用法 + +<h4>基本用法,可以控制全屏、关闭和设置宽度。</h4> + +:::demo + +```vue +<template> + <d-button @click="drawerShow"> drawer {{ btnName }} </d-button> + <d-drawer + v-if="isDrawerShow" + v-model:visible="isDrawerShow" + :width="drawerWidth" + :isCover="isCover" + position="right" + @close="drawerClose" + @afterOpened="drawerAfterOpened" + /> +</template> +<script> +import { ref } from 'vue' + +export default ({ + setup() { + let isDrawerShow = ref(false) + let btnName = ref('close') + let drawerWidth = ref('15vw') + let isCover = ref(true) + + const drawerShow = () => { + isDrawerShow.value = true + btnName.value = 'open' + } + + const drawerClose = () => { + btnName.value = 'close' + } + + const drawerAfterOpened = () => { + console.log('open') + } + + return { + isDrawerShow, + btnName, + drawerWidth, + drawerShow, + drawerClose, + drawerAfterOpened, + isCover, + } + } +}) +</script> +``` + +::: + +### 参数及API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | +| v-model:visible | `Boolean` | `false` | 必选,设置抽屉板是否可见 | [基本用法](#基本用法) | +| width | `String` | `300px` | 可选,设置抽屉板宽度 | [基本用法](#基本用法) | +| zIndex | `Number` | `1000` | 可选,设置 drawer 的 z-index 值 | [基本用法](#基本用法) | +| isCover | `Boolean` | `true` | 可选,是否有遮罩层 | [基本用法](#基本用法) | +| onClose | `Function` | -- | 可选,关闭 drawer 时候调用 | [基本用法](#基本用法) | +| escKeyCloseable | `Boolean` | `true` | 可选,设置可否通过 esc 按键来关闭 drawer 层 | [基本用法](#基本用法) | +| afterOpened | `Function` | -- | 可选,打开 drawer 后时候调用 | [基本用法](#基本用法) | +| position | `String` | 'right' | 可选,抽屉板出现的位置,'left'或者'right' | [基本用法](#基本用法) | diff --git a/packages/devui-vue/docs/components/dropdown/index.md b/packages/devui-vue/docs/components/dropdown/index.md new file mode 100644 index 0000000000000000000000000000000000000000..296eb3ee9c948040a184e641372a527be92fefe3 --- /dev/null +++ b/packages/devui-vue/docs/components/dropdown/index.md @@ -0,0 +1,134 @@ +# Dropdown 下拉菜单 +按下弹出列表组件。 + +### 何时使用 +当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。 + + + +### 基本用法 + +:::demo + +```vue +<template> + <div style="display:flex"> + 触发方式: + <d-radio-group css-style="row" v-model="trigger"> + <d-radio v-for="item in triggerList" :key="item" :value="item"> + {{ item }} + </d-radio> + </d-radio-group> + </div> + <div style="display:flex"> + 关闭区域: + <d-radio-group css-style="row" v-model="closeScope"> + <d-radio v-for="item in closeScopeAreas" :key="item" :value="item"> + {{ item }} + </d-radio> + </d-radio-group> + </div> + + <div style="display:flex"> + 仅当鼠标从菜单移除时才关闭: + <d-switch v-model:checked="closeOnMouseLeaveMenu"></d-switch> + </div> + + <div style="display:flex"> + 动画开关: + <d-switch v-model:checked="showAnimation"></d-switch> + </div> + + <d-button ref="origin" style="margin-top: 20px; margin-right: 10px">More</d-button> + <d-button + v-show="trigger === 'manually'" + @click="isOpen = !isOpen" + > + {{!isOpen ? 'show dropdown' : 'close dropdown'}} + </d-button> + <d-dropdown + :origin="origin" + :isOpen="isOpen" + :trigger="trigger" + :closeScope="closeScope" + :closeOnMouseLeaveMenu="closeOnMouseLeaveMenu" + :showAnimation="showAnimation" + > + <ul class="devui-dropdown-menu" role="menu"> + <li role="menuitem"> + <a class="devui-dropdown-item">Item 1</a> + </li> + <li class="disabled" role="menuitem"> + <a class="devui-dropdown-item disabled">Item 2</a> + </li> + <li role="menuitem"> + <a class="devui-dropdown-item">Item 3</a> + </li> + <li role="menuitem"> + <a class="devui-dropdown-item">Item 4</a> + </li> + </ul> + </d-dropdown> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + return { + origin: ref(), + isOpen: ref(false), + trigger: ref('click'), + triggerList: ['click', 'hover', 'manually'], + + closeScope: ref('blank'), + closeScopeAreas: ['all', 'blank', 'none'], + closeOnMouseLeaveMenu: ref(false), + showAnimation: ref(true) + } + } +}) +</script> + +<style> +ul.devui-dropdown-menu{ + padding-left: 0; +} +.devui-dropdown-menu li { + padding-left: 0; +} + +.devui-dropdown-menu a { + color: unset; +} +.devui-dropdown-menu a:hover { + text-decoration: none !important; +} + +</style> +``` +::: + +### d-dropdown + +d-dropdown 参数 + +| 参数 | 类型 | 默认 | 说明 | +| --------------------- | ------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------- | +| origin | `Element \| ComponentPublicInstance` | 无 | 必选,必须指定 dropdown 的关联元素 | +| isOpen | `boolean` | `false` | 可选,可以显示指定 dropdown 是否打开 | +| disabled | `boolean` | `false` | 可选,设置为 true 禁用 dropdown | +| trigger | `TriggerType` | `click` | 可选,dropdown 触发方式, click 为点击,hover 为悬停(也包含点击)、manually 为完全手动控制 | +| closeScope | `CloseScopeArea` | `all` | 可选,点击关闭区域,blank 点击非菜单空白才关闭, all 点击菜单内外都关闭,none 菜单内外均不关闭仅下拉按键可以关闭 | +| closeOnMouseLeaveMenu | `boolean` | `false` | 可选,是否进入菜单后离开菜单的时候关闭菜单 | +| showAnimation | `boolean` | `true` | 可选,是否开启动画 | + +TriggerType 类型 +```typescript +type TriggerType = 'click' | 'hover' | 'manually'; +``` + +CloseScopeArea 类型 +```typescript +type CloseScopeArea = 'all' | 'blank' | 'none'; +``` \ No newline at end of file diff --git a/packages/devui-vue/docs/components/editable-select/index.md b/packages/devui-vue/docs/components/editable-select/index.md new file mode 100644 index 0000000000000000000000000000000000000000..559255b671384551025d33fe16c3ca2b4f54bbb7 --- /dev/null +++ b/packages/devui-vue/docs/components/editable-select/index.md @@ -0,0 +1,180 @@ +# EditableSelect 可输入下拉选择框 + +同时支持输入和下拉选择的输入框。 + +### 何时使用 + +当需要同时支持用户输入数据和选择已有数据的时候使用,加入输入联想功能,方便用户搜索已有数据。 + +### 基本用法 + +通过 options 设置数据源。 + +:::demo + +```vue +<template> + <div class="demo-wrap"> + <d-editable-select v-model="value" :options="options" :maxHeight="300"></d-editable-select> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const value = ref("") + const options = ref([ + "C#", + "C", + "C++", + "CPython", + "Java", + "JavaScript", + "Go", + "Python", + "Ruby", + "F#", + "TypeScript", + "SQL", + "LiveScript", + "CoffeeScript" + ]) + return { + value, + options, + } + }, +}) +</script> +<style> +.demo-wrap { + height: 300px; +} +</style> +``` + +::: +### 设置禁用选项 +支持禁用指定数据。 +:::demo +```vue +<template> + <d-editable-select v-model="value" :options="options" :maxHeight="300" disabled></d-editable-select> + <d-editable-select v-model="value" :options="options1" :maxHeight="300" disabledKey="disable"></d-editable-select> +</template> +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const value = ref("") + const options = ref([ + "C#", + "C", + "C++", + "CPython", + "Java", + "JavaScript", + "Go", + "Python", + "Ruby", + "F#", + "TypeScript", + "SQL", + "LiveScript", + "CoffeeScript" + ]) + const options1 = ref([{name: 'c'}, {name: 'C++', disable: true}]); + return { + value, + options, + options1 + } + }, +}) +</script> +``` +::: + + +### 异步获取数据源并设置匹配方法 +支持异步设置数据源并设置匹配方法。 +:::demo +```vue +<template> + <div class="demo-wrap"> + <d-editable-select v-model="value" :options="options" :maxHeight="300" remote :remote-method="remoteMethod"></d-editable-select> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const languages = [ + "C#", + "C", + "C++", + "CPython", + "Java", + "JavaScript", + "Go", + "Python", + "Ruby", + "F#", + "TypeScript", + "SQL", + "LiveScript", + "CoffeeScript"] + const value = ref("") + const options = ref([]) + + const remoteMethod = (query) => { + if (query !== '') { + setTimeout(() => { + options.value = languages.filter((item) => { + return item.includes(query) + }) + }, 200) + } else { + options.value = [] + } + } + return { + value, + options, + remoteMethod + } + }, +}) +</script> +``` +::: +### d-editable-select + +d-editable-select 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置 | +| ------------ | ------------- | ----- | -------------------------------------------------- | ------------ | -------- | +| appendToBody | boolean | false | 可选,下拉是否 appendToBody | [基本用法](#基本用法) | | +| width | number | -- | 可选,控制下拉框宽度,搭配 appendToBody 使用(px) | [基本用法](#基本用法) | | +| v-model | string/number | -- | 绑定值 | [基本用法](#基本用法) | | +| options | Array | -- | 必选,数据列表 | [基本用法](#基本用法) | | +| disabled | boolean | false | 可选,值为 true 禁用下拉框 | | | +| disabledKey | string | -- | 可选,设置禁用选项的 Key 值 | 设置禁用选项 | | +| maxHeight | number | -- | 可选,下拉菜单的最大高度(px) | [基本用法](#基本用法) | | +| remote | boolean | false | 可选,远程搜索 | | | + + +d-editable-select 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | + +d-editable-select 插槽 + +| name | 说明 | +| ------- | ------------------ | +| default | Option 模板 | +| empty | 无 Option 时的列表 | diff --git a/packages/devui-vue/docs/components/form/index.md b/packages/devui-vue/docs/components/form/index.md new file mode 100644 index 0000000000000000000000000000000000000000..2c784e44c4468d17496859a9c3d978edf20e7213 --- /dev/null +++ b/packages/devui-vue/docs/components/form/index.md @@ -0,0 +1,1650 @@ +# Form 表单 + +表单用于收集数据 + +### 何时使用 + +需要进行数据收集、数据校验、数据提交功能时。 + + + +### 基础用法 + +> done + +基本用法当中,Label是在数据框的上面。 + + +:::demo + +```vue +<template> + <d-form ref="dFormBasic" :formData="formModel" layout="vertical" @submit="onSubmitForm"> + <d-form-item prop="name"> + <d-form-label required hasHelp helpTips="名字可以随意填">Name</d-form-label> + <d-form-control extraInfo="这行是说明文字,可以不用理,你尽管填你的姓名。"> + <d-input v-model:value="formModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label>Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" /> + </d-form-control> + </d-form-item> + <d-form-item prop="city"> + <d-form-label>City</d-form-label> + <d-form-control> + <d-select v-model="formModel.city" :options="selectOptions" /> + </d-form-control> + </d-form-item> + <d-form-item prop="loveFruits"> + <d-form-label>Love Fruits</d-form-label> + <d-form-control> + <d-tag-input + v-model:tags="formModel.loveFruits" + v-model:suggestionList="formModel.suggestionList" + display-property="name" + placeholder="请输入喜欢的水果" + no-data="暂无数据" + ></d-tag-input> + </d-form-control> + </d-form-item> + <d-form-item prop="sex"> + <d-form-label>Sex</d-form-label> + <d-form-control> + <d-radio v-model="formModel.sex" value="0">男</d-radio> + <d-radio v-model="formModel.sex" value="1">女</d-radio> + </d-form-control> + </d-form-item> + <d-form-item prop="goOffWork"> + <d-form-label>Go off work, I nerver to be a Juan King!</d-form-label> + <d-form-control> + <d-switch v-model:checked="formModel.goOffWork"></d-switch> + </d-form-control> + </d-form-item> + <d-form-item prop="ladySupport"> + <d-form-label>Which lady you would like to support?</d-form-label> + <d-form-control> + <d-checkbox-group v-model="formModel.ladySupport" label="1818黄金眼"> + <d-checkbox label="郑女士" value="ladyZheng" /> + <d-checkbox label="小毛" value="ladyMao" /> + <d-checkbox label="小刘" value="ladyLiu" /> + <d-checkbox label="小蒋" value="ladyJiang" /> + <d-checkbox label="小滕" value="ladyTeng" /> + </d-checkbox-group> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref, nextTick} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormBasic = ref(null); + let formModel = reactive({ + name: 'AlanLee', + age: '24', + city: '深圳', + loveFruits: [{name: 'apple'}], + suggestionList: [{name: 'apple'}, {name: 'watermalon'}, {name: 'peach'}], + sex: '0', + goOffWork: true, + ladySupport: ['ladyZheng'], + }); + const selectOptions = reactive([ + '北京', '上海', '广州', '深圳' + ]); + const resetForm = () => { + console.log('formData reset before', dFormBasic.value.formData); + dFormBasic.value.resetFormFields(); + console.log('formData reset after', dFormBasic.value.formData); + } + const onSubmitForm = () => { + console.log('onSubmitForm formModel', formModel) + } + return { + dFormBasic, + formModel, + selectOptions, + resetForm, + onSubmitForm + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} + +</style> + +``` + +::: + + +### 横向排列 + +> done + +Label左右布局方式。 + + +:::demo + +```vue +<template> + <d-form ref="dFormHorizontal" :formData="formModel" layout="horizontal" labelSize="lg" @submit="onSubmitForm"> + <d-form-item prop="name"> + <d-form-label required>Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label>Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" /> + </d-form-control> + </d-form-item> + <d-form-item prop="city"> + <d-form-label>City</d-form-label> + <d-form-control> + <d-select v-model:value="formModel.city" :options="selectOptions" /> + </d-form-control> + </d-form-item> + <d-form-item prop="loveFruits"> + <d-form-label>Love Fruits</d-form-label> + <d-form-control> + <d-tag-input + v-model:tags="formModel.loveFruits" + v-model:suggestionList="formModel.suggestionList" + display-property="name" + placeholder="请输入喜欢的水果" + no-data="暂无数据" + ></d-tag-input> + </d-form-control> + </d-form-item> + <d-form-item prop="sex"> + <d-form-label>Sex</d-form-label> + <d-form-control> + <d-radio v-model="formModel.sex" value="0">男</d-radio> + <d-radio v-model="formModel.sex" value="1">女</d-radio> + </d-form-control> + </d-form-item> + <d-form-item prop="goOffWork"> + <d-form-label>Go off work</d-form-label> + <d-form-control> + <d-switch v-model:checked="formModel.goOffWork"></d-switch> + </d-form-control> + </d-form-item> + <d-form-item prop="ladySupport"> + <d-form-label>Support lady</d-form-label> + <d-form-control> + <d-checkbox-group v-model="formModel.ladySupport" label="1818黄金眼"> + <d-checkbox label="郑女士" value="ladyZheng" /> + <d-checkbox label="小毛" value="ladyMao" /> + <d-checkbox label="小刘" value="ladyLiu" /> + <d-checkbox label="小蒋" value="ladyJiang" /> + <d-checkbox label="小滕" value="ladyTeng" /> + </d-checkbox-group> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormHorizontal = ref(null); + let formModel = reactive({ + name: 'AlanLee', + age: '24', + city: '', + loveFruits: [{name: 'apple'}], + suggestionList: [{name: 'apple'}, {name: 'watermalon'}, {name: 'peach'}], + sex: '0', + goOffWork: true, + ladySupport: ['ladyZheng'], + }); + const selectOptions = reactive([ + '北京', '上海', '广州', '深圳' + ]); + const resetForm = () => { + console.log('dFormHorizontal', dFormHorizontal.value); + dFormHorizontal.value.resetFormFields(); + } + const onSubmitForm = () => { + console.log('onSubmitForm formModel', formModel) + } + return { + dFormHorizontal, + formModel, + selectOptions, + resetForm, + onSubmitForm + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +### 弹框表单 + +> todo <br> +> 待替换为Modal组件 + +弹框表单,弹框建议是400px,550px,700px,900px,建议宽高比是16: 9、3: 2。 + + +:::demo + +```vue +<template> + <d-button @click="openModal">Open Modal</d-button> + <div class="my-modal" v-show="showModal" @click="closeModal"> + <d-form ref="dFormModal" :formData="formModel" layout="horizontal" labelSize="lg" @submit="onSubmitForm" class="my-form" @click.stop="() => {}"> + <d-form-item prop="name"> + <d-form-label required>Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label>Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" /> + </d-form-control> + </d-form-item> + <d-form-item prop="city"> + <d-form-label>City</d-form-label> + <d-form-control> + <d-select v-model:value="formModel.city" :options="selectOptions" /> + </d-form-control> + </d-form-item> + <d-form-item prop="loveFruits"> + <d-form-label>Love Fruits</d-form-label> + <d-form-control> + <d-tag-input + v-model:tags="formModel.loveFruits" + v-model:suggestionList="formModel.suggestionList" + display-property="name" + placeholder="请输入喜欢的水果" + no-data="暂无数据" + ></d-tag-input> + </d-form-control> + </d-form-item> + <d-form-item prop="sex"> + <d-form-label>Sex</d-form-label> + <d-form-control> + <d-radio v-model="formModel.sex" value="0">男</d-radio> + <d-radio v-model="formModel.sex" value="1">女</d-radio> + </d-form-control> + </d-form-item> + <d-form-item prop="goOffWork"> + <d-form-label>Go off work</d-form-label> + <d-form-control> + <d-switch v-model:checked="formModel.goOffWork"></d-switch> + </d-form-control> + </d-form-item> + <d-form-item prop="ladySupport"> + <d-form-label>Support lady</d-form-label> + <d-form-control> + <d-checkbox-group v-model="formModel.ladySupport" label="1818黄金眼"> + <d-checkbox label="郑女士" value="ladyZheng" /> + <d-checkbox label="小毛" value="ladyMao" /> + <d-checkbox label="小刘" value="ladyLiu" /> + <d-checkbox label="小蒋" value="ladyJiang" /> + <d-checkbox label="小滕" value="ladyTeng" /> + </d-checkbox-group> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> + </div> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormModal = ref(null); + let formModel = reactive({ + name: 'AlanLee', + age: '24', + city: '', + loveFruits: [{name: 'apple'}], + suggestionList: [{name: 'apple'}, {name: 'watermalon'}, {name: 'peach'}], + sex: '0', + goOffWork: true, + ladySupport: ['ladyZheng'], + }); + const selectOptions = reactive([ + '北京', '上海', '广州', '深圳' + ]); + const resetForm = () => { + console.log('dFormModal', dFormModal.value); + dFormModal.value.resetFormFields(); + } + const onSubmitForm = () => { + console.log('onSubmitForm formModel', formModel) + } + const showModal = ref(false); + const openModal = () => { + showModal.value = true; + } + const closeModal = () => { + showModal.value = false; + } + return { + dFormModal, + formModel, + selectOptions, + resetForm, + onSubmitForm, + showModal, + openModal, + closeModal + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} + +.my-modal { + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + width: 100vw; + height: 100vh; + z-index: 10000; + margin: auto; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; +} + +.my-form { + background-color: #fff; + width: 60vw; + padding: 20px; +} +</style> + +``` + +::: + + +### 多列表单 + +> done + +多列表单。layout的属性为`columns`,同时搭配columnsClass属性,值为"u-[row]-[col]",例如`u-1-3`为1行3列。 + + +:::demo + +```vue +<template> + <d-form ref="dFormColumn" layout="columns" columnsClass="u-1-3" :formData="formModel" @submit="onSubmitForm"> + <d-form-item prop="name" v-for="(item) in 6" :key="item" class="column-item"> + <d-form-label required hasHelp>Name</d-form-label> + <d-form-control> + <d-input /> + </d-form-control> + </d-form-item> + <d-form-item prop="loveFruits" class="column-item"> + <d-form-label>Love Fruits</d-form-label> + <d-form-control> + <d-tag-input + v-model:tags="formModel.loveFruits" + v-model:suggestionList="formModel.suggestionList" + display-property="name" + placeholder="请输入喜欢的水果" + no-data="暂无数据" + ></d-tag-input> + </d-form-control> + </d-form-item> + <d-form-item prop="sex" class="column-item"> + <d-form-label>Sex</d-form-label> + <d-form-control> + <d-radio v-model="formModel.sex" value="0">男</d-radio> + <d-radio v-model="formModel.sex" value="1">女</d-radio> + </d-form-control> + </d-form-item> + <d-form-item prop="goOffWork" class="column-item"> + <d-form-label>Go off work</d-form-label> + <d-form-control> + <d-switch v-model:checked="formModel.goOffWork"></d-switch> + </d-form-control> + </d-form-item> + <d-form-item prop="ladySupport" class="column-item"> + <d-form-label>Support lady</d-form-label> + <d-form-control> + <d-checkbox-group v-model="formModel.ladySupport" label="1818黄金眼"> + <d-checkbox label="郑女士" value="ladyZheng" /> + <d-checkbox label="小毛" value="ladyMao" /> + <d-checkbox label="小刘" value="ladyLiu" /> + <d-checkbox label="小蒋" value="ladyJiang" /> + <d-checkbox label="小滕" value="ladyTeng" /> + </d-checkbox-group> + </d-form-control> + </d-form-item> + + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormColumn = ref(null); + let formModel = reactive({ + name: 'AlanLee', + age: '24', + city: '', + loveFruits: [{name: 'apple'}], + suggestionList: [{name: 'apple'}, {name: 'watermalon'}, {name: 'peach'}], + sex: '0', + goOffWork: true, + ladySupport: ['ladyZheng'], + }); + const selectOptions = reactive([ + '北京', '上海', '广州', '深圳' + ]); + const resetForm = () => { + console.log('dFormColumn', dFormColumn.value); + dFormColumn.value.resetFormFields(); + } + const onSubmitForm = () => { + console.log('onSubmitForm formModel', formModel) + } + return { + dFormColumn, + formModel, + selectOptions, + resetForm, + onSubmitForm + } + } +}) +</script> + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + + +### 模板驱动表单验证 + +> doing + +在`d-form`、`d-input`等表单类组件上使用`v-d-validate-rules`指令,配置校验规则。 + + +#### 验证单个元素,使用内置校验器,配置error message + +> done +> +> 待支持国际化词条配置 + +当前DevUI支持的内置校验器有:`required`、`minlength`、`maxlength`、`min`、`max`、`requiredTrue`、`email`、`pattern`、`whitespace`。<br> + +- 若需限制用户输入不能全为空格,可使用`whitespace`内置校验器<br> +- 若需限制用户输入长度,将最大限制设置为实际校验值`+1`是一个好的办法。<br> +- 除`pattern`外,其他内置校验器我们也提供了内置的错误提示信息,在你未自定义提示消息时,我们将使用默认的提示信息。<br> +- message配置支持string与object两种形式(支持国际化词条配置,如`'zh-cn'`,默认将取`'default'`)。 + +:::demo + +```vue +<template> + <d-form ref="dFormTemplateValidate1" :formData="formModel" labelSize="lg" > + <d-form-item prop="name"> + <d-form-label required>Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" v-d-validate-rules="[ + { + maxlength: 8, + }, + { + pattern: /^[a-zA-Z\d]+(\s+[a-zA-Z\d]+)*$/, + message: { + 'zh-cn': '只能包含数字与大小写字符', + 'en-us': 'The value cannot contain characters except uppercase and lowercase letters.', + default: '只能包含数字与大小写字符' + } + } + ]" /> + </d-form-control> + </d-form-item> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate1 = ref(null); + let formModel = reactive({ + name: 'AlanLee', + }); + + return { + dFormTemplateValidate1, + formModel, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + +#### 验证单个元素,自定义校验器 + +> done + +自定义校验器,可传入`validators`字段配置校验规则,你可以简单返回`true | false `来标识当前校验是否通过,来标识当前是否错误并返回错误消息,适用于动态错误提示。如果是异步校验器,可传入`asyncValidators`字段配置校验规则。 + +:::demo + +```vue +<template> + <d-form ref="dFormTemplateValidate2" :formData="formModel" labelSize="lg" > + <d-form-item prop="sum"> + <d-form-label>计算:1 + 1 = ?</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.sum" v-d-validate-rules="{ + validators: [ + {message: '不对喔!', validator: customValidator}, + {message: '答对啦!', validator: customValidator2} + ] + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="asyncSum"> + <d-form-label>计算:1 + 2 = ?(async)</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.asyncSum" v-d-validate-rules="{ + asyncValidators: [ + {message: '不对喔!(async)', asyncValidator: customAsyncValidator}, + {message: '答对啦!(async)', asyncValidator: customAsyncValidator2} + ] + }" /> + </d-form-control> + </d-form-item> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate2 = ref(null); + let formModel = reactive({ + sum: '', + asyncSum: '', + }); + + const customValidator = (rule, value) => { + return value == "2"; // value值等于2的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!”) + } + const customValidator2 = (rule, value) => { + return value != "2"; // value值不等于2的时候,校验规则通过,不提示本规则中自定义的message(“答对啦!”) + } + + const customAsyncValidator = (rule, value) => { + return value == "3"; // value值等于3的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!(async)”) + } + const customAsyncValidator2 = (rule, value) => { + return value != "3"; // value值不等于3的时候,校验规则通过,不提示本规则中自定义的message(“答对啦!(async)”) + } + return { + dFormTemplateValidate2, + formModel, + customValidator, + customValidator2, + customAsyncValidator, + customAsyncValidator2, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +#### 验证单个元素,配置错误更新策略errorStrategy、校验时机updateOn + +> done + +设置`errorStrategy`属性初始化时是否进行校验, 默认配置为`dirty`,校验不通过进行错误提示;若需要在初始化时将错误抛出,可配置为`pristine`。 + +设置`updateOn`,指定校验的时机。 校验器`updateOn`基于你绑定的模型的`updateOn`设置, 你可以通过`options`来指定, 默认为`change`,可选值还有`blur` 、`input`、`submit`、 设置为`submit`,则当元素所在表单进行提交时将触发校验。(待实现submit) + +:::demo + +```vue +<template> + <d-form ref="dFormTemplateValidate3" :formData="formModel" labelSize="lg" > + <d-form-item prop="sum"> + <d-form-label>计算:1 + 1 = ?</d-form-label> + <d-form-control extraInfo="updateOn为change,当输入完成时,输入框的值发生改变。此时触发验证规则"> + <d-input v-model:value="formModel.sum" v-d-validate-rules="{ + rules: { + validators: [ + {message: '不对喔!', validator: customValidator}, + {message: '答对啦!', validator: customValidator2} + ] + }, + options: { + updateOn: 'change' + } + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="asyncSum"> + <d-form-label>计算:1 + 2 = ?(async)</d-form-label> + <d-form-control extraInfo="updateOn为input,当正在输入时,输入框的值发生改变。此时触发验证规则"> + <d-input v-model:value="formModel.asyncSum" v-d-validate-rules="{ + rules: { + asyncValidators: [ + {message: '不对喔!(async)', asyncValidator: customAsyncValidator}, + {message: '只能输入数字!', asyncValidator: customAsyncValidator2} + ] + }, + options: { + updateOn: 'input' + } + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="errorSum"> + <d-form-label>计算:1 + 1 = ?</d-form-label> + <d-form-control extraInfo="errorStrategy为pristine,初始化时触发验证规则"> + <d-input v-model:value="formModel.errorSum" v-d-validate-rules="{ + errorStrategy: 'pristine', + rules: { + validators: [ + {message: '不对喔!', validator: customValidator3}, + ] + }, + options: { + updateOn: 'input' + } + }" /> + </d-form-control> + </d-form-item> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate3 = ref(null); + let formModel = reactive({ + sum: '', + asyncSum: '', + errorSum: '3', + }); + + const customValidator = (rule, value) => { + return value == "2"; // value值等于2的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!”) + } + const customValidator2 = (rule, value) => { + return value != "2"; // value值不等于2的时候,校验规则通过,不提示本规则中自定义的message(“答对啦!”) + } + + const customAsyncValidator = (rule, value) => { + return value == "3"; // value值等于3的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!(async)”) + } + const customAsyncValidator2 = (rule, value) => { + let reg = /^[\d]+(\s+[\d]+)*$/; + return reg.test(value); + } + + const customValidator3 = (rule, value) => { + return value == "2"; // value值等于2的时候,校验规则通过,不提示本规则中自定义的message + } + return { + dFormTemplateValidate3, + formModel, + customValidator, + customValidator2, + customAsyncValidator, + customAsyncValidator2, + customValidator3, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +#### 验证单个元素,自定义管理消息提示 + +> doing +> +> 待引入popover组件 + +配置`messageShowType`可选择消息自动提示的方式,默认为`popover`。 + +- 设置为`popover`错误信息将在元素聚焦时以`popover`形式呈现。 +- 设置为`text`错误信息将自动以文本方式显示在元素下方(需要与表单控件容器配合使用)。 +- 设置为`none`错误信息将不会自动呈现到视图, 可在模板中获取`message`或通过监听`messageChange`事件获取错误`message`, 或在模板中直接通过引用获取。 +- 配置`popPosition`可在消息提示方式为`popover`时,自定义`popover`内容弹出方向。 默认为`['right', 'bottom']`。 + +:::demo + +```vue +<template> + <d-form ref="dFormTemplateValidate4" :formData="formModel" labelSize="lg" > + <d-form-item prop="sum"> + <d-form-label>计算:1 + 1 = ?</d-form-label> + <d-form-control extraInfo="messageShowType为none,不显示提示文字"> + <d-input v-model:value="formModel.sum" v-d-validate-rules="{ + messageShowType: 'none', + rules: { + validators: [ + {message: '不对喔!', validator: customValidator} + ] + }, + options: { + updateOn: 'change' + } + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="asyncSum"> + <d-form-label>计算:1 + 2 = ?</d-form-label> + <d-form-control extraInfo="messageShowType为popover,使用popover进行提示(todo,待引入popover组件)"> + <d-input v-model:value="formModel.asyncSum" v-d-validate-rules="{ + rules: { + asyncValidators: [ + {message: '不对喔!(async)', asyncValidator: customAsyncValidator} + ] + }, + options: { + updateOn: 'input' + } + }" /> + </d-form-control> + </d-form-item> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate4 = ref(null); + let formModel = reactive({ + sum: '', + asyncSum: '', + }); + + const customValidator = (rule, value) => { + return value == "2"; // value值等于2的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!”) + } + + const customAsyncValidator = (rule, value) => { + return value == "3"; // value值等于3的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!(async)”) + } + + return { + dFormTemplateValidate4, + formModel, + customValidator, + customAsyncValidator, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + + +#### 验证单个元素,自定义asyncDebounceTime + +> done + + +对于异步校验器,提供默认300ms debounce time。在options中设置`asyncDebounceTime`显示设置(单位ms)。 + + +:::demo + +```vue +<template> + <d-form ref="dFormTemplateValidate5" :formData="formModel" labelSize="lg" > + <d-form-item prop="asyncSum"> + <d-form-label>计算:1 + 2 = ?(async)</d-form-label> + <d-form-control extraInfo="asyncDebounceTime为500"> + <d-input v-model:value="formModel.asyncSum" v-d-validate-rules="{ + rules: { + asyncValidators: [ + {message: '不对喔!(async)', asyncValidator: customAsyncValidator} + ] + }, + options: { + updateOn: 'input', + asyncDebounceTime: 500 + } + }" /> + </d-form-control> + </d-form-item> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate5 = ref(null); + let formModel = reactive({ + asyncSum: '', + }); + + const customAsyncValidator = (rule, value) => { + return value == "3"; // value值等于3的时候,校验规则通过,不提示本规则中自定义的message(“不对喔!(async)”) + } + return { + dFormTemplateValidate5, + formModel, + customAsyncValidator, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + + +#### Form验证与提交 + +> done + +点击提交按钮时进行验证,需指定name属性,并同时绑定d-form标签的submit事件才能生效。 + +:::demo + +```vue +<template> + <d-form name="userInfoForm" ref="dFormTemplateValidate6" :formData="formModel" labelSize="lg" @submit="onSubmit"> + <d-form-item prop="name"> + <d-form-label>Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" v-d-validate-rules="{ + rules: {minlength: 2, message: '不能小于2个字符'}, + options: { + updateOn: 'input', + } + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label>Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" v-d-validate-rules="{ + rules: {min: 1, message: '年龄需大于0'}, + options: { + updateOn: 'input', + } + }" /> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate6 = ref(null); + let formModel = reactive({ + name: '', + age: '', + }); + + const resetForm = () => { + dFormTemplateValidate6.value.resetFormFields(); + } + + const onSubmit = (e) => { + console.log('@submit') + } + + return { + dFormTemplateValidate6, + formModel, + onSubmit, + resetForm, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +#### Form验证与提交,用户注册场景 + +> doing + +待实现在dForm层统一设置messageShowType。 + +:::demo + +```vue +<template> + <d-form name="userInfoForm2" ref="dFormTemplateValidate7" :formData="formModel" labelSize="lg" @submit="onSubmit" v-d-validate-rules="{ + rules: {message: '表单验证未通过'}, + messageShowType: 'toast' + }"> + <d-form-item prop="name"> + <d-form-label>Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" v-d-validate-rules="{ + rules: {minlength: 2, message: '不能小于2个字符'}, + options: { + updateOn: 'input', + } + }" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label>Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" v-d-validate-rules="{ + rules: {min: 1, message: '年龄需大于0'}, + options: { + updateOn: 'input', + } + }" /> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTemplateValidate7 = ref(null); + let formModel = reactive({ + name: '', + age: '', + }); + + const resetForm = () => { + dFormTemplateValidate7.value.resetFormFields(); + } + + const onSubmit = (e) => { + console.log('@submit') + } + + return { + dFormTemplateValidate7, + formModel, + onSubmit, + resetForm, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + +### 响应式表单验证 + +> done + +在`d-form`标签中指定校验规则rules,同时在`d-form-item`中指定`prop`的值为校验字段名。 + + +:::demo + +```vue +<template> + <d-form ref="dFormReactiveValidate" :form-data="validateFormModel" :rules="rules"> + <d-form-item prop="name"> + <d-form-label :required="true" >Name</d-form-label> + <d-form-control> + <d-input v-model:value="validateFormModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label :required="true" >Age</d-form-label> + <d-form-control> + <d-input v-model:value="validateFormModel.age" /> + </d-form-control> + </d-form-item> + </d-form> + +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormReactiveValidate = ref(null); + let validateFormModel = reactive({ + name: 'AlanLee', + age: '24', + }); + const rules = reactive({ + name: [{ required: true, message: '不能为空', trigger: 'blur'}], + age: [ + { + required: true, + message: '年龄不能小于0', + trigger: 'blur', + validator: (rule, value) => value > 0 + }, + { + required: true, + message: '年龄不能大于120', + trigger: 'input', + validator: (rule, value) => value < 120 + } + ], + }); + + return { + dFormReactiveValidate, + rules, + validateFormModel, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +### 指定表单Feedback状态 + +> done + +你可通过对d-form-control设置feedbackStatus手动指定反馈状态。当前已支持状态:`success`、`error`、`pending`。 + + +:::demo + +```vue +<template> + <d-form ref="dFormFeedback" :form-data="formModel"> + <d-form-item prop="name"> + <d-form-label :required="true" >Name</d-form-label> + <d-form-control feedbackStatus="pending"> + <d-input v-model:value="formModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="nickname"> + <d-form-label :required="true" >Nickname</d-form-label> + <d-form-control feedbackStatus="success"> + <d-input v-model:value="formModel.nickname" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label :required="true" >Age</d-form-label> + <d-form-control feedbackStatus="error"> + <d-input v-model:value="formModel.age" /> + </d-form-control> + </d-form-item> + <d-form-item prop="sex"> + <d-form-label :required="true">Sex</d-form-label> + <d-form-control feedbackStatus="error"> + <d-select v-model="formModel.sex" :options="sexSelectOptions" placeholder="Select your sex"></d-select> + </d-form-control> + </d-form-item> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormFeedback = ref(null); + let formModel = reactive({ + name: 'AlanLee', + nickname: 'AlanLee97', + age: '24', + sex: '男', + }); + + const sexSelectOptions = reactive([ + '男', '女' + ]) + + return { + dFormFeedback, + formModel, + sexSelectOptions, + } + } +}) +</script> + + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + + +可通过对具名插槽suffixTemplate在d-form-control中自定义反馈状态icon。 + + +:::demo + +```vue +<template> + <d-form ref="dFormFeedback2" :form-data="formModel"> + <d-form-item prop="address"> + <d-form-label :required="true" >Address</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.address" /> + <template v-slot:suffixTemplate> + <d-icon name="right-o" color="rgb(61, 204, 166)" /> + </template> + </d-form-control> + </d-form-item> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormFeedback2 = ref(null); + let formModel = reactive({ + address: '深圳南山区', + }); + + return { + dFormFeedback2, + formModel, + } + } +}) +</script> + +``` + +::: + + +### 表单协同验证 + +> done + +在一些场景下,你的多个表单组件互相依赖,需共同校验(如注册场景中的密码输入与确认密码),通过自定义校验器实现校验规则(将密码输入与确认密码的值进行比较)。 + + +:::demo + +```vue +<template> + <d-form name="togetherValidateForm" ref="dFormTogetherValidate" :form-data="formModel" labelSize="lg" @submit="onSubmit"> + <d-form-item prop="username"> + <d-form-label :required="true" >Username</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.username" v-d-validate-rules="formRules.userNameRule" /> + </d-form-control> + </d-form-item> + <d-form-item prop="password"> + <d-form-label :required="true" >Password</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.password" v-d-validate-rules="formRules.passwordRule" /> + </d-form-control> + </d-form-item> + <d-form-item prop="confirmPassword"> + <d-form-label :required="true" >Confirm Password</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.confirmPassword" v-d-validate-rules="formRules.confirmPasswordRule" /> + </d-form-control> + </d-form-item> + <d-form-operation class="demo-form-operation"> + <d-button type="submit" class="demo-btn">提交</d-button> + <d-button bsStyle="common" @click="resetForm">重置</d-button> + </d-form-operation> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormTogetherValidate = ref(null); + let formModel = reactive({ + username: '', + password: '', + confirmPassword: '', + }); + + const formRules = { + userNameRule: { + rules: { + minlength: 6, + message: '最小6个字符' + } + }, + passwordRule: { + rules: { + minlength: 6, + message: '最小6个字符' + } + }, + confirmPasswordRule: { + options: { + updateOn: 'input', + }, + rules: { + minlength: 6, + message: '最小6个字符', + validators: [ + { + message: '确认密码与密码不相符', + validator: (rule, value) => { + return value === formModel.password + } + } + ] + } + } + } + + const resetForm = () => { + dFormTogetherValidate.value.resetFormFields(); + } + + const onSubmit = (e) => { + console.log('@submit') + } + + return { + dFormTogetherValidate, + formModel, + formRules, + resetForm, + onSubmit, + } + } +}) +</script> + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` + +::: + +### 跨组件验证 + +> todo + + + + +:::demo + +```vue +<template> + <d-form ref="dFormWithComponent" :form-data="formModel"> + <d-form-item prop="name"> + <d-form-label :required="true" >Name</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.name" /> + </d-form-control> + </d-form-item> + <d-form-item prop="age"> + <d-form-label :required="true" >Age</d-form-label> + <d-form-control> + <d-input v-model:value="formModel.age" /> + </d-form-control> + </d-form-item> + </d-form> +</template> + +<script> +import {defineComponent, reactive, ref} from 'vue'; + +export default defineComponent({ + setup(props, ctx) { + const dFormWithComponent = ref(null); + let formModel = reactive({ + name: 'AlanLee', + age: '24', + }); + + return { + dFormWithComponent, + formModel, + } + } +}) +</script> + +<style> +.demo-form-operation { + display: flex; + align-items: center; +} +.demo-btn { + margin-right: 10px; +} +</style> + +``` +::: + + + +### Form Attributes + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| ------------ | ------------------------------------------------------------ | ------ | ----------------------------------- | ------------ | +| name | 可选,设置表单name属性,进行表单提交验证时必选。 | string | | | +| formData | 必选,表单数据 | object | | | +| layout | 可选,设置表单的排列方式 | string | `horizontal`、`vertical`、`columns` | `horizontal` | +| labelSize | 可选,设置 label 的占宽,未设置默认为 100px,'sm'对应 80px,'lg'对应 150px | string | `sm`、`lg` | -- | +| labelAlign | 可选,设置水平布局方式下,label 对齐方式 | string | `start`、`center`、`end` | `start` | +| columnsClass | 可选,设置多列表单样式 | string | | | +| rules | 可选,设置表单校验规则 | object | | | + + + +### Form Methods + +| 方法名 | 说明 | 参数 | +| ------ | ------------------ | ---- | +| submit | 可选,提交表单事件 | -- | + + + +### Form-Item Attributes + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| ------------ | ---------------------------------------------------- | ------- | --------------- | ------- | +| prop | 可选,指定验证表单需验证的字段,验证表单时必选该属性 | | | | +| dHasFeedback | 可选,设置当前 formControl 是否显示反馈图标 | boolean | `true`、`false` | `false` | + + + +### Form-Lable Attributes + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| -------- | ------------------------------------------------------------ | ------- | --------------- | ------- | +| required | 可选,表单选项是否必填 | boolean | `true`、`false` | `false` | +| hasHelp | 可选,表单项是否需要帮助指引 | boolean | `true`、`false` | `false` | +| helpTips | 可选,表单项帮助指引提示内容,需配合 `hasHelp`使用,且`helpTips`的值不能为空字符串才会生效。 | string | | -- | + + + +### Form-Control Attributes + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| -------------- | ---------------------------------------------------------- | ------- | --------------- | ------- | +| extraInfo | 可选,附件信息,一般用于补充表单选项的说明 | string | | -- | +| feedbackStatus | 可选,手动指定当前 control 状态反馈 | boolean | `true`、`false` | `false` | +| suffixTemplate | 可选,可传入图标模板作为输入框后缀(通过插槽传入icon组件) | | | -- | + + + +### Directives + +#### v-d-validate-rules + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| ------- | ------------------ | ------ | --------------------------- | ------ | +| rules | 必选,表单校验规则 | object | | -- | +| options | 可选,配置选项 | object | `errorStrategy`、`updateOn` | | + +> 该指令仅在`d-form`标签或`d-input`等表单类组件上使用有效。 + + + +- rules格式如下 + +```js +{[validatorKey]: validatorValue, message: 'some tip messages.'} +``` + +当前DevUI支持的内置校验器validatorKey有:`required`、`minlength`、`maxlength`、`min`、`max`、`requiredTrue`、`email`、`pattern`、`whitespace`。<br> + + + +<br> + +- options支持以下字段 + - errorStrategy,错误更新策略:`dirty`(默认)、`prestine` + + - updateOn,校验时机,可选值有:`change`(默认)、 `blur`、 `input` + + +<style> + ul, ol { + list-style: unset !important; + } +</style> diff --git a/packages/devui-vue/docs/components/fullscreen/index.md b/packages/devui-vue/docs/components/fullscreen/index.md new file mode 100644 index 0000000000000000000000000000000000000000..7132dcd5bca23412b673b27276cd9399b4fce7b7 --- /dev/null +++ b/packages/devui-vue/docs/components/fullscreen/index.md @@ -0,0 +1,93 @@ +# Fullscreen 全屏 + +全屏组件。 + +### 何时使用 + +当用户需要将某一区域进行全屏展示时。 + +### 沉浸式全屏 + +充满整个显示器屏幕的沉浸式全屏。 + +:::demo + +```vue +<template> + <d-fullscreen :zIndex='100' @fullscreenLaunch='fullscreenLaunch'> + <div fullscreen-target> + <d-button fullscreen-launch>{{btnContent}}</d-button> + </div> + </d-fullscreen> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const btnContent = ref('FullScreen') + const fullscreenLaunch = (val) => { + if (val) { + btnContent.value = 'Exit' + } else { + btnContent.value = 'FullScreen' + } + } + return { + btnContent, + fullscreenLaunch + } + } +} +</script> +``` +::: + +### 普通全屏 + +充满当前浏览器窗口的普通全屏。 + +:::demo + +```vue +<template> + <d-fullscreen :mode='"normal"' @fullscreenLaunch='fullscreenLaunch'> + <div fullscreen-target> + <d-button bsStyle="common" fullscreen-launch>{{btnContent}}</d-button> + </div> + </d-fullscreen> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const btnContent = ref('普通') + const fullscreenLaunch = (val) => { + if (val) { + btnContent.value = '退出' + } else { + btnContent.value = '普通' + } + } + return { + btnContent, + fullscreenLaunch + } + } +} +</script> +``` +::: + +### 参数及API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | +| mode | `immersive` 或 `normal` | `immersive` | 可选,设置全屏模式 | [沉浸式全屏](#沉浸式全屏) | +| zIndex | `Number` | 10 | 可选,设置全屏层级 | [普通全屏](#普通全屏) | +| fullscreenLaunch | `EventEmitter<boolean>` | | 可选,全屏之后的回调 | [普通全屏](#普通全屏) | + +**fullscreen-target** 选择器 +必含指令,内容投影,设置**需要全屏的元素**沉浸式全屏。 + +**fullscreen-launch** 选择器 +必含指令,内容投影,设置**触发**进入全屏的按钮沉浸式全屏。 \ No newline at end of file diff --git a/packages/devui-vue/docs/components/gantt/index.md b/packages/devui-vue/docs/components/gantt/index.md new file mode 100644 index 0000000000000000000000000000000000000000..919457f8a05ee5dead1132a3ea002e1ecfda6365 --- /dev/null +++ b/packages/devui-vue/docs/components/gantt/index.md @@ -0,0 +1,65 @@ +# Gantt 甘特图 + +甘特图。 + +### 何时使用 + +当用户需要通过条状图来显示项目,进度和其他时间相关的系统进展的内在关系随着时间进展的情况时。 + +### 基本用法 + +- d-gantt-scale(时间轴)容器作为时间轴标线的定位父级元素,须设置 position 或者是 table、td、th、body 元素。 +- d-gantt-scale(时间轴)容器和 d-gantt-bar(时间条)容器宽度须通过 GanttService 提供的方法根据起止时间计算后设置,初始化之后还须订阅 ganttScaleConfigChange 动态设置。 +- 时间条 move、resize 事件会改变该时间条起止时间和时间轴的起止时间,订阅时间条 resize、move 事件和 ganttScaleConfigChange 来记录变化。 +- 响应时间条 move、resize 事件调整最外层容器的滚动以获得更好的体验。 + +:::demo + +```vue +<template> + <d-fullscreen :zIndex="100" @fullscreenLaunch="fullscreenLaunch"> + <d-gantt :startDate="startDate" :endDate="endDate"></d-gantt> + </d-fullscreen> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const curYear = new Date().getFullYear() + + const startDate = ref(new Date(curYear, 3, 1)) + const endDate = ref(new Date(curYear, 10, 1)) + const fullscreenLaunch = () => {} + return { + fullscreenLaunch, + startDate, + endDate, + } + }, +}) +</script> + +<style></style> +``` + +::: + +### d-gantt + +d-gantt 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | ---------- | +| | | | | | | +| | | | | | | +| | | | | | | + +d-gantt 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | diff --git a/packages/devui-vue/docs/components/grid/index.md b/packages/devui-vue/docs/components/grid/index.md new file mode 100644 index 0000000000000000000000000000000000000000..2a67551b3e7570f72b8bff6ff2f0fa15a06f8c87 --- /dev/null +++ b/packages/devui-vue/docs/components/grid/index.md @@ -0,0 +1,316 @@ +# Grid 栅格 + +24栅格系统。 +### 何时使用 + +需要使用弹性布局时,并且需要适配不同的屏幕时,使用grid组件。 + + +### 基本用法 + +基础栅格 + +:::demo 使用 Row 和 Col组件,可以创建一个基本的栅格系统,Col必须放在Row里面。 + +```vue +<template> + <d-row> + <d-col :span="12">col-12</d-col> + <d-col :span="12">col-12</d-col> + </d-row> + <d-row> + <d-col :span="8">col-8</d-col> + <d-col :span="8">col-8</d-col> + <d-col :span="8">col-8</d-col> + </d-row> + <d-row> + <d-col :span="6">col-6</d-col> + <d-col :span="6">col-6</d-col> + <d-col :span="6">col-6</d-col> + <d-col :span="6">col-6</d-col> + </d-row> + <d-row> + <d-col :span="4">col-4</d-col> + <d-col :span="4">col-4</d-col> + <d-col :span="4">col-4</d-col> + <d-col :span="4">col-4</d-col> + <d-col :span="4">col-4</d-col> + <d-col :span="4">col-4</d-col> + </d-row> +</template> + +<style> +.devui-row:not(:last-of-type) { + margin-bottom: 20px; +} +.devui-col { + text-align: center; + min-height: 44px; + line-height: 44px; +} +.devui-col:nth-of-type(2n + 1) { + background: #f8f8f8; +} +.devui-col:nth-of-type(2n) { + background: #99b0ff; + color: #fff; +} +</style> +``` + +::: + +### 对齐 + +垂直对齐和水平对齐 + +:::demo 使用Row的align属性和justify属性子元素垂直对齐和水平对齐。 + +```vue +<template> + <p>Align top</p> + <d-row align="top"> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + </d-row> + <p>Align middle</p> + <d-row align="middle"> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + </d-row> + <p>Align bottom</p> + <d-row align="bottom"> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + <d-col :span="6" class="col-child">col-6</d-col> + </d-row> + <p>Justify bottom</p> + <d-row justify="start"> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + </d-row> + <p>Justify center</p> + <d-row justify="center"> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + </d-row> + <p>Justify end</p> + <d-row justify="end"> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + </d-row> + <p>Justify between</p> + <d-row justify="between"> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + </d-row> + <p>Justify around</p> + <d-row justify="around"> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + <d-col :span="4" class="col-child">col-4</d-col> + </d-row> +</template> + +``` + +::: + + +### 子元素的间隔 + +栅格之间的间隔可以用Row的gutter属性 + +:::demo :gutter="10" 子元素左右间隔为 5px;:gutter="[10, 20]" 子元素左右间隔为5px,上下间隔为10px;需要适配屏幕宽度的情况,:gutter="{ xs: 10, sm: 20, md: [20, 10], lg: [30, 20], xl: [40, 30], xxl: [50, 40] }" + +```vue +<template> + <d-row :gutter="10"> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + </d-row> + <d-row :gutter="[10, 20]"> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + </d-row> + <d-row :gutter="{ xs: 10, sm: 20, md: [20, 10], lg: [30, 20], xl: [40, 30], xxl: [50, 40]}"> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + <d-col :span="6" class="col-gutter"> + <div class="col-child">col-6</div> + </d-col> + </d-row> +</template> + +<style> +.col-gutter { + height: auto; + background: transparent !important; +} +.col-gutter:nth-of-type(2n + 1) > .col-child { + background: #f8f8f8 +} +.col-gutter:nth-of-type(2n) > .col-child { + background: #99b0ff; +} +</style> +``` + +::: + +### flex填充 + +Col的flex属性支持flex填充。 + +:::demo + +```vue +<template> + <d-row type="flex"> + <d-col :flex="2">2 / 5</d-col> + <d-col :flex="3">3 / 5</d-col> + </d-row> + <d-row type="flex"> + <d-col flex="100px">100px</d-col> + <d-col flex="auto">auto</d-col> + </d-row> + <d-row type="flex"> + <d-col flex="1 1 200px">1 1 200px</d-col> + <d-col flex="0 1 300px">0 1 300px</d-col> + </d-row> +</template> +``` + +::: + +### 左右偏移 + +使用Col的offset、pull和push来使子元素左右偏移。 + +:::demo 列偏移。使用 offset 可以将列向右侧偏。例如,offset={4} 将元素向右侧偏移了 4 个列(column)的宽度;offset、pull、push也可以内嵌到。 + +```vue +<template> + <d-row> + <d-col :span="8">col-8</d-col> + <d-col :span="8" :offset="8">col-8</d-col> + </d-row> + <d-row> + <d-col :span="6" :offset="6">col-6 col-offset-6</d-col> + <d-col :span="6" :offset="6">col-6 col-offset-6</d-col> + </d-row> + <d-row> + <d-col :span="12" :offset="6" :md="{ span: 22, offset: 1 }">col-12 col-offset-6</d-col> + </d-row> +</template> +``` + +::: + +### 响应式布局 + +预设六个响应尺寸:xs sm md lg xl xxl。 + +:::demo 参照 Bootstrap 的 [响应式设计](https://getbootstrap.com/docs/3.4/css/)。 + +```vue +<template> + <d-row> + <d-col :xs="2" :sm="4" :md="6" :lg="8" :xl="10">Col</d-col> + <d-col :xs="20" :sm="16" :md="12" :lg="8" :xl="4">Col</d-col> + <d-col :xs="2" :sm="4" :md="6" :lg="8" :xl="10">Col</d-col> + </d-row> +</template> +``` + +::: + +### 栅格排序 + +列排序。通过使用order、 push 和 pull 类就可以改变列(column)的顺。 + +:::demo 参照 Bootstrap 的 [响应式设计](https://getbootstrap.com/docs/3.4/css/)。 + +```vue +<template> + <d-row> + <d-col :span="18" :order="2">col-18 order-2</d-col> + <d-col :span="6" :order="1">col-6 order-1</d-col> + </d-row> + <d-row> + <d-col :span="18" :push="6">col-18 col-push-6</d-col> + <d-col :span="6" :pull="18">col-6 col-pull-18</d-col> + </d-row> +</template> +``` + +::: + +### d-grid + +d-row 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| align | `string` | `'top'` | flex 布局下的垂直对齐方式:`'top'`,`'middle'`,`'bottom'` | [垂直对齐](#垂直对齐) | | +| justify | `string` | `'start'` | flex 布局下的垂直对齐方式:`'start'`,`'end'`,`'center'`,`'space-around'`,`'space-between'` | [垂直对齐](#垂直对齐) | | +| gutter | `number\|array\|object` | 0 | 栅格间隔,数值形式:水平间距。对象形式支持响应式: { xs: 8, sm: 16, md: 24}。数组形式:[水平间距, 垂直间距]。 | [对齐](#对齐) | | +| wrap | `boolean` | false | 是否自动换行 | | | + +d-col 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | --------- | +| span | `number` | - | 栅格占位格数,为 0 时相当于 display: none | [基本用法](#基本用法) | | +| flex | `string\|number` | - | flex 布局填充 | [flex填充](#flex填充) | | +| offset | `number` | - | 栅格左侧的间隔格数,间隔内不可以有栅格 | [左右偏移](#左右偏移) | +| pull | `number` | - | 栅格向左移动格数 | [左右偏移](#左右偏移)、[栅格排序](#栅格排序) | +| push | `number` | - | 栅格向右移动格数 | [左右偏移](#左右偏移)、[栅格排序](#栅格排序) | +| order | `number` | - | 栅格顺序,flex 布局模式下有效 | [栅格排序](#栅格排序) | +| xs | `number\|object` | - | <576px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [栅格排序](#栅格排序) | +| sm | `number\|object` | - | >=576px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [响应式布局](#响应式布局) | +| md | `number\|object` | - | >=768px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [响应式布局](#响应式布局) | +| lg | `number\|object` | - | >=992px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [响应式布局](#响应式布局) | +| xl | `number\|object` | - | >=1200px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [响应式布局](#响应式布局) | +| xxl | `number\|object` | - | >=1600px 响应式栅格,可为栅格数或一个包含其他属性的对象 | [响应式布局](#响应式布局) | \ No newline at end of file diff --git a/packages/devui-vue/docs/components/icon/index.md b/packages/devui-vue/docs/components/icon/index.md new file mode 100644 index 0000000000000000000000000000000000000000..12e1d4b6532389d335104ba3722004392bcd1a48 --- /dev/null +++ b/packages/devui-vue/docs/components/icon/index.md @@ -0,0 +1,90 @@ +# Icon 图标 + +用于显示图标。 + +### 何时使用 + +需要显示图标时。 + +所有内置的图标可在DevUI官网进行查看: + +[https://devui.design/icon/ruleResource](https://devui.design/icon/ruleResource) + +### 基本用法 + +:::demo 通过`name`属性,指定需要显示的图标。 + +```vue +<d-icon name="like"></d-icon> +<d-icon name="https://devui.design/components/assets/logo.svg" size="16px"></d-icon> +``` + +::: + +### 图标颜色 + +:::demo 通过`color`属性指定图标的颜色。 + +```vue +<d-icon name="right-o" color="#50d4ab"></d-icon> +<d-icon name="error-o" color="#f95f5b"></d-icon> +``` + +::: + +### 图标大小 + +:::demo 通过`size`属性,设置图标大小。 + +```vue +<d-icon name="experice-new" size="32px"></d-icon> +<d-icon name="experice-new" size="48px"></d-icon> +``` + +::: + +### 自定义字体图标 + +Icon 组件默认引用 DevUI 图标库的图标,如果需要在现有 Icon 的基础上使用更多图标,可以引入第三方 iconfont 对应的字体文件和 CSS 文件,之后就可以在 Icon 组件中直接使用。 + +```css +@font-face { + font-family: "my-icon"; + src: url("./my-icon.ttf") format("truetype"); +} + +.my-icon { + font-family: "my-icon"; +} + +.my-icon-right::before { + content: "\E03F"; +} +``` + +引入字体图标的 css + +```css +@import "my-icon.css"; +``` + +or + +```js +import "my-icon.css"; +``` + +使用 + +```html +<d-icon class-prefix="my-icon" name="right" /> +``` + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | +| name | `String` | -- | 必选,Icon 名称 | [基本用法](#基本用法) | +| size | `String` | '16px' | 可选,图标大小 | [基本用法](#基本用法) | +| color | `String` | '#252b3a' | 可选,图标颜色 | [基本用法](#基本用法) | +| classPrefix | `String` | 'icon' | 可选,自定义字体图标前缀 | [自定义字体图标](#自定义字体图标) | diff --git a/packages/devui-vue/docs/components/image-preview/index.md b/packages/devui-vue/docs/components/image-preview/index.md new file mode 100644 index 0000000000000000000000000000000000000000..25ebc6a27049af2a5185fe823a83e3f6cb675e4f --- /dev/null +++ b/packages/devui-vue/docs/components/image-preview/index.md @@ -0,0 +1,123 @@ +# ImagePreview 图片预览 + +预览一张或多张图片的组件。 + +### 何时使用 + +需要根据用户传入进行图片预览展示或对容器内图片进行预览时。 + +### 基本用法 + +:::demo 使用 v-d-image-preview 指令,对容器内图片进行预览。 +```vue +<template> + <div v-d-image-preview class="devui-image-preview-demo"> + <img v-for="src in imageList" :src="src" :key="src" /> + </div> +</template> +<script> + import { defineComponent, ref, reactive } from 'vue' + export default defineComponent({ + setup() { + const _imageList = [ + 'https://devui.design/components/assets/image1.png', + 'https://devui.design/components/assets/image3.png' + ] + const imageList = ref(_imageList) + return { + imageList + } + } + }) +</script> + +<style lang="scss" scoped> +.devui-image-preview-demo { + display: flex; + flex-wrap: wrap; + margin-top: 10px; + img { + margin: 10px; + cursor: pointer; + } + .btn { + margin: 10px; + } +} +</style> +``` +::: + +### 自定义开启预览窗口 + +:::demo 传入 custom 参数,指令会自动注入 open 方法,通过 custom.open 开启预览窗口 +```vue +<template> + <div v-d-image-preview="{custom: image.custom, disableDefault:true }" class="devui-image-preview-demo"> + <img v-for="src in imageList" :src="src" :key="src" /> + </div> + <d-button @click="open" class="btn">自定义</d-button> +</template> +<script> + import { defineComponent, ref, reactive } from 'vue' + export default defineComponent({ + setup() { + const _imageList = [ + 'https://devui.design/components/assets/image1.png', + 'https://devui.design/components/assets/image3.png' + ] + const imageList = ref(_imageList) + const image = reactive({ + custom: {}, + imageList: _imageList + }) + function open() { + image.custom.open() + } + return { + imageList, + image, + open + } + } + }) +</script> + +<style lang="scss" scoped> +.devui-image-preview-demo { + display: flex; + flex-wrap: wrap; + margin-top: 10px; + img { + margin: 10px; + cursor: pointer; + } + .btn { + margin: 10px; + } +} +</style> +``` +::: + +### 设置 zIndex + +通过设置 zIndex 控制弹出效果的层级,设置 backDropZIndex 控制弹出层背景的层级。 +可以看到当设置 zIndex 小于 backDropZIndex 时,imagePreview 会显示在背景下方。 +可以通过 Esc 关闭 imagePreview。 + +``` +// 待嵌入 modal 组件即可 +``` + + +### API + +| 参数 | 类型 | 默认 | 说明 | +| :------------: | :-------: | :---: | :------------------------------------------------------------ | +| custom | `Object` | -- | 可选,指令会自动注入 open 方法,通过 custom.open 开启预览窗口 | +| disableDefault | `Boolean` | false | 可选,关闭默认点击触发图片预览方式 | +| zIndex | `Number` | 1050 | 可选,可选,设置预览时图片的 z-index 值 | +| backDropZIndex | `Number` | 1040 | 可选,设置预览时图片背景的 z-index 值 | + + diff --git a/packages/devui-vue/docs/components/input-number/index.md b/packages/devui-vue/docs/components/input-number/index.md new file mode 100644 index 0000000000000000000000000000000000000000..74bc4c9b08398f06b35d8c166ba634314826ad09 --- /dev/null +++ b/packages/devui-vue/docs/components/input-number/index.md @@ -0,0 +1,137 @@ +# InputNumber 数字输入框 + +数字输入框组件。 + +### 何时使用 + +当需要获取标准数值时。 + +### 基本用法 + +:::demo 使用它,只需要在d-input-number元素中使用v-model绑定变量即可,变量的初始值即为默认值。 + +```vue +<template> + <div> + <d-input-number v-model="num" @change="onChange" :max="10" :min="1" :placeholder="'请输入'"></d-input-number> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup(props,ctx){ + const num = ref(0) + const onChange = (val) => { + console.log(val) + } + return { + num, + onChange + } + } + }) +</script> +``` +::: + +### 禁用状态 + +:::demo disabled属性接受一个Boolean,设置为true即可禁用整个组件,如果你只需要控制数值在某一范围内,可以设置min属性和max属性,不设置min和max时,最小值为 0。 + +```vue +<template> + <div> + <d-input-number v-model="num" :disabled="true"></d-input-number> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup(props,ctx){ + const num = ref(0) + return { + num + } + } + }) +</script> +``` +::: + +### 步数 + +:::demo 设置step属性可以控制步长,接受一个Number。 + +```vue +<template> + <div> + <d-input-number v-model="num" :step="2"></d-input-number> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup(props,ctx){ + const num = ref(3) + return { + num + } + } + }) +</script> +``` +::: + +### 尺寸 + +:::demo 额外提供了 lg、normal、sm 三种尺寸的数字输入框。 + +```vue +<template> + <div> + <d-input-number v-model="num1" :size="'lg'"></d-input-number> + <d-input-number v-model="num2" :size="'normal'"></d-input-number> + <d-input-number v-model="num3" :size="'sm'"></d-input-number> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup(props,ctx){ + const num1 = ref(1) + const num2 = ref(2) + const num3 = ref(3) + return { + num1, + num2, + num3 + } + } + }) +</script> +``` +::: +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :-----------------------: | :---------------------------------: | +| step | `number` | 0 | 可选,步数 | [步数](#步数) | +| placeholder | `string` | -- | 可选,文本框 placeholder | [基本用法](#基本用法) | +| max | `number` | -- | 可选,输入框的最大值max | [基本用法](#基本用法) | +| min | `number` | -- | 可选,输入框的最小值min | [基本用法](#基本用法) | +| disabled | `boolean` | false | 可选,文本框是否被禁用 | [禁用状态](#禁用状态) | +| value | `number` | 0 | 可选,文本框默认值 | [基本用法](#基本用法) | +| size | `'lg'\|'normal'\|'sm'` | '' | 可选,文本框尺寸,有三种选择`'lg'`,`'narmal'`,`'sm'` | [尺寸](#尺寸) | + +### Events + +| 事件名称 | 说明 | 回调参数 | +| :---------: | :------: | :-------: | +| change | 绑定值被改变时触发 | (currentValue) | +| blur | 在组件 Input 失去焦点时触发 | (event: Event) | +| focus | 在组件 Input 获得焦点时触发 | (event: Event) | +| input | 在组件 Input 获得输入时触发 | (currentValue) | diff --git a/packages/devui-vue/docs/components/input/index.md b/packages/devui-vue/docs/components/input/index.md new file mode 100644 index 0000000000000000000000000000000000000000..f6fb8aa0e948882984737773436c8e98afbfbc8b --- /dev/null +++ b/packages/devui-vue/docs/components/input/index.md @@ -0,0 +1,96 @@ +# Input 输入框 + +文本输入框。 + +### 何时使用 + +需要手动输入文字使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <h4 style="margin: 10px 0">Default</h4> + + <d-input placeholder="Please Enter" autoFocus id="textInput" class="dinput"></d-input> + + <h4 style="margin: 10px 0">Disabled</h4> + + <d-input placeholder="Please Enter" :disabled="true" class="dinput"></d-input> + + <h4 style="margin: 10px 0">Error</h4> + + <d-input placeholder="Please Enter" :error="true" class="dinput"></d-input> +</template> +<style> + .dinput { + width: 200px; + } +</style> +``` + +::: + +### 尺寸 + +:::demo + +```vue +<template> + <h4 style="margin: 10px 0">Small</h4> + + <d-input size="sm" class="dinput" placeholder="Please Enter" ></d-input> + + <h4 style="margin: 10px 0">Middle</h4> + + <d-input class="dinput" placeholder="Please Enter"></d-input> + + <h4 style="margin: 10px 0">Large</h4> + + <d-input size="lg" placeholder="Please Enter" class="dinput"></d-input> +</template> +``` + +::: + + +### 密码框 + +:::demo + +```vue +<template> + <d-input v-model:value="searchText" class="dinput" placeholder="Please Enter" showPassword></d-input> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const searchText = ref('') + return { + searchText + } + }, +}) +</script> +``` + +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :------: | :-------: | :-----------------------: | :---------------------------------: | +| id | `string` | -- | 可选,文本框 id | [基本用法](#基本用法) | +| placeholder | `string` | -- | 可选,文本框 placeholder | [基本用法](#基本用法) | +| maxLength | `number` | Number.MAX_SAFE_INTEGER | 可选,输入框的 max-length | | +| disabled | `boolean` | false | 可选,文本框是否被禁用 | [基本用法](#基本用法) | +| error | `boolean` | false | 可选,文本框是否出现输入错误 | [基本用法](#基本用法) | +| size | `'sm'\|''\|'lg'` | '' | 可选,文本框尺寸,有三种选择`'lg'`,`''`,`'sm'` | [尺寸](#尺寸) | +| cssClass | `string` | '' | 可选,支持传入类名到输入框上 | | +| showPassword | `boolean` | false | 可选,密码输入框 | [密码框](#密码框) | +| autoFocus | `boolean` | false | 可选,输入框是否自动对焦 | [基本用法](#基本用法) | + diff --git a/packages/devui-vue/docs/components/layout/index.md b/packages/devui-vue/docs/components/layout/index.md new file mode 100644 index 0000000000000000000000000000000000000000..cccf1a837546cddc5e947fecd1c025fc55a19f0c --- /dev/null +++ b/packages/devui-vue/docs/components/layout/index.md @@ -0,0 +1,382 @@ +# Layout 布局 + +页面的布局方式。 + +### 何时使用 + +当用户需要直接使用一些既有布局时。 + +### 基本用法 + +::: demo + +```vue +<template> + <d-layout> + <d-header class="dheader">Header</d-header> + <d-content>Content</d-content> + <d-footer class="dfooter">Footer</d-footer> + </d-layout> +</template> + +<style> + .dheader, .dfooter { + background: #333854; + color: #fff; + text-align: center; + line-height: 40px; + } +</style> +``` + +::: + +:::demo + +```vue +<template> + <d-layout> + <d-header class="dheader">Header</d-header> + <d-layout> + <d-aside class="daside">Aside</d-aside> + <d-content class="main-content">Content</d-content> + </d-layout> + <d-footer class="dfooter">Footer</d-footer> + </d-layout> +</template> + +<style> + .dheader, .dfooter { + background: #333854; + color: #fff; + text-align: center; + line-height: 40px; + } + .daside { + background: #f8f8f8; + width: 100px; + min-height: 200px; + display: flex; + align-items: center; + justify-content: center; + } +</style> +``` + +::: + +:::demo + +```vue +<template> + <d-layout> + <d-header class="dheader">Header</d-header> + <d-layout> + <d-content class="main-content">Content</d-content> + <d-aside class="daside">Aside</d-aside> + </d-layout> + <d-footer class="dfooter">Footer</d-footer> + </d-layout> +</template> + +<style> + .dheader, .dfooter { + background: #333854; + color: #fff; + text-align: center; + line-height: 40px; + } +</style> +``` + +::: + +:::demo + +```vue +<template> + <d-layout> + <d-aside class="daside">Aside</d-aside> + <d-layout> + <d-header class="dheader">Header</d-header> + <d-content class="main-content">Content</d-content> + <d-footer class="dfooter">Footer</d-footer> + </d-layout> + </d-layout> +</template> + +<style> + .daside { + background: #f8f8f8; + width: 100px; + min-height: 200px; + display: flex; + align-items: center; + justify-content: center; + } + .dheader, .dfooter { + background: #333854; + color: #fff; + text-align: center; + line-height: 40px; + min-height: 40px; + } + .main-content { + line-height: 200px; + text-align: center; + } +</style> +``` + +::: + +### 应用场景1 + +常用上中下布局。 + +:::demo + +```vue +<template> + <d-layout> + <d-header class="dheader-1"> + <div class="logo"> + <span class="logo-devui"> + <img src="https://devui.design/components/assets/logo.svg" width="26" height="26" /> + </span> + <span class="text">DevUI</span> + </div> + </d-header> + <d-content class="dcontent-1"> + <d-breadcrumb class="dbreadcrumb"> + <d-breadcrumb-item> + <span>DevUI</span> + </d-breadcrumb-item> + <d-breadcrumb-item> + <span>面包屑</span> + </d-breadcrumb-item> + </d-breadcrumb> + <div class="inner-content"></div> + </d-content> + <d-footer class="dfooter-1">footer</d-footer> + </d-layout> +</template> + +<style> + .dheader-1 { + text-align: left; + position: relative; + height: 40px; + background-color: #333854; + color: #fff; + } + .dheader-1 .logo { + position: absolute; + left: 0; + margin-left: 40px; + height: 40px; + width: 120px; + color: #fff; + font-size: 16px; + line-height: 40px; + } + .dheader-1 .logo .logo-devui { + margin-top: 8px; + } + + .dheader-1 .logo .logo-devui, + .dheader-1 .logo .text { + display: inline-block; + vertical-align: top; + } + .dcontent-1 { + padding: 0 40px; + height: 300px; + background-color: #f3f6f8; + } + .dcontent-1 .dbreadcrumb { + margin: 8px 0; + } + .dcontent-1 .inner-content { + background-color: #fff; + height: 100%; + } + .dfooter-1 { + background: #333854; + color: #fff; + text-align: center; + line-height: 40px; + min-height: 40px; + } +</style> + +``` + +::: + +### 应用场景2 + +常用上中下布局及侧边栏布局。 + +:::demo + +```vue +<template> + <d-layout class="dlayout-2"> + <d-header class="dheader-2"> + <div class="logo"> + <span class="logo-devui"> + <img src="https://devui.design/components/assets/logo.svg" width="26px" height="26px" /> + </span> + <span class="text">DevUI</span> + </div> + </d-header> + <d-layout> + <d-aside class="daside-2"> + <d-accordion :data="menu" class="menu"></d-accordion> + </d-aside> + <d-content class="dcontent-2"> + <d-breadcrumb class="dbreadcrumb"> + <d-breadcrumb-item> + <span>DevUI</span> + </d-breadcrumb-item> + <d-breadcrumb-item> + <span>面包屑</span> + </d-breadcrumb-item> + </d-breadcrumb> + <div class="inner-content"></div> + </d-content> + </d-layout> + <d-footer class="dfooter-2">footer</d-footer> + </d-layout> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const menu = ref([ + { + title: '内容一', + open: true, + children: [{ title: '子内容1' }, { title: '子内容2' }, { title: '子内容3' }], + }, + { + title: '内容二', + children: [{ title: '子内容1' }, { title: '子内容2' }, { title: '子内容3' }], + }, + { + title: '内容三(默认展开)', + open: true, + children: [{ title: '子内容1(禁用)', disabled: true }, { title: '子内容2(默认激活)', active: true }, { title: '子内容3' }], + }, + ]) + return { + menu + } + } +}) + +</script> + +<style> + .dlayout-2 { + background-color: #fff; + } + .dlayout-2 li { + list-style: none; + } + + .daside-2 { + border-left: 1px solid transparent; + } + + .dheader-2 { + text-align: left; + height: 40px; + background-color: #333854; + position: relative; + + } + .dheader-2 .search { + color: #fff; + margin-right: 40px; + position: absolute; + right: 0; + } + + .dheader-2 .logo { + position: absolute; + left: 0; + margin-left: 20px; + height: 40px; + width: 120px; + color: #fff; + font-size: 16px; + line-height: 40px; + } + .dheader-2 .logo .logo-devui { + margin-top: 8px; + } + .dheader-2 .logo .logo-devui, + .dheader-2 .logo .text { + display: inline-block; + vertical-align: top; + } + + .dcontent-2 { + padding: 0 40px; + background-color: #f3f6f8; + } + .dcontent-2 .inner-content { + background-color: #fff; + padding: 16px; + height: 100%; + } + .dcontent-2 .dbreadcrumb { + margin-top: 8px; + } + .dfooter-2 { + color: #fff; + background-color: #333854; + padding: 8px 24px; + } + +</style> + +``` + +::: + +### API + +在页面中使用: + +```html +<d-layout> + <d-header></d-header> + <d-content></d-content> + <d-footer></d-footer> +</d-layout> +``` + +### d-layout + +布局容器,可以与<code>d-header</code>, <code>d-content</code>, <code>d-footer</code>, <code>d-aside</code>组合实现布局; <code>d-layout</code>下可嵌套元素:<code>d-header</code>, <code>d-content</code>, <code>d-aside</code>, <code>d-layout</code>。 + +### d-header + +顶部布局,只能放在<code>d-layout</code>容器中,作为<code>d-layout</code>容器的顶部实现。 默认高度:40px。 + +### d-footer + +底部布局,只能放在<code>d-layout</code>容器中,作为<code>d-layout</code>容器的底部实现。 + +### d-content + +内容容器,只能放在<code>d-layout</code>容器中,作为<code>d-layout</code>容器<code>d-header</code>与<code>d-footer</code>之间的内容。 + +### d-aside + +侧边栏,只能放在<code>d-layout</code>容器中,作为<code>d-layout</code>容器的侧边栏部分。 \ No newline at end of file diff --git a/packages/devui-vue/docs/components/loading/index.md b/packages/devui-vue/docs/components/loading/index.md new file mode 100644 index 0000000000000000000000000000000000000000..3d2ca412e34166f869904c44c2a9bef3c308659b --- /dev/null +++ b/packages/devui-vue/docs/components/loading/index.md @@ -0,0 +1,341 @@ +# Loading 加载提示 + +提示用户页面正在执行指令,需要等待。 + +### 何时使用 + +当执行指令时间较长(需要数秒以上)时,向用户展示正在执行的状态。 + +### 基本用法 + +展示加载表格数据的场景中的基本使用方法。 +:::demo + +```vue +<template> + <d-button @click="fetchTableData" style="margin-top: 8px">click me!</d-button> + <table + v-dLoading="loadingStatus" + :backdrop="true" + positionType="relative" + :view="{ top: '50%', left: '50%' }" + :zIndex="100" + style="width: 100%; text-align: left;" + > + <thead> + <tr> + <th>序号</th> + <th>姓名</th> + <th>队伍</th> + <th>操作</th> + </tr> + </thead> + <tbody> + <tr v-for="(val, index) in datas" :key="index"> + <td>{{ index }}</td> + <td>张家齐</td> + <td>跳水</td> + <td>跳水队</td> + </tr> + </tbody> + </table> +</template> + +<script> +import { defineComponent, ref, reactive } from 'vue' + +export default defineComponent({ + setup() { + const loadingStatus = ref(false) + const datas = reactive([]) + const fetchTableData = () => { + loadingStatus.value = true + + setTimeout(() => { + datas.push(1, 2, 3) + loadingStatus.value = false + }, 2000) + } + + return { + datas, + loadingStatus, + fetchTableData + } + } +}) +</script> +``` + +::: + +### 多 promise + +支持多个 promise。 +:::demo + +```vue +<template> + <d-button @click="fetchMutiplePromise" style="margin-top: 8px">click me!</d-button> + + <div + v-dLoading="promises" + message="One moment please..." + style="margin-top: 20px; width: 100%; height: 80px; padding: 10px;" + > + loading will show here2 + </div> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const promises = ref([]) + const fetchMutiplePromise = () => { + let list = [] + for (let i = 0; i < 3; i++) { + list.push( + new Promise((res, rej) => { + setTimeout(() => { + res(i) + }, (i + 1) * 1000) + }).then((res) => { + return res + }) + ) + } + promises.value = list + } + + return { + promises, + fetchMutiplePromise + } + } +}) +</script> +``` + +::: + +### 自定义样式 + +通过 templateRef 自定义 loading 样式。 +:::demo + +```vue +<template> + <d-button :width="220" @click="showLoading1" style="margin-right: 8px; display: inline-block;"> + Loading Style 1 + </d-button> + + <d-button + :width="220" + v-dLoading="isShowLoading2" + @click="showLoading2" + :loadingTemplateRef="temp2" + style="margin-right: 8px; display: inline-block;" + > + Loading Style 2 + </d-button> + + <d-button + v-dLoading="true" + bsStyle="text" + :width="220" + :loadingTemplateRef="temp3" + style="margin-right: 8px; display: inline-block;" + > + Loading Style 3 + </d-button> + + <div + style="height: 80px; line-height: 80px" + v-dLoading="isShowLoading1" + :loadingTemplateRef="temp1" + > + loading will show here1 + </div> +</template> + +<script> +import { defineComponent, ref, h } from 'vue' + +export default defineComponent({ + setup() { + const temp1 = h( + 'div', + { + className: 'devui-infinity-loading' + }, + h('i', { + className: 'icon-refresh' + }) + ) + + const temp2 = h( + 'div', + { + className: 'devui-circle-loading-container-2' + }, + h('i', { + className: 'icon-refresh' + }) + ) + + const temp3 = h( + 'div', + { + className: 'devui-circle-loading-container-3' + }, + h('i', { + className: 'icon-refresh' + }) + ) + + const isShowLoading1 = ref(false) + const showLoading1 = () => { + isShowLoading1.value = new Promise((res) => { + setTimeout(() => { + res(true) + }, 1000) + }) + } + + const isShowLoading2 = ref(false) + const showLoading2 = () => { + isShowLoading2.value = new Promise((res) => { + setTimeout(() => { + res(true) + }, 1000) + }) + } + + return { + temp1, + temp2, + temp3, + isShowLoading1, + isShowLoading2, + showLoading1, + showLoading2 + } + } +}) +</script> + +<style> +.devui-infinity-loading { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +.devui-circle-loading-container-2 { + position: absolute; + left: 5px; + top: 50%; + transform: translateY(-50%); +} + +.devui-circle-loading-container-3 { + position: absolute; + right: -20px; + top: 50%; + transform: translateY(-50%); +} +</style> +``` + +::: + +### 服务方式调用 + +使用服务的方式全屏加载 loading 组件或者在指定宿主上加载 loading 组件。 +:::demo + +```vue +<template> + <d-button :width="220" @click="serviceToBody" style="margin-right: 8px; display: inline-block;"> + click me show full screen loading! + </d-button> + + <d-button + :width="200" + v-if="isShow" + @click="openTargetLoading" + style="margin-right: 8px; display: inline-block;" + > + click me show loading in target! + </d-button> + + <d-button + :width="200" + v-else + bsStyle="common" + @click="closeTargetLoading" + style="margin-right: 8px; display: inline-block;" + > + click me close loading in target! + </d-button> + + <div id="me" style="margin-top: 20px; width: 100%; height: 60px; padding: 10px;"> + loading will show here3 + </div> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default { + data() { + return { + isShow: true, + resultTarget: null + } + }, + methods: { + serviceToBody() { + const results = this.$loadingService.open() + + setTimeout(() => { + results.loadingInstance.close() + }, 2000) + }, + openTargetLoading() { + this.resultTarget = this.$loadingService.open({ + target: document.querySelector('#me'), + message: 'One moment please...', + positionType: 'relative', + zIndex: 1 + }) + this.isShow = false + }, + closeTargetLoading() { + this.resultTarget.loadingInstance.close() + this.isShow = true + } + } +} +</script> +``` + +::: + +### 参数 + +dLoading 参数 + +| **参数** | **类型** | **默认** | **说明** | **跳转 Demo** | +| ------------------ | ------------------------------------------------------------- | --------------------------- | --------------------------------------------------------------------- | ----------------------------- | +| v-dLoading | `Promise<any> \| Array<Promise<any>> \| Boolean \| undefined` | -- | 可选,指令方式,控制 loading 状态 | [基本用法](#基本用法) | +| target | `element` | document.body | 可选,服务方式,Loading 需要覆盖的 DOM 节点 | [服务方式调用](#服务方式调用) | +| message | `string` | -- | 可选,loading 时的提示信息 | [多 promise](#多promise) | +| loadingTemplateRef | `VNode` | -- | 可选,自定义 loading 模板 | [自定义样式](#自定义样式) | +| backdrop | `boolean` | true | 可选,loading 时是否显示遮罩 | [基本用法](#基本用法) | +| positionType | `string` | relative | 可选,指定`dLoading`宿主元素的定位类型,取值与 css position 属性一致。 | [基本用法](#基本用法) | +| view | `{top?:string,left?:string} ` | `{top: '50%', left: '50%'}` | 可选,调整 loading 的显示位置,相对于宿主元素的顶部距离与左侧距离 | [基本用法](#基本用法) | +| zIndex | `number` | -- | 可选,loading 加载提示的 z-index 值 | [基本用法](#基本用法) | diff --git a/packages/devui-vue/docs/components/modal/index.md b/packages/devui-vue/docs/components/modal/index.md new file mode 100644 index 0000000000000000000000000000000000000000..cda89377815b812d4eccb89305b601dbd56c16b4 --- /dev/null +++ b/packages/devui-vue/docs/components/modal/index.md @@ -0,0 +1,395 @@ +# Modal 模态弹窗 +模态对话框。 +### 何时使用 +1.需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。 + +2.弹窗起到与用户进行交互的作用,用户可以在对话框中输入信息、阅读提示、设置选项等操作。 + +#### 标准对话框 +使用dialogService可拖拽的标准对话框。 +:::demo +```vue +<template> + <d-button @click="open">打开 modal</d-button> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const modalservice = inject('DIALOG_SERVICE_TOKEN'); + const open = () => { + const result = modalservice.open({ + title: 'Start Snapshot Version', + content: () => ( + h('div', {}, [ + 'Modal Content', + h('div', {}, ['name: Tom']), + h('div', {}, ['age: 10']), + h('div', {}, ['address: Chengdu']), + ]) + ), + buttons: [{ + btnStyle: 'primary', + text: 'Ok', + handler: () => result.hide(), + }, { + btnStyle: 'common', + text: 'Cancel', + handler: () => result.hide() + }] + }); + } + return { + open, + } + } +}) +</script> +``` +::: + +#### 自定义对话框 +使用modalService可以自定义对话框内的所有内容。 +:::demo + +```vue +<template> + <div>👷施工中</div> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + } +}) +</script> + +``` +::: + +#### 拦截对话框关闭 +通过 beforeHidden 设置在关闭弹出框时的拦截方法。 +:::demo + +```vue +<template> + <d-button btnStyle="common" @click="open">click me!</d-button> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const dialogService = inject('DIALOG_SERVICE_TOKEN'); + const open = () => { + const result = dialogService.open({ + title: 'Start Snapshot Version', + content: () => ( + h('div', {}, [ + 'Modal Content', + h('div', {}, ['name: Tom']), + h('div', {}, ['age: 10']), + h('div', {}, ['address: Chengdu']), + ]) + ), + dialogtype: 'standard', + beforeHidden: beforeHidden, + backdropCloseable: true, + buttons: [{ + btnStyle: 'primary', + text: 'Save', + handler: () => result.hide(), + }] + }); + } + + const beforeHidden = () => { + return new Promise((resolve) => { + const results = dialogService.open({ + width: '300px', + maxHeight: '600px', + title: '', + content: () => 'Do you want to save the modification before closing the page?', + backdropCloseable: false, + dialogtype: 'warning', + buttons: [{ + btnStyle: 'primary', + text: 'Save', + handler() { + results.hide(); + resolve(true); + } + }, { + btnStyle: 'common', + text: 'Cancel', + handler() { + results.hide(); + resolve(true); + } + }] + }); + }); + } + + return { open }; + } +}) +</script> + +``` +::: + + +#### 信息提示 +各种类型的信息提示框。 +:::demo +```vue +<template> + <div class="btn-group"> + <d-button btnStyle="common" @click="open('success', '成功', 'Delete [Git] repository successfully.')">success</d-button> + <d-button btnStyle="common" @click="open('failed', '错误', 'It is failed. if you want to resolve it,please contact the supportor.')">fail</d-button> + <d-button btnStyle="common" @click="open('warning', '警告', 'Leaving this page!')">warning</d-button> + <d-button btnStyle="common" @click="open('info', '提示', 'You signed in with another tab or window. Reload to refresh your session.')">info</d-button> + </div> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const dialogService = inject('DIALOG_SERVICE_TOKEN'); + const open = (type, title, content) => { + const result = dialogService.open({ + title, + content: () => h('span', {style: {fontSize: '12px'} }, content), + dialogType: type, + backdropCloseable: true, + buttons: [{ + btnStyle: 'primary', + text: 'Save', + handler: () => result.hide(), + }] + }); + } + + return { open }; + } +}) +</script> +<style> + .btn-group > * { + margin-right: 8px; + } +</style> +``` +::: + +#### 更新标准弹出框按钮状态 +通过update方法来更新dialog配置的buttons配置。 +:::demo +```vue +<template> + <d-button @click="open">打开 modal</d-button> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const modalservice = inject('DIALOG_SERVICE_TOKEN'); + const open = () => { + const result = modalservice.open({ + title: 'Start Snapshot Version', + content: () => ( + h('div', { + onMouseover() { + result.updateButtonOptions([{disabled: true}]); + } + }, [ + 'Modal Content', + h('div', {}, ['name: Tom']), + h('div', {}, ['age: 10']), + h('div', {}, ['address: Chengdu']), + ]) + ), + buttons: [{ + btnStyle: 'primary', + text: 'Ok', + handler: () => result.hide(), + }, { + btnStyle: 'common', + text: 'Cancel', + handler: () => result.hide() + }] + }); + } + return { + open, + } + } +}) +</script> +``` +::: + +#### 配置按钮自动获得焦点 +配置dialogService的buttons中的autofocus属性可以设置按钮自动获得焦点,可以通过回车直接触发按钮点击。 +:::demo +```vue +<template> + <d-button @click="open">打开 modal</d-button> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const modalservice = inject('DIALOG_SERVICE_TOKEN'); + const open = () => { + const result = modalservice.open({ + title: 'Start Snapshot Version', + content: () => ( + h('div', { + onMouseover() { + result.updateButtonOptions([{disabled: true}]); + } + }, [ + 'Modal Content', + h('div', {}, ['name: Tom']), + h('div', {}, ['age: 10']), + h('div', {}, ['address: Chengdu']), + ]) + ), + buttons: [{ + btnStyle: 'primary', + text: 'Ok', + autofocus: true, + handler: () => result.hide(), + }, { + btnStyle: 'common', + text: 'Cancel', + handler: () => result.hide() + }] + }); + } + return { + open, + } + } +}) +</script> +``` +::: + +#### 通过外层fixed同时避免滚动和抖动 +通过外层fixed同时避免滚动和抖动,在使用这种方式时,页面内所有fixed元素需要给定具体的位置值,使用默认定位值会导致位置偏移。 +:::demo +```vue +<template> + <d-button @click="open">打开 modal</d-button> +</template> +<script> +import {ref, defineComponent, inject, onMounted, h} from 'vue'; +export default defineComponent({ + setup() { + const modalservice = inject('DIALOG_SERVICE_TOKEN'); + const open = () => { + const result = modalservice.open({ + bodyScrollable: false, + title: 'Start Snapshot Version', + content: () => ( + h('div', {}, [ + 'Modal Content', + h('div', {}, ['name: Tom']), + h('div', {}, ['age: 10']), + h('div', {}, ['address: Chengdu']), + ]) + ), + buttons: [{ + btnStyle: 'primary', + text: 'Ok', + handler: () => result.hide(), + }, { + btnStyle: 'common', + text: 'Cancel', + handler: () => result.hide() + }] + }); + } + return { + open, + } + } +}) +</script> +``` +::: + + +### API +Modal 和 Dialog 均以 service 方式来构造。 + +他们通过这种方式引入: +```vue + +{ + setup() { + const modalService = inject('MODAL_SERVICE_TOKEN'); + const dialogService = inject('DIALOG_SERVICE_TOKEN'); + } +} +``` +#### Modal + +ModalService.open(props: ModalOptions) + +ModalOptions 属性 + +| 属性 | 类型 | 默认 | 说明 | +| :---------------: | :-------------------------------------------------------: | :------: | :----------------------------------------------- | +| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | +| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | +| backdropZIndex | `number` | 1049 | 可选,如果为 true,背景不能滚动 | +| placement | `'center' \| 'top' \| 'bottom'` | 'center' | 可选,弹出框出现的位置 | +| offsetX | `string` | '0px' | 可选,弹出框纵向偏移 | +| offsetY | `string` | '0px' | 可选,弹出框横向偏移 | +| bodyScrollable | `boolean` | true | 可选,modal 打开后,body是否可滚动,默认可滚动。 | +| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框 | +| showAnimation | `boolean` | true | 可选,是否显示动画 | +| escapable | `boolean` | true | 可选,点击背景触发的事件 | +| content | `Slot` | true | 可选,弹出框内容 | +| onClose | `() => void` | -- | 可选,弹出框关闭之后回调的函数 | +| beforeHidden | `(() => Promise<boolean> \| boolean) \| Promise<boolean>` | -- | 可选,关闭窗口之前的回调 | + +#### Dialog + +DialogService.open(props: DialogOptions) + +DialogOptions 属性 + +| 属性 | 类型 | 默认 | 说明 | +| :---------------: | :-------------------------------------------------------: | :--------: | :----------------------------------------------------- | +| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | +| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | +| backdropZIndex | `number` | 1049 | 可选,如果为 true,背景不能滚动 | +| placement | `'center' \| 'top' \| 'bottom'` | 'center' | 可选,弹出框出现的位置 | +| offsetX | `string` | '0px' | 可选,弹出框纵向偏移 | +| offsetY | `string` | '0px' | 可选,弹出框横向偏移 | +| bodyScrollable | `boolean` | true | 可选,modal 打开后,body是否可滚动,默认可滚动。 | +| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框 | +| showAnimation | `boolean` | true | 可选,是否显示动画 | +| escapable | `boolean` | true | 可选,点击背景触发的事件 | +| draggable | `boolean` | true | 可选,弹出框是否可拖拽 | +| dialogType | `'standard'\|'success'\|'failed'\|'warning'\|'info'` | 'standard' | 可选,弹出框类型,有四种选择 | +| title | `string` | -- | 可选,弹出框 title | +| content | `Slot` | -- | 可选,弹出框内容,支持字符串和组件 | +| buttons | `ButtonOptions[]` | [] | 可选,弹出框按钮,支持自定义文本、样式、禁用、点击事件 | +| onClose | `() => void` | -- | 可选,弹出框关闭之后回调的函数 | +| beforeHidden | `(() => Promise<boolean> \| boolean) \| Promise<boolean>` | -- | 可选,关闭窗口之前的回调 | + +### Other + +ButtonOptions 定义 +| 属性 | 类型 | 默认 | 说明 | +| :-------: | :-----------------------: | :---: | :----------------- | +| text | `string` | -- | 可选,按钮文本内容 | +| handler | `($event: Event) => void` | -- | 可选,按钮点击事件 | +| autofocus | `boolean` | false | 可选,自动聚焦 | +| disabled | `boolean` | false | 可选,禁用按钮 | + diff --git a/packages/devui-vue/docs/components/nav-sprite/index.md b/packages/devui-vue/docs/components/nav-sprite/index.md new file mode 100644 index 0000000000000000000000000000000000000000..10fcbfff453a55d140523f5309b53cb211b96b87 --- /dev/null +++ b/packages/devui-vue/docs/components/nav-sprite/index.md @@ -0,0 +1,9 @@ +# NavSprite 导航精灵 + +导航精灵组件 + +### 何时使用 + +针对某块阅读区域生成阅读目录,提高阅读效率。 + +### 基本用法 diff --git a/packages/devui-vue/docs/components/overlay/index.md b/packages/devui-vue/docs/components/overlay/index.md new file mode 100644 index 0000000000000000000000000000000000000000..7d604b356d6046ecc2c653440c4c767f0b0a4bf0 --- /dev/null +++ b/packages/devui-vue/docs/components/overlay/index.md @@ -0,0 +1,224 @@ +# 遮罩层 +遮罩层属于基础组件,用于构建独立于当前页面布局的组件。 +### 何时使用 +当你需要全局弹窗,或者需要元素跟随功能,便可以使用该组件。 +### 固定遮罩层 + +:::demo 使用`sm`,`''`,`lg`来定义`Search`基本类型 + +```vue +<template> + <d-button @click="handleClick" style="width: 100px;">{{title}}</d-button> + <d-fixed-overlay + v-model:visible="visible" + backgroundClass="justify-center items-center bg-gray-50" + backgroundBlock + > + <div class="h-100 w-100" style="background: red;">hello world</div> + </d-fixed-overlay> +</template> +<script> +import { defineComponent, ref, computed } from 'vue'; +export default defineComponent({ + setup() { + const origin = ref(); + const visible = ref(false); + const handleClick = () => visible.value = !visible.value; + const title = computed(() => visible.value ? '隐藏' : '显示固定遮罩层' ); + return { + visible, + handleClick, + title + } + }, +}); +</script> +``` +::: + + +### 弹性遮罩层 + +:::demo +```vue +<template> + <div class="h-500 w-full flex flex-column items-center justify-center"> + <div + ref="origin" + class="flex items-center justify-center h-100 w-100 text-white bg-gray" + >orgin</div> + <d-button @click="handleVisible" style="margin: 20px;">{{title}}</d-button> + <div class="w-full mt-20"> + <div class="flex mt-20"> + <span style="width: 200px">依赖元素的 X 轴:</span> + <d-radio-group v-model="position.originX" :values="horizontalProps" css-style="row"/> + </div> + <div class="flex mt-20"> + <span style="width: 200px">依赖元素的 Y 轴:</span> + <d-radio-group v-model="position.originY" :values="verticalProps" css-style="row"/> + </div> + <div class="flex mt-20"> + <span style="width: 200px">Overlay X 轴:</span> + <d-radio-group v-model="position.overlayX" :values="horizontalProps" css-style="row"/> + </div> + <div class="flex mt-20"> + <span style="width: 200px">Overlay Y 轴:</span> + <d-radio-group v-model="position.overlayY" :values="verticalProps" css-style="row"/> + </div> + </div> + </div> + + <d-flexible-overlay + :origin="origin" + v-model:visible="visible" + :position="position" + > + <div + class="flex items-center justify-center text-white-50 h-100 w-100" + style="background: #673ab7;" + >hello world</div> + </d-flexible-overlay> +</template> +<script> +import { defineComponent, ref, computed, reactive } from 'vue' + +export default defineComponent({ + setup() { + const origin = ref(); + const visible = ref(false); + const title = computed(() => visible.value ? '隐藏' : '显示') + const handleVisible = () => visible.value = !visible.value; + + const horizontalProps = ['left', 'center', 'right']; + const verticalProps = ['top', 'center', 'bottom']; + const position = reactive({ + originX: 'left', + originY: 'top', + overlayX: 'left', + overlayY: 'top' + }); + + return { + origin, + visible, + handleVisible, + title, + position, + verticalProps, + horizontalProps + } + } +}) +</script> +``` + +::: + +<style> +.flex { + display: flex; +} + +.flex-column { + flex-direction: column; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.h-100 { + height: 100px; +} + +.w-100 { + width: 100px; +} + +.text-white { + color: white; +} + +.bg-gray { + background: gray; +} + +.h-500 { + height: 500px; +} + +.w-full { + width: 100%; +} + +.bg-gray-50 { + background: #00000088; +} + +.text-white-50 { + color: #ffffff88; +} + +.mt-20 { + margin-top: 20px; +} +</style> + + +### API +d-fixed-overlay 参数 + +| 参数 | 类型 | 默认 | 说明 | +| :--------------: | :------------------------: | :---: | :-------------------------------------------------------------------- | +| visible | `boolean` | false | 可选,遮罩层是否可见 | +| onUpdate:visible | `(value: boolean) => void` | -- | 可选,遮罩层取消可见事件 | +| backgroundBlock | `boolean` | false | 可选,如果为 true,背景不能滚动 | +| backgroundClass | `string` | -- | 可选,背景的样式类 | +| backgroundStyle | `StyleValue` | -- | 可选,背景的样式 | +| backdropClick | `() => void` | -- | 可选,点击背景触发的事件 | +| backdropClose | `boolean` | false | 可选,如果为true,点击背景将触发 `onUpdate:visible`,默认参数是 false | +| hasBackdrop | `boolean` | true | 可选,如果为false,背景元素的 `point-event` 会设为 `none`,且不显示默认背景 | +| overlayStyle | `CSSProperties` | -- | 可选,遮罩层的样式 | + +d-flexible-overlay 参数 + +| 参数 | 类型 | 默认 | 说明 | +| :--------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---: | :---------------------------------------------------------------- | +| visible | `boolean` | false | 可选,遮罩层是否可见 | +| onUpdate:visible | `(value: boolean) => void` | -- | 可选,遮罩层取消可见事件 | +| backgroundBlock | `boolean` | false | 可选,如果为 true,背景不能滚动 | +| backgroundClass | `string` | -- | 可选,背景的样式类 | +| backgroundStyle | `StyleValue` | -- | 可选,背景的样式 | +| backdropClick | `() => void` | -- | 可选,点击背景触发的事件 | +| backdropClose | `boolean` | false | 可选,如果为true,点击背景将触发 `onUpdate:visible`,参数是 false | +| hasBackdrop | `boolean` | true | 可选,如果为false,背景元素的 `point-event` 会设为 `none`,且不显示默认背景 | +| origin | `Element \| ComponentPublicInstance \| Rect` | false | 必选,你必须指定起点元素才能让遮罩层与该元素连接在一起 | +| position | `ConnectionPosition` | false | 可选,指定遮罩层与原点的连接点 | + +Rect 数据结构 +```typescript +interface Rect { + x: number + y: number + width?: number + height?: number +} +``` + +ConnectionPosition 数据结构 +```typescript +type HorizontalConnectionPos = 'left' | 'center' | 'right'; +type VerticalConnectionPos = 'top' | 'center' | 'bottom'; + +export interface ConnectionPosition { + originX: HorizontalConnectionPos + originY: VerticalConnectionPos + overlayX: HorizontalConnectionPos + overlayY: VerticalConnectionPos +} +``` + diff --git a/packages/devui-vue/docs/components/pagination/index.md b/packages/devui-vue/docs/components/pagination/index.md new file mode 100644 index 0000000000000000000000000000000000000000..dad91b8a72be43a9b2158af8a8de15e14752e51a --- /dev/null +++ b/packages/devui-vue/docs/components/pagination/index.md @@ -0,0 +1,473 @@ +# Pagination 分页 + +分页器。 + +### 何时使用 + +当加载/渲染所有数据将花费很多时间时,可以切换页码浏览数据。 + + +### 基本用法 + +:::demo + +```vue +<template> + <h5 style="padding: 20px 0 10px;">size = 'sm'</h5> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + /> + + <h5 style="padding: 20px 0 10px;">size = 'md'</h5> + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + /> + + <h5 style="padding: 20px 0 10px;">size = 'lg'</h5> + <d-pagination + size="lg" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + /> + + <h5 style="padding: 20px 0 10px;">Custom Style</h5> + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + goToText="Jump to" + :preLink="preLink" + :nextLink="nextLink" + /> +</template> +<script> +import { defineComponent, shallowReactive, h } from 'vue' + +export default defineComponent({ + setup() { + const pager = shallowReactive({ + total: 306, + pageIndex: 5, + pageSize: 10, + pageSizeOptions: [10, 20, 30, 40, 50] + }) + + const preLink = '<span class="icon-arrow-left"></span>'; + const nextLink = '<span class="icon-arrow-right"></span>'; + + return { + pager, + preLink, + nextLink + } + } +}) +</script> +``` +::: + + +### 极简模式 +极简模式适用于一些有大量信息的页面,可以简化页面的复杂度。 +:::demo + + +```vue +<template> + <h5 style="padding: 20px 0 10px;">Simple Mode</h5> + <d-pagination + :total="pager.total" + v-model:pageSize="pager.pageSize" + totalItemText="Total" + v-model:pageIndex="pager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :lite="true" + /> + + <h5 style="padding: 20px 0 10px;">Super Simple Mode</h5> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + :showPageSelector="false" + v-model:pageIndex="pager.pageIndex" + :canChangePageSize="true" + :lite="true" + /> + + <h5 style="padding: 20px 0 10px;">haveConfigMenu = "true"</h5> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + :showPageSelector="false" + v-model:pageIndex="pager.pageIndex" + :canChangePageSize="true" + :lite="true" + :haveConfigMenu="true" + > + <div class="pagination-config-item"> + <div class="config-item-title">show field</div> + <div class="config-item-words">setting</div> + </div> + <div class="pagination-config-item"> + <div class="config-item-title">display method</div> + <div style="padding-left: 8px; margin-top: 4px"> + <i class="icon-list-view"></i> + <i class="icon-veIcon-briefcase"></i> + </div> + </div> + </d-pagination> +</template> +<script> +import { defineComponent, shallowReactive } from 'vue' + +export default defineComponent({ + setup() { + const pager = shallowReactive({ + total: 306, + pageIndex: 5, + pageSize: 10, + pageSizeOptions: [10, 20, 30, 40, 50] + }) + + return { + pager + } + } +}) +</script> + +<style> +/* 配置中的每一项,自定义项建议应用此样式或在此基础上修改 */ +.pagination-config-item { + padding-bottom: 8px; + padding-top: 4px; + border-bottom: 1px solid $devui-line; +} + +/* 配置中每一项的标题样式,自定义项建议应用此样式或在此基础上修改 */ +.config-item-title { + color: $devui-line; + padding-left: 8px; + font-size: $devui-font-size; + line-height: 1.5; +} + +.config-item-words { + color: $devui-text; + padding-left: 8px; + font-size: $devui-font-size; + margin-top: 4px; +} + +.config-item-words:hover { + background-color: $devui-area; + cursor: pointer; +} +</style> +``` +::: + +### 多种配置 +支持设置输入跳转、显示跳转按钮;设置pageSize等功能。 +:::demo + +```vue +<template> + <div style="padding: 20px 0 10px;"></div> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :maxItems="10" + :canViewTotal="true" + :canJumpPage="true" + :canChangePageSize="true" + @pageIndexChange="pageIndexChange" + @pageSizeChange="pageSizeChange" + /> + + <div style="padding: 20px 0 10px;"></div> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :maxItems="10" + :canViewTotal="true" + :canJumpPage="true" + :showJumpButton="true" + @pageIndexChange="pageIndexChange" + @pageSizeChange="pageSizeChange" + /> + + <div style="padding: 20px 0 10px;"></div> + <d-pagination + size="sm" + :total="pager.total" + v-model:pageSize="pager.pageSize" + v-model:pageIndex="pager.pageIndex" + :maxItems="10" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :autoFixPageIndex="false" + :autoHide="false" + @pageIndexChange="pageIndexChangeWithoutFix" + @pageSizeChange="pageSizeChangeWithoutFix" + :pageSizeOptions="pager.pageSizeOptions" + :pageSizeDirection="['centerUp']" + /> +</template> +<script> +import { defineComponent, shallowReactive } from 'vue' + +export default defineComponent({ + setup() { + const pager = shallowReactive({ + total: 306, + pageIndex: 5, + pageSize: 10, + pageSizeOptions: [10, 20, 30, 40, 50] + }) + + const pageSizeChange = (val) => { + pager.pageIndex = 1; + console.log(val, 'pageSizeChange') + } + const pageIndexChange = (val) => { + console.log(val, 'pageIndexChange') + } + + const pageIndexChangeWithoutFix = (pageIndex) => { + console.log(pageIndex, 'pageIndexChangeWithoutFix'); + } + const pageSizeChangeWithoutFix = (pageSize) => { + pager.pageIndex = 1; + console.log(pageSize, 'pageSizeChangeWithoutFix'); + } + + return { + pager, + pageSizeChange, + pageIndexChange, + pageIndexChangeWithoutFix, + pageSizeChangeWithoutFix + } + } +}) +</script> +``` +::: + +### 特殊情况 +特殊场景下分页器的显示。 +:::demo + + +```vue +<template> + <h5 style="padding: 20px 0 10px;"> + When the value of <code>pageIndex</code> exceeds the maximum page number, enable <code>showTruePageIndex</code> to display the value of <code>pageIndex</code> + </h5> + <d-pagination + size="sm" + :total="pager1.total" + v-model:pageSize="pager1.pageSize" + v-model:pageIndex="pager1.pageIndex" + :maxItems="5" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :showTruePageIndex="true" + /> + + <h5 style="padding: 20px 0 10px;"> + When the value of <code>pageIndex</code> exceeds the maximum page number, the <code>showTruePageIndex</code> function is disabled and only the maximum page number is displayed. + </h5> + <d-pagination + size="sm" + :total="pager2.total" + v-model:pageSize="pager2.pageSize" + v-model:pageIndex="pager2.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + :showTruePageIndex="false" + /> + + <h5 style="padding: 20px 0 10px;">Default Mode</h5> + <d-pagination + size="sm" + :total="defaultPager.total" + v-model:pageSize="defaultPager.pageSize" + v-model:pageIndex="defaultPager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :canJumpPage="true" + :maxItems="5" + /> + <div style="display: flex; margin-top: 10px;"> + <d-button bsStyle="primary" circled="true" size="sm" @click="setTotal(0)" :width="200">total = 0</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setTotal(5)" :width="200">total = 5</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setTotal(15)" :width="200">total = 15</d-button> + </div> + + <h5 style="padding: 20px 0 10px;">Simple Mode</h5> + <d-pagination + :total="litePager.total" + v-model:pageSize="litePager.pageSize" + totalItemText="total" + v-model:pageIndex="litePager.pageIndex" + :canViewTotal="true" + :canChangePageSize="true" + :lite="true" + /> + <div style="display: flex; margin-top: 10px;"> + <d-button bsStyle="primary" circled="true" size="sm" @click="setLiteTotal(0)" :width="200">total = 0</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setLiteTotal(20)" :width="200">total = 20</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setLiteTotal(30000)" :width="200">total = 30000</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setLiteTotal(100000)" :width="200">total = 100000</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setIndex(2)" :width="200">index = 2</d-button> + <d-button bsStyle="common" circled="true" size="sm" @click="setIndex(3)" :width="200">index = 3</d-button> + </div> +</template> +<script> +import { defineComponent, shallowReactive } from 'vue' + +export default defineComponent({ + setup() { + + const pager1 = shallowReactive({ + total: 10, + pageIndex: 3, + pageSize: 10 + }) + const pager2 = shallowReactive({ + total: 10, + pageIndex: 3, + pageSize: 10 + }) + + const defaultPager = shallowReactive({ + total: 0, + pageIndex: 1, + pageSize: 10 + }) + const setTotal = (val) => { + defaultPager.total = val + } + + const litePager = shallowReactive({ + total: 0, + pageIndex: 1, + pageSize: 10 + }) + + const setLiteTotal = (val) => { + litePager.total = val + } + const setIndex = (val) => { + litePager.pageIndex = val + } + + return { + pager1, + pager2, + defaultPager, + setTotal, + litePager, + setLiteTotal, + setIndex + } + } +}) +</script> +``` +::: + +### 参数 + +d-pagination 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| ----------------- | ------------------------------------------------------------ | -------------------------- | ------------------------------------------------------------ | --------------------- | +| pageSize | `number` | 10 | 可选,每页显示最大条目数量 | [基本用法](#基本用法) | +| total | `number` | 0 | 可选,显示的总条目数 | [基本用法](#基本用法) | +| pageSizeOptions | `number[] ` | 10 | 可选,分页每页最大条目数量的下拉框的数据源,默认有四种选择 5, 10, 20, 50 | [多种配置](#多种配置) | +| pageSizeDirection | `Array<`[`AppendToBodyDirection`](#appendtobodydirection) `\|` [`ConnectedPosition`](#connectedposition)`>` | ['centerDown', 'centerUp'] | 可选,设置分页每页条目的下拉框展示的方向 | [多种配置](#多种配置) | +| pageIndex | `number` | 1 | 可选,初始化页码 | [基本用法](#基本用法) | +| maxItems | `number` | 10 | 可选,分页最多显示几个按钮 | [基本用法](#基本用法) | +| preLink | `string` | -- | 可选,上一页按钮显示图标,默认设置为左箭头图标 | [基本用法](#基本用法) | +| nextLink | `string` | -- | 可选, 下一页按钮显示图标,默认设置为右箭头图标 | [基本用法](#基本用法) | +| size | `number` | '' | 可选,分页组件尺寸,有三种选择 lg,``,sm,分别代表大,中,小 | [基本用法](#基本用法) | +| canJumpPage | `boolean` | false | 可选,是否显示分页输入跳转 | [基本用法](#基本用法) | +| canChangePageSize | `boolean` | false | 可选,是否显示用于选择更改分页每页最大条目数量的下拉框 | [基本用法](#基本用法) | +| canViewTotal | `boolean` | false | 可选,是否显示总条目 | [基本用法](#基本用法) | +| totalItemText | `string` | '所有条目' | 可选,总条目文本 | [极简模式](#极简模式) | +| goToText | `string` | '跳至' | 可选,总条目文本 | [基本用法](#基本用法) | +| showJumpButton | `boolean` | false | 可选,是否显示跳转按钮 | [多种配置](#多种配置) | +| showTruePageIndex | `boolean` | false | 可选,页码超出分页范围时候也显示当前页码的开关 | [多种配置](#多种配置) | +| lite | `boolean` | false | 可选,是否切换为极简模式 | [极简模式](#极简模式) | +| showPageSelector | `boolean` | true | 可选,`极简模式`下是否显示页码下拉 | [极简模式](#极简模式) | +| haveConfigMenu | `boolean` | false | 可选,`极简模式`下是否显示配置 | [极简模式](#极简模式) | +| autoFixPageIndex | `boolean` | true | 可选,改变 pageSize 时是否自动修正页码,若`pageSizeChange`事件中会对`pageIndex`做处理,建议设置为`false` | [极简模式](#极简模式) | +| autoHide | `boolean` | false | 可选,是否自动隐藏, autoHide为 true 并且 pageSizeOptions最小值 > total 不展示分页 | [极简模式](#极简模式) | + +d-pagination 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| --------------- | -------------------- | ---------------------------------------------------------- | --------------------- | +| pageIndexChange | `EventEmitter<number>` | 可选,页码变化的回调,返回当前页码值 | [多种配置](#多种配置) | +| pageSizeChange | `EventEmitter<number>` | 可选,每页最大条目数量变更时的回调,返回当前每页显示条目数 | [多种配置](#多种配置) | + +**接口 & 类型定义** + +##### AppendToBodyDirection + +```ts +export type AppendToBodyDirection = 'rightDown' | 'rightUp' | 'leftUp' | 'leftDown' | 'centerDown' | 'centerUp'; +``` + +##### ConnectedPosition + +```ts +export interface ConnectedPosition { + originX: 'start' | 'center' | 'end'; + originY: 'top' | 'center' | 'bottom'; + + overlayX: 'start' | 'center' | 'end'; + overlayY: 'top' | 'center' | 'bottom'; + + weight?: number; + offsetX?: number; + offsetY?: number; + panelClass?: string | string[]; +} +``` + diff --git a/packages/devui-vue/docs/components/panel/index.md b/packages/devui-vue/docs/components/panel/index.md new file mode 100644 index 0000000000000000000000000000000000000000..0c1b61985915e59c490180ac4c7164d1135ca178 --- /dev/null +++ b/packages/devui-vue/docs/components/panel/index.md @@ -0,0 +1,181 @@ +# Panel 面板 + +内容面板,用于内容分组。 + +### 何时使用 + +当页面内容需要进行分组显示时使用,一般包含头部、内容区域、底部三个部分。 + +### 基本用法 +:::demo + +```vue +<template> + <d-panel type="primary" :isCollapsed="true" :showAnimation="true" > + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> + <br /><br /> + <d-panel :toggle=toggle :isCollapsed="true" :showAnimation="true" :hasLeftPadding="false"> + <d-panel-header> + Panel has no left padding + <em :class="`icon icon-chevron-${toggleState ? 'down':'up'}`"></em> + </d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> + <br /><br /> + <d-panel :isCollapsed="true" :beforeToggle=beforeToggle> + <d-panel-header>Panel with header and footer</d-panel-header> + <d-panel-body>This is body</d-panel-body> + <d-panel-footer>This is footer</d-panel-footer> + </d-panel> +</template> +<script> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup(){ + const toggleState = ref(true); + const toggle = (e) => toggleState.value = e; + const beforeToggle = () => false; + return { + toggle, + toggleState, + beforeToggle + } + } +}) +</script> +``` +::: + +### 多种类型 + +面板类型分为default、primary、success,danger、warning、info。 + +:::demo +```vue +<template> +<d-panel type="primary" :isCollapsed="true" :showAnimation="true"> + <d-panel-header>Panel with Primary Type</d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> + <br /><br /> + <d-panel type="success" :isCollapsed="true" :showAnimation="true"> + <d-panel-header>Panel with Success Type</d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> + <br /><br /> + <d-panel type="warning" :isCollapsed="true" :showAnimation="true"> + <d-panel-header>Panel with Warning Type</d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> + <br /><br /> + <d-panel type="danger" :isCollapsed="true" :showAnimation="true"> + <d-panel-header>Panel with danger Type</d-panel-header> + <d-panel-body>This is body</d-panel-body> + </d-panel> +</template> +``` +::: + +### 阻止折叠 + +某种情况下,我们需要阻止面板收起。Panel提供了这项API,我们可以使用beforeToggle来阻止面板的收起 + +根据条件判断,当panel展开时,点击阻止折叠按钮,将无法折叠panel。当panel折叠时不影响操作。 + +:::demo +```vue +<template> + <d-panel type="primary" :hasLeftPadding=padding :toggle=handleToggle :beforeToggle=beforeToggle :showAnimation=showAnimation > + <d-panel-header> + Panel with foldable <i :class="`icon-arrow-${toggle ? 'down' : 'up'}`"></i> + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + <br /><br /> + <d-button @click="panelToggle = !panelToggle" > + {{ panelToggle ? '阻止折叠' : '允许折叠' }} + </d-button> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup(){ + let isCollapsed = ref(true); + let panelToggle = ref(true); + let toggle = ref(true); + let showAnimation = ref(true); + let state; + let padding = ref(false); + const handleToggle = (e) => {toggle.value = e;} + const beforeToggle = (e) => {console.log(e); return panelToggle.value;} + return { + state, + toggle, + panelToggle, + beforeToggle, + isCollapsed, + handleToggle, + showAnimation, + padding + } + } +}) +</script> +``` +::: + +### 动态切换 + +我们已hasLeftPadding为例 + +:::demo +```vue +<template> + <d-panel :type="type" :hasLeftPadding=padding :isCollapsed> + <d-panel-header> + Panel with foldable + </d-panel-header> + <d-panel-body> + This is body + </d-panel-body> + </d-panel> + <br /><br /> + <d-button @click="padding = !padding" > + {{ padding ? '有左填充' : '没有左填充' }} + </d-button> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup(){ + let padding = ref(false); + return { + padding, + } + } +}) +</script> +``` +::: + + + +### API + +|参数| 类型| 默认| 说明| +|:-:|:-:|:-:|:-:| +|type| PanelType| 'default'| 可选,面板的类型| +|cssClass| string| -- | 可选,自定义 class 名| +|isCollapsed| boolean| false | 可选,是否展开| +|hasLeftPadding| boolean| true | 可选,是否显示左侧填充| +|showAnimation| boolean| true | 可选,是否展示动画| +|beforeToggle| Function\|Promise\|Observable| -- | 可选,面板折叠状态改变前的回调函数,返回 boolean 类型,返回 false 可以阻止面板改变折叠状态 根据条件阻止折叠| +|toggle| Function| -- | 可选,面板当前状态的回调函数,返回boolean类型,返回 false 代表面板被收起,返回 true 代表面板展开 \ No newline at end of file diff --git a/packages/devui-vue/docs/components/popover/index.md b/packages/devui-vue/docs/components/popover/index.md new file mode 100644 index 0000000000000000000000000000000000000000..9270b4985f4dfbbbe59fba383df9820dc8b1bb50 --- /dev/null +++ b/packages/devui-vue/docs/components/popover/index.md @@ -0,0 +1,272 @@ +# Popover 悬浮提示 +简单的文字提示气泡框。 + +### 何时使用 +用来通知用户非关键性问题或提示某控件处于某特殊情况。 + +### 基本用法 +当Popover弹出时,会基于`reference`插槽的内容进行定位。 +:::demo +```vue +<template> +<div class="item" > + <d-popover visible> + <template #reference> + <d-button bsStyle="common">default</d-button> + </template> + </d-popover> + <d-popover content="info!" popType="info" position="top" trigger="hover"> + <template #reference> + <d-button bsStyle="primary">info</d-button> + </template> + </d-popover> + <d-popover content="error!" popType="error" position="left" :zIndex="9999"> + <template #reference> + <d-button bsStyle="danger">error</d-button> + </template> + </d-popover> + <d-popover content="success!" popType="success" position="right"> + <template #reference> + <d-button bsStyle="success">success</d-button> + </template> + </d-popover> + <d-popover content="warning!" popType="warning" > + <template #reference> + <d-button bsStyle="warning">warning</d-button> + </template> + </d-popover> + <d-popover content="no-animation!" :showAnimation="false" :popMaxWidth="100"> + <template #reference> + <d-button bsStyle="common">no-animation</d-button> + </template> + </d-popover> +</div> +</template> +<style> +.item > *{ + margin-right:10px; +} +</style> +``` +::: + +### 自定义内容 +自定义`reference`插槽的内容与弹出提示内容。 + +:::demo + +```vue +<template> +<div class="item"> + <d-popover content="自定义内容" > + <template #reference> + <d-button bsStyle="primary"> click me!</d-button> + </template> + </d-popover> + <d-popover content="自定义内容" trigger="hover" :popoverStyle="{ backgroundColor: '#7693f5',color: '#fff'}"> + <template #reference> + <d-button bsStyle="primary"> hover me!</d-button> + </template> + </d-popover> +</div> +</template> + +<style> +.item > *{ + margin-right:10px; +} +</style> +``` +::: + + +### 弹出位置 +总共支持12个弹出位置。 + +:::demo + +```vue +<template> +<div class="item"> + <d-popover position="left" > + <template #content> + <div>left</div> + </template> + <template #reference> + <d-button bsStyle="common">left</d-button> + </template> + </d-popover> + <d-popover position="left-top" > + <template #content> + <div >left-top</div> + <div>left-top</div> + </template> + <template #reference> + <d-button bsStyle="common">left-top</d-button> + </template> + </d-popover> + <d-popover position="left-bottom" > + <template #content> + <div>left-bottom</div> + <div>left-bottom</div> + </template> + <template #reference> + <d-button bsStyle="common">left-bottom</d-button> + </template> + </d-popover> +</div> + +<div style="margin-top:10px;" class="item"> + <d-popover position="top" > + <template #content> + <span >top</span> + </template> + <template #reference> + <d-button bsStyle="common">top</d-button> + </template> + </d-popover> + <d-popover position="top-left" > + <template #content> + <span >top-left</span> + </template> + <template #reference> + <d-button bsStyle="common">top-left</d-button> + </template> + </d-popover> + <d-popover position="top-right" > + <template #content> + <span >top-right</span> + </template> + <template #reference> + <d-button bsStyle="common">top-right</d-button> + </template> + </d-popover> +</div> + +<div style="margin-top:10px;" class="item"> + <d-popover position="right" > + <template #content> + <div >right</div> + </template> + <template #reference> + <d-button bsStyle="common">right</d-button> + </template> + </d-popover> + <d-popover position="right-top" > + <template #content> + <div >right-top</div> + <div >right-top</div> + </template> + <template #reference> + <d-button bsStyle="common">right-top</d-button> + </template> + </d-popover> + <d-popover position="right-bottom" > + <template #content> + <div >right-bottom</div> + <div >right-bottom</div> + </template> + <template #reference> + <d-button bsStyle="common">right-bottom</d-button> + </template> + </d-popover> +</div> + +<div style="margin-top:10px;" class="item"> + <d-popover position="bottom" > + <template #content> + <div >bottom</div> + </template> + <template #reference> + <d-button bsStyle="common">bottom</d-button> + </template> + </d-popover> + <d-popover position="bottom-left" > + <template #content> + <div >bottom-left</div> + </template> + <template #reference> + <d-button bsStyle="common">bottom-left</d-button> + </template> + </d-popover> + <d-popover position="bottom-right" > + <template #content> + <div >bottom-right</div> + </template> + <template #reference> + <d-button bsStyle="common">bottom-right</d-button> + </template> + </d-popover> +</div> +</template> +<style> +.item > *{ + margin-right:10px; +} +</style> +``` + +::: + +### 延时触发 +仅需要在 trigger 为 hover 的时候,鼠标移入的时长超过 [mouseEnterDelay] 毫秒之后才会触发,以防止用户无意划过导致的闪现,默认值是150毫秒;鼠标移出之后,再经过[mouseLeaveDelay]毫秒后,Popover组件才会隐藏,默认值是100毫秒。 + +:::demo + +```vue +<template> +<div class="item"> + <d-popover position="bottom-right" trigger="hover" :mouseEnterDelay ="500"> + <template #content> + <div > Mouse enter 500ms later. </div> + show Me + </template> + <template #reference> + <d-button bsStyle="primary">MouseEnter delay 500ms</d-button> + </template> + </d-popover> + <d-popover position="bottom-right" trigger="hover" :mouseLeaveDelay="2000"> + <template #content> + <div> Mouse leave 2000ms later. </div> + </template> + <template #reference> + <d-button bsStyle="common"> MouseLeave delay 2000ms</d-button> + </template> + </d-popover> + </div> +</template> +<style> +.item > * { + margin-right:10px; +} +</style> +``` +::: + +### DPopover API详情 + +#### Props + +| 参数 | 类型 | 默认值 | 描述 | 跳转Demo | +| ---- | ---- | ---- | ---- | ---- | +| content | `string` | defalut |可选,弹出框的显示内容或 | [自定义内容](#自定义内容) | +| visible | `boolean` | false | 可选,弹框的初始化弹出状态 | [基本用法](#基本用法) | +| trigger | `string` | click | 可选,弹框触发方式 | [基本用法](#基本用法) | +| popType | `string` | default | 可选,弹出框类型,样式不同 | [基本用法](#基本用法) | +| zIndex | `number` | 1060 | 可选,z-index值用于手动控制层高 | [基本用法](#基本用法) | +| positionType | `string` | bottom | 可选,控制弹框出现 的方向 | [弹出位置](#弹出位置) | +| showAnimation | `boolean` | true | 可选,是否显示动画 | [基本用法](#基本用法) | +| popMaxWidth | `number` | - | 可选,限制弹出框最大宽度(`px`) | [基本用法](#基本用法) | +| mouseEnterDelay | `number` | 150 | 可选,仅需要在 trigger 为 hover 的时候,设置鼠标移入后延时多少才显示 Popover,单位是 `ms` | [延时触发](#延时触发) | +| mouseLeaveDelay | `number` | 100 | 可选,仅需要在 trigger 为 hover 的时候,设置鼠标移出后延时多少才隐藏 popover,单位是 `ms` | [延时触发](#延时触发) | +| popoverStyle | `{[klass:string]:any;}` | - | 可选,在需要改变弹出层样式时设置,箭头会应用同样的背景色。样式,参见[Angular版本—Popover](https://devui.design/components/zh-cn/popover/api) | [自定义内容](#自定义内容) | + + + +#### Slot + +| 名称 | 说明 | +| --------- | --------------------------- | +| content | 自定义菜单内容 | +| reference | 触发 Popover 显示的元素内容 | + diff --git a/packages/devui-vue/docs/components/progress/index.md b/packages/devui-vue/docs/components/progress/index.md new file mode 100644 index 0000000000000000000000000000000000000000..8358ba6ad957ec7b3ff4e53828637585ea406a97 --- /dev/null +++ b/packages/devui-vue/docs/components/progress/index.md @@ -0,0 +1,101 @@ +# Progress 进度条 + +进度条。 + +### 何时使用 +1. 当操作需要较长的时间时,向用户展示操作进度。 +2. 当操作需要打断现有界面或后台运行,需要较长时间时。 +3. 当需要显示一个操作完成的百分比或已完成的步骤/总步骤时。 + +### 基本用法 + + +::: demo 基本的进度和文字配置。 +```vue +<template> +<section class="devui-code-box-demo"> + <div class="progress-container"> + <d-progress :percentage="80" percentageText="80%"></d-progress> + </div> + <div class="progress-container"> + <d-progress :percentage="30" percentageText="30%" barbgcolor="#50D4AB" height="30px"></d-progress> + </div> +</section> +</template> +<style> +.progress-container { + margin-bottom: 20px; +} +.devui-code-box-demo{ + border-bottom: 1px dashed #dfe1e6; + padding: 16px 0; + .progress-container { + margin-bottom: 20px; + } +} +</style> +``` +::: + +### 圆环用法 +::: demo +```vue +<template> + <section class="devui-code-box-demo"> + <div class="progress-container-circle"> + <d-progress :isCircle="true" :percentage="80" :showContent="false"> </d-progress> + </div> + <div class="progress-container-circle"> + <d-progress :isCircle="true" :percentage="80" barbgcolor="#50D4AB" :strokeWidth="8"> + </d-progress> + </div> + <div class="progress-container-circle"> + <d-progress :isCircle="true" :percentage="80" barbgcolor="#50D4AB"> + <span class="icon-position"> + <d-icon + name="right" + color="#3dcca6" + /> + </span> + </d-progress> + </div> + </section> +</template> +<style> +.progress-container-circle { + height: 130px; + width: 130px; + font-size: 20px; + display: inline-block; + margin-right: 10px; +} +.icon-position { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + margin: 0; + padding: 0; + line-height: 1; + white-space: normal; + text-align: center; + transform: translate(-50%, -50%); + color: #50d4ab; + font-size: 24px; +} + +</style> +``` +::: + +### API +#### d-progress 参数 +| 参数 | 类型 | 默认值 | 描述 | 跳转Demo | +| :---: | :---: | :---: | :---: | :---: | +| percentage | `number` | 0 | 可选,进度条的值最大为 100 | [基本用法](#基本用法) | +| percentageText | `string` | -- | 可选,进度条当前值的文字说明比如:'30%' \| '4/5' | [基本用法](#基本用法) | +| barBgColor | `string` | #5170ff | 可选,进度条的颜色显示,默认为天蓝色 | [基本用法](#基本用法) | +| height | `string` | 20px | 可选,进度条的高度值,默认值为 20px | [基本用法](#基本用法) | +| isCircle | `boolean` | false | 可选, 显示进度条是否为圈形 | [圆环用法](#圆环用法) | +| strokeWidth | `number` | 6 | 可选,设置圈形进度条宽度,单位是进度条与画布宽度的百分比 | [圆环用法](#圆环用法) | +| showContent | `boolean` | true | 可选,设置圈形进度条内是否展示内容 | [圆环用法](#圆环用法) | diff --git a/packages/devui-vue/docs/components/quadrant-diagram/index.md b/packages/devui-vue/docs/components/quadrant-diagram/index.md new file mode 100644 index 0000000000000000000000000000000000000000..225c4ab8f8a49065d007695586170278dd875c06 --- /dev/null +++ b/packages/devui-vue/docs/components/quadrant-diagram/index.md @@ -0,0 +1,38 @@ +# QuadrantDiagram 象限图 + +象限图。 + +### 何时使用 + +根据需求对事务进行区域划分与价值排序,可用于管理事务的优先级。 + +### 基本用法 + +<h4>Basic Usage</h4> + +:::demo + +```vue +<template> + <d-quadrant-diagram :view='view'/> +</template> + + +<script> +import { defineComponent, reactive } from 'vue' + +export default ({ + setup() { + const view = reactive({ + height: 500, + width: 500, + }); + return { + view, + } + } +}) +</script> +``` + +::: diff --git a/packages/devui-vue/docs/components/radio/index.md b/packages/devui-vue/docs/components/radio/index.md new file mode 100644 index 0000000000000000000000000000000000000000..3ab37dd63af4dea4e59591bbe746b6a5507d2f70 --- /dev/null +++ b/packages/devui-vue/docs/components/radio/index.md @@ -0,0 +1,307 @@ +# Radio 单选框 + +单选框。 + +### 何时使用 + +用户要从一个数据集中选择单个选项,且能并排查看所有可选项,选项数量在 2~7 之间时,建议使用单选按钮。 + +### 相互独立的单选项 + +:::demo + +```vue +<template> + <d-radio + v-for="item in list" + v-model="choose" + :key="item" + :value="item" + :style="{ marginBottom: '20px' }" + > + The Radio value is: {{ item }} + </d-radio> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + return { + list, + choose, + } + }, +}) +</script> +``` + +::: + +### radio 根据条件终止切换操作 + +:::demo 根据条件判断,第二项禁止跳转。 + +```vue +<template> + <d-radio + v-for="item in list" + v-model="choose" + :key="item" + :value="item" + :beforeChange="beforeChange" + :style="{ marginBottom: '20px' }" + @change="valChange" + > + The Radio value is: {{ item }} + </d-radio> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + return { + list, + choose, + beforeChange(value) { + return value !== 'Item2' + }, + valChange(val) { + console.log('current value', val) + }, + } + }, +}) +</script> +``` + +::: + +### radio-group 根据条件终止切换操作 + +:::demo + +```vue +<template> + <d-radio-group css-style="row" v-model="choose" :beforeChange="beforeChange"> + <d-radio v-for="item in list" :key="item" :value="item"> + {{ item }} + </d-radio> + </d-radio-group> + <d-radio-group v-model="choose2" css-style="row" disabled> + <d-radio v-for="item in list2" :key="item" :value="item"> + {{ item }} + </d-radio> + </d-radio-group> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + const list2 = ['Spring', 'Summer', 'Autumn', 'Winter'] + const choose2 = ref('Summer') + + return { + list, + choose, + list2, + choose2, + beforeChange(value) { + return value !== 'Item2' + }, + } + }, +}) +</script> +``` + +::: + +### 禁用 + +:::demo + +```vue +<template> + <d-radio + v-for="item in list" + v-model="choose" + :key="item" + :value="item" + :style="{ marginBottom: '20px' }" + disabled + > + The Radio value is: {{ item }} + </d-radio> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + return { + list, + choose, + } + }, +}) +</script> +``` + +::: + +### 横向排列 + +:::demo + +```vue +<template> + <d-radio-group css-style="row" v-model="choose"> + <d-radio v-for="item in list" :key="item" :value="item"> + The Radio value is: {{ item }} + </d-radio> + </d-radio-group> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + return { + list, + choose, + } + }, +}) +</script> +``` + +::: + +### 竖向排列 + +:::demo + +```vue +<template> + <d-radio-group :values="list" v-model="choose"></d-radio-group> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ['Spring', 'Summer', 'Autumn', 'Winter'] + const choose = ref('Summer') + + return { + list, + choose, + valChange(val) { + console.log('current value', val) + }, + } + }, +}) +</script> +``` + +::: + +### 自定义单选项 + +:::demo 数组源可为普通数组、对象数组等。 + +```vue +<template> + <d-radio-group css-style="row" v-model="choose"> + <d-radio v-for="item in list" :key="item" :value="item"> + The Radio value is: {{ item }} + </d-radio> + </d-radio-group> + <d-radio-group css-style="row" v-model="choose2"> + <d-radio v-for="item in list2" :key="item.name" :value="item.name"> + The Radio value is: {{ item.name }} + </d-radio> + </d-radio-group> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['Item1', 'Item2', 'Item3']) + let choose = ref('Item1') + + const list2 = [{ name: 'Item1' }, { name: 'Item2' }, { name: 'Item3' }] + let choose2 = ref('Item3') + + return { + list, + choose, + list2, + choose2, + } + }, +}) +</script> +``` + +::: + +### API + +d-radio 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :----------: | :------------------: | :---: | :------------------------------------------------------------------------------ | --------------------------------------- | +| name | `string` | -- | 可选,单选项名称 | [互相独立的单选项](#相互独立的单选项) | +| value | `string` | -- | 必选,单选项值 | [互相独立的单选项](#相互独立的单选项) | +| disabled | `boolean` | false | 可选,是否禁用该单选项 | [禁用](#禁用) | +| beforeChange | `Function / Promise` | -- | 可选,radio 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 radio 切换 | [回调切换](#radio-根据条件终止切换操作) | + +d-radio 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| :----: | :--------------------: | :------------------------------- | ------------------------------------- | +| change | `EventEmitter<string>` | 单选项值改变时触发,返回选中的值 | [互相独立的单选项](#相互独立的单选项) | + +d-radio-group 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :----------: | :------------------: | :------: | :-------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| name | `string` | -- | 可选,单选框的名称 | [竖向排列](#竖向排列) | +| values | `array` | -- | 可选,单选数据组 | [竖向排列](#竖向排列) | +| disabled | `boolean` | false | 可选,是否禁用该选项组 | [radio-group 根据条件终止切换操作](#radio-group-根据条件终止切换操作) | +| cssStyle | `'row' / 'column'` | 'column' | 可选,设置横向或纵向排列 | [横向排列](#横向排列) | +| beforeChange | `Function / Promise` | -- | 可选,radio-group 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 radio-group 的切换 | [回调切换](#radio-group-根据条件终止切换操作) | + +d-radio-group 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| :----: | :--------------------: | :------------------------------- | --------------------- | +| change | `EventEmitter<string>` | 单选项值改变时触发,返回选中的值 | [竖向排列](#竖向排列) | diff --git a/packages/devui-vue/docs/components/rate/index.md b/packages/devui-vue/docs/components/rate/index.md new file mode 100644 index 0000000000000000000000000000000000000000..be6e90f1f7368375190f3949c2d67affc8c2d587 --- /dev/null +++ b/packages/devui-vue/docs/components/rate/index.md @@ -0,0 +1,173 @@ +# Rate 等级评估 + +等级评估。 + +### 何时使用 + +用户对一个产品进行评分时可以使用。 + +### Demo + +### 只读模式 + +:::demo + +```vue +<template> + <d-rate :read="true" v-model="value1" /> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const value1 = ref(3.5) + return { + value1, + } + }, +} +</script> +``` + +::: + +### 动态模式 + +:::demo + +```vue +<template> + <d-rate v-model="value" icon="star-o" /> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const value = ref(2) + return { + value, + } + }, +} +</script> +``` + +::: + +### 动态模式-自定义 + +:::demo + +```vue +<template> + <d-rate character="A" color="#ffa500" v-model="value" :count="6" /> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const value = ref(3) + return { + value, + } + }, +} +</script> +``` + +::: + +### 半选模式 + +:::demo + +```vue +<template> + <d-rate v-model="value" :allowHalf="true" @change="change" /> + {{ value }} +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const value = ref(2) + const change = (val) => { + console.log(val) + } + return { + value, + change, + } + }, +} +</script> +``` + +::: + +### 使用 type 参数 + +:::demo + +```vue +<template> + <div> + <d-rate + v-model="value1" + :read="true" + type="success" + :count="5" + icon="star" + /> + </div> + <div> + <d-rate + v-model="value2" + :read="true" + type="warning" + :count="5" + icon="star" + /> + </div> + <div> + <d-rate v-model="value3" :read="true" type="error" :count="5" /> + </div> +</template> +<script> +import { ref } from 'vue' +export default { + setup() { + const value1 = ref(3.5) + const value2 = ref(2) + const value3 = ref(3) + return { + value1, + value2, + value3, + } + }, +} +</script> +``` + +::: + +### API + +d-rate 参数 + +| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | +| :-------: | :-----------------------------: | :----: | :------------------------------------------------------- | ----------------------------------- | +| read | `boolean` | false | 可选,设置是否为只读模式,只读模式无法交互 | [只读模式](#只读模式) | +| count | `number` | 5 | 可选,设置总等级数 | [只读模式](#只读模式) | +| type | `'success'\|'warning'\|'error'` | -- | 可选,设置当前评分的类型,不同类型对应不同颜色 | [使用 type 参数](#使用-type-参数) | +| color | `string` | -- | 可选,星星颜色 | [动态模式-自定义](#动态模式-自定义) | +| icon | `string` | -- | 可选,评分图标的样式,只支持 devUI 图标库中所有图标 | [动态模式](#动态模式) | +| character | `string` | -- | 可选,评分图标的样式,icon 与 character 只能设置其中一个 | [动态模式-自定义](#动态模式-自定义) | +| allowHalf | `boolean` | false | 可选,动态模式下是否允许半选 | [半选模式](#半选模式) | + +d-rate 事件 + +| 参数 | 类型 | 说明 | 回调参数 | 跳转 Demo | +| ------ | ---------------------- | -------------- | ------------ | --------------------- | +| change | `EventEmitter<number>` | 分值改变时触发 | 改变后的分值 | [半选模式](#半选模式) | diff --git a/packages/devui-vue/docs/components/read-tip/index.md b/packages/devui-vue/docs/components/read-tip/index.md new file mode 100644 index 0000000000000000000000000000000000000000..d3c4c955d939359bd24083daa106f6cb5c54c3ce --- /dev/null +++ b/packages/devui-vue/docs/components/read-tip/index.md @@ -0,0 +1,194 @@ +# ReadTip 阅读提示 + +阅读提示组件。 + +### 何时使用 + +当html文档中需要对特定内容进行提示时使用。 + + +### 基本用法 +通过设置selector选择需要显示readtip的元素,传入title和content设置显示的内容。 +:::demo + +```vue +<template> + <d-read-tip :readTipOptions="readTipOptions" > + <h1>Let's see how to use ReadTip</h1> + <p class="readtip-content">Set selector to display readtip</p> + <p>The following is the target you want to show readtip</p> + <span class="readtip-target">@Jack</span> + <template #contentTemplate> + <p>我是devui 基础用法</p> + </template> + </d-read-tip > +</template> + +<script setup> +import { defineComponent } from 'vue' +const readTipOptions = { + trigger: 'click', + rules: { + trigger: 'click', + position:'top', + selector: '.readtip-target', + title: 'Name: Jack', + content: 'This is Jack\'s profile', + }, + }; + +</script> + +<style> +.readtip-container { + padding: 12px; +} + +.readtip-target { + display: inline-block; + font-weight: bold; + cursor: pointer; + margin-top: 16px; +} + +.readtip-target:hover { + text-decoration: underline; +} +</style> +``` + +::: + +### 包括多个提示的readtip +传入多个rule,设置不同元素的readtip显示模式。 +:::demo + +```vue +<template> + <d-read-tip :readTipOptions="readTipOptions" > + <h1>Multiple Readtips</h1> + <h2 class="introduction">You can pass in multiple rules to display different readtips</h2> + <p class="first-content">Click here to display first content</p> + <p class="second-content">Click here to display second content</p> + <h3 class="third-content">Hover here to display third content</h3> + <h3 class="third-content">Another third content with same class name</h3> + +</div> + </d-read-tip > +</template> + +<script setup> +import { defineComponent } from 'vue' +const readTipOptions = { + trigger: 'click', + showAnimate: false, + mouseenterTime: 100, + mouseleaveTime: 100, + position: 'top', + overlayClassName: 'read-tip-container', + rules: [ + { + selector: '.first-content', + position: 'top', + title: 'This Is the First Title', + content: 'Lorem ipsum dolor sit amet, consectetur ad.', + }, + { + selector: '.second-content', + position: 'left', + title: 'This Is the Second Title', + content: 'Class aptent taciti sociosqu ad litora torquent per conubia nostra', + overlayClassName: 'child-class', + }, + { + trigger: 'hover', + selector: '.third-content', + position: 'bottom', + title: 'This Is the Third Title', + content: 'Aenean libero urna, scelerisque tincidunt', + }, + ], + }; + +</script> + +<style> +.readtip-container { + padding: 12px; +} + +.readtip-target { + display: inline-block; + font-weight: bold; + cursor: pointer; + margin-top: 16px; +} + +.readtip-target:hover { + text-decoration: underline; +} + +.first-content { + font-weight: bold; + margin-bottom: 4px; + cursor: pointer; +} + +.second-content { + font-weight: bold; + cursor: pointer; +} + +.third-content { + cursor: pointer; +} +</style> +``` + +::: + +### d-read-tip + +d-read-tip 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| -------------------- | ------------------ | ---- | ------------------------------- | ---------------------- | ---------- | +| readTipOptions | ReadTipOptions | -- | 必选,配置提示选项 | 基本用法 | -- | +| readTipOptions.rules | ReadTipRules | -- | 必选,配置 readtip 内容 | 包括多个提示的 readtip | -- | +| contentTemplate | `TemplateRef<any>` | -- | 可选,传入模板显示 readtip 内容 | 传入模板显示内容 | -- | + + + +``` +export interface ReadTipOptions { + trigger?: 'hover' | 'click'; // 默认值是 hover + showAnimate?: boolean; // 默认值是 false + mouseenterTime?: number; // 默认值是 100 + mouseleaveTime?: number; // 默认值是 100 + position?: PositionType | PositionType[]; // 默认值是 'top' + overlayClassName?: string; // 默认值为空字符串 + appendToBody?: boolean; // 默认值为true + rules: ReadTipRules; +} +export type ReadTipRules = ReadTipRule | ReadTipRule[]; + +export interface ReadTipRule { + key?: string; + selector: string; + trigger?: 'hover' | 'click'; // 可以继承自 ReadTipOptions + title?: string; + content?: string; + showAnimate?: boolean; // 可以继承自 ReadTipOptions + mouseenterTime?: number; // 可以继承自 ReadTipOptions + mouseleaveTime?: number; // 可以继承自 ReadTipOptions + position?: PositionType | PositionType[]; // 可以继承自 ReadTipOptions + overlayClassName?: string; // 可以继承自 ReadTipOptions + appendToBody?: boolean; //可以继承自 ReadTipOtions + //customData与template搭配使用,customData为传入模板的上下文,可以自定义模板内容 + dataFn?: ({ + element, + rule: ReadTipRule, + }) => Observable<{ title?: string; content?: string; template?: TemplateRef<any>; customData?: any }>; +} +``` + diff --git a/packages/devui-vue/docs/components/ripple/index.md b/packages/devui-vue/docs/components/ripple/index.md new file mode 100644 index 0000000000000000000000000000000000000000..5e9e551b73fb2a9530b3b271dabe94c8958de738 --- /dev/null +++ b/packages/devui-vue/docs/components/ripple/index.md @@ -0,0 +1,180 @@ +# Ripple 水波纹指令 + +<span color="#409EFF">`v-ripple`</span> 指令 用于用户动作交互场景, 可以应用于任何块级元素 + +### 使用 + +:::demo 用户 可以在组件 或者 HTML 元素上任意使用 <span color="#409EFF">`v-ripple`</span> 指令 使用基本的 <span color="#409EFF">`v-ripple`</span> 指令, `v-ripple` 接收 一个对象 + +```vue +<template> + <div class="ripple-button"> + <div class="ripple-htmlElement" v-ripple="{ duration: 0.5 }"> + HTML元素 中使用 v-ripple + </div> + </div> +</template> +<style scoped> +.ripple-button { + display: flex; +} +</style> +``` + +::: + +### 自定义色彩 + +### 通过修改文本颜色来动态改变 + +:::demo + +```vue +<template> + <ul> + <li + v-for="item in [ + { color: '#409EFF', text: '这是一条 Primary 涟漪' }, + { color: '#67C23A', text: '这是一条 Success 涟漪' }, + { color: '#E6A23C', text: '这是一条 Warning 涟漪' }, + { color: '#F56C6C', text: '这是一条 Danger 涟漪' }, + { color: '#909399', text: '这是一条 Info 涟漪' }, + ]" + :style="{ color: item.color }" + > + <div class="ripple-changeTextColor" v-ripple="{ duration: 0.39 }"> + {{ item.text }} + </div> + </li> + </ul> +</template> +``` + +::: + +### 自定义颜色 + +:::demo + +```vue +<template> + <ul> + <li + v-for="(item, index) in [ + { color: '#409EFF', text: '这是一条 Primary 涟漪' }, + { color: '#67C23A', text: '这是一条 Success 涟漪' }, + { color: '#E6A23C', text: '这是一条 Warning 涟漪' }, + { color: '#F56C6C', text: '这是一条 Danger 涟漪' }, + { color: '#909399', text: '这是一条 Info 涟漪' }, + ]" + :style="{ color: item.color }" + > + <div + class="ripple-changeTextColor" + v-ripple="{ duration: 0.39, color: `${item.color.slice(0, 4)}` }" + > + {{ item.text }} + </div> + </li> + </ul> +</template> +``` + +::: + +### 应用于其他组件 + +Button + +:::demo + +```vue +<template> + <div class="ripple-button"> + <d-button + class="button" + bsStyle="common" + v-ripple="{ color: 'red', duration: 0.1, easing: 'linear' }" + >common</d-button + > + <d-button + class="button" + bsStyle="common" + v-ripple="{ color: 'blue', duration: 0.3, easing: 'ease-in' }" + >common</d-button + > + <d-button + class="button" + bsStyle="common" + v-ripple="{ color: '#fba', duration: 0.6, easing: 'ease-out' }" + >common</d-button + > + <d-button + class="button" + bsStyle="common" + v-ripple="{ color: '#abf', duration: 1, easing: 'ease-in-out' }" + >common</d-button + > + </div> +</template> +<style scoped> +.ripple-button { + display: flex; +} +</style> +``` + +::: + +Icon + +:::demo + +```vue +<template> + <div class="ripple-button"> + <d-icon class="ripple-icon" name="emoji" v-ripple></d-icon> + <d-icon class="ripple-icon" name="right" v-ripple color="#3dcca6"></d-icon> + <d-icon class="ripple-icon" name="error" v-ripple color="#f95f5b"></d-icon> + <d-icon + class="ripple-icon" + name="ban" + v-ripple + color="#f95f5b" + size="24px" + ></d-icon> + </div> +</template> + +``` + +::: + +<style> +.ripple-htmlElement { + width: 600px; + height: 150px; + background-color: #eee; + text-align: center; + line-height: 150px; + border: 1px solid #eee50; + box-shadow: 0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)!important; + user-select: none; +} +.ripple-changeTextColor { + display: block; + padding: 10px 15px; + user-select: none; +} +</style> + +### API + +| 参数 | 类型 | 默认 | 说明 | +| :-------------: | :------: | :------: | :-------------------------------- | +| color | `string` | #00050 | 可选,默认当前文本颜色 | +| initial-opacity | `number` | 0.1 | 可选,初始交互效果透明度大小 | +| final-opacity | `number` | 0.1 | 可选,结束交互效果长按透明度大小 | +| duration | `number` | 0.4s | 可选,持续时间 | +| easing | `string` | ease-out | 可选,缓动动画 | +| delay-time | `number` | 75ms | 可选,延迟 debouceTime 时间后调用 | diff --git a/packages/devui-vue/docs/components/search/index.md b/packages/devui-vue/docs/components/search/index.md new file mode 100644 index 0000000000000000000000000000000000000000..97d61245108d3272d3158b1ae026903170b0984a --- /dev/null +++ b/packages/devui-vue/docs/components/search/index.md @@ -0,0 +1,101 @@ +# Search 搜索框 + +搜索框。 + +### 何时使用 + +当用户需要在数据集中搜索所需数据时,输入所需数据的内容(或部分内容),返回所有匹配内容的搜索结果。 + +### 基本用法 + +:::demo 使用`sm`,`''`,`lg`来定义`Search`基本类型 + +```vue +<template> + <div> + Small + <d-search size="sm" autoFocus style="width: 200px" :delay="1000"></d-search> + Middle + <d-search style="width: 200px" isKeyupSearch></d-search> + Large + <d-search iconPosition="left" size="lg" style="width: 200px"></d-search> + Disabled + <d-search disabled style="width: 200px"></d-search> + </div> +</template> +``` +::: + +### 搜索图标左置 + +:::demo 使用`left`,`right`来定义`Search`搜索图标位置, 默认`right` + +```vue +<template> + <div> + <d-search iconPosition="left" style="width: 200px" placeholder="请输入"></d-search> + </div> +</template> +``` +::: + +### 无边框 + +:::demo 使用`noBorder`来定义`Search`无边框 + +```vue +<template> + <div> + <d-search iconPosition="left" noBorder style="width: 200px"></d-search> + </div> +</template> +``` +::: + +### 双向绑定 + +:::demo 使用`v-model`双向绑定 + +```vue + +<template> + <d-search cssClass="ipt" v-model="searchText" :maxLength="5" style="width: 200px"></d-search> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const searchText = ref('Devui') + return { + searchText + } + }, +}) +</script> +``` + +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | --------- | +| size | `'sm'\|''\|'lg'` | '' | 可选,搜索框尺寸,有三种选择 lg、''、sm | [基本用法](#基本用法) || +| placeholder | `string` | -- | 可选,输入框 placeholder | [搜索图标左置](#搜索图标左置) || +| maxLength | `number` | -- | 可选,输入框的 max-length | [双向绑定](#双向绑定) || +| delay | `number` | 300 | 可选,debounceTime 的延迟 | [基本用法](#基本用法) || +| disabled | `boolean` | false | 可选,输入框是否被禁用 | [基本用法](#基本用法) || +| autoFocus | `boolean` | false | 可选,输入框是否自动对焦 | [基本用法](#基本用法) || +| isKeyupSearch | `boolean` | false | 可选,是否支持输入值立即触发 searchFn | [基本用法](#基本用法) || +| iconPosition | `string` | 'right' | 可选,搜索图标位置,有两种选择'left' / 'right' | [搜索图标左置](#搜索图标左置) || +| noBorder | `boolean` | false | 可选,是否显示边框 | [无边框](#无边框) || +| cssClass | `string` | '' | 可选,支持传入类名到输入框上 | [双向绑定](#双向绑定) || + +### d-search 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| :---------: | :------: | :--------------------: | :---------: | +| searchFn | `string` | 回车或点击搜索按钮触发的回调函数,返回文本框输入的值 | [基本用法](#基本用法) | + diff --git a/packages/devui-vue/docs/components/select/index.md b/packages/devui-vue/docs/components/select/index.md new file mode 100644 index 0000000000000000000000000000000000000000..2cac4481bf263c147818d8c7b929c46c9078ead5 --- /dev/null +++ b/packages/devui-vue/docs/components/select/index.md @@ -0,0 +1,179 @@ +# Select 下拉选择框 + +下拉选择框。 + +### 何时使用 + +用户可以从多个选项中选择一项或几项;仅支持用户在下拉选项中选择和搜索系统提供的选项,不支持输入。 + +### 基本用法 + +:::demo 通过`size`:`sm`,`md(默认)`,`lg`来设置`Select`大小,通过`overview`:`underlined`设置只有下边框样式 + +```vue +<template> + <div> + Small + <d-select v-model="value1" :options="options" size="sm"></d-select> + + Middle + <d-select v-model="value2" :options="options"></d-select> + + Large + <d-select v-model="value3" :options="options" size="lg"></d-select> + + Underlined + <d-select v-model="value4" :options="options" size="lg" overview="underlined"></d-select> + </div> +</template> + +<script> +import { defineComponent, reactive, ref } from 'vue' + +export default defineComponent({ + setup () { + const value1 = ref('') + const value2 = ref('') + const value3 = ref('') + const value4 = ref('') + const items = new Array(6).fill(0).map((item, i) => `Option ${i+1}`) + const options = reactive(items) + + return { + value1, + value2, + value3, + value4, + options + } + }, +}) +</script> +``` +::: + +#### 多选 + +:::demo 通过`multiple`:`true`来开启多选 + +```vue +<template> + <d-select v-model="value" :options="options" :multiple="true" /> +</template> + +<script> +import { defineComponent, reactive, ref } from 'vue' + +export default defineComponent({ + setup () { + const value = ref([]) + const items = new Array(6).fill(0).map((item, i) => `Option ${i+1}`) + const options = reactive(items) + + return { + value, + options + } + }, +}) +</script> +``` +::: + +#### 禁用 + +:::demo 通过`disabled`:`true`来禁用`Select`,通过`option-disabled-key`来设置单个选项禁用,比如设置`disabled`字段,则对象上disabled为`true`时不可选择 + +```vue +<template> + <d-select v-model="value1" :options="options1" :disabled="true" /> + <br> + <d-select v-model="value2" :options="options2" option-disabled-key="disabled" /> + <br> + <d-select v-model="value3" :options="options3" :multiple="true" option-disabled-key="notAllow" /> +</template> + +<script> +import { defineComponent, reactive, ref } from 'vue' + +export default defineComponent({ + setup () { + const value1 = ref('') + const value2 = ref('') + const value3 = ref([]) + const items = new Array(6).fill(0).map((item, i) => `Option ${i+1}`) + const options1 = reactive(items) + const options2 = reactive([ + { + name: 'Option 1', + value: 0 + }, { + name: 'Option 2', + value: 1 + }, { + name: 'Option 3', + value: 2, + disabled: true + } + ]) + const options3 = reactive([ + { + name: 'Option 1', + value: 0 + }, { + name: 'Option 2', + value: 1, + notAllow: true + }, { + name: 'Option 3', + value: 2 + } + ]) + + return { + value1, + value2, + value3, + options1, + options2, + options3 + } + }, +}) +</script> + +``` +::: + +#### 可清空 + +:::demo 通过`allow-clear`:`true`来设置`Select`可清空 + +```vue +<template> + <d-select v-model="value1" :options="options" :allow-clear="true" /> + <br> + <d-select v-model="value2" :options="options" :multiple="true" :allow-clear="true" /> +</template> + +<script> +import { defineComponent, reactive, ref } from 'vue' + +export default defineComponent({ + setup () { + const value1 = ref('') + const value2 = ref([]) + const items = new Array(6).fill(0).map((item, i) => `Option ${i+1}`) + const options = reactive(items) + + return { + value1, + value2, + options + } + }, +}) +</script> + +``` +::: diff --git a/packages/devui-vue/docs/components/skeleton/index.md b/packages/devui-vue/docs/components/skeleton/index.md new file mode 100644 index 0000000000000000000000000000000000000000..2aae393d3cfc9df4cbac4aa5723e37cfbd7525b2 --- /dev/null +++ b/packages/devui-vue/docs/components/skeleton/index.md @@ -0,0 +1,133 @@ +# Skeleton 骨架屏 +用于在内容加载过程中展示一组占位图形。 + +### 何时使用 +在需要等待加载内容的位置设置一个骨架屏,某些场景下比 Loading 的视觉效果更好。 + +### 基本用法 +最基本的占位效果。 + +:::demo + +```vue +<template> + <d-skeleton :row="3" /> +</template> +``` +::: + + +### 复杂组合 +:::demo + +```vue +<template> + <div class="skeleton-btn-groups"> + <div class="skeleton-btn"> + 展示骨架屏: + <d-switch v-model:checked="loading" /> + </div> + <div class="skeleton-btn"> + 动画: + <d-switch v-model:checked="animate" /> + </div> + <div class="skeleton-btn"> + 显示头像: + <d-switch v-model:checked="avatar" /> + </div> + <div class="skeleton-btn"> + 显示标题: + <d-switch v-model:checked="title" /> + </div> + <div class="skeleton-btn"> + 显示段落: + <d-switch v-model:checked="paragraph" /> + </div> + <div class="skeleton-btn"> + 头像圆角: + <d-switch v-model:checked="roundAvatar" /> + </div> + <div class="skeleton-btn"> + 段落和标题圆角: + <d-switch v-model:checked="round" /> + </div> + </div> + <d-skeleton :row="3" :animate="animate" :avatar="avatar" :avatar-shape="roundAvatar?'':'square'" :title="title" :paragraph="paragraph" :loading="loading" :round="round"> + <div> + <div>row one</div> + <div>row two</div> + <div>row three</div> + <div>row four</div> + </div> + </d-skeleton> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup () { + const loading = ref(true) + const animate = ref(true) + const avatar = ref(true) + const title = ref(true) + const paragraph = ref(true) + const roundAvatar = ref(true) + const round = ref(false) + + return { + loading, + animate, + avatar, + title, + paragraph, + roundAvatar, + round + } + } +}) +</script> +<style> +.skeleton-btn-groups{ + display: flex; + margin-bottom: 1rem; +} +.skeleton-btn{ + display: flex; + flex-direction: column; + justify-content: space-between; +} +</style> +``` +::: + +### API +d-skeleton +| 参数 | 类型 | 默认 | 说明 | +| :-----: | :-------: | :-----: | :-------------------------------------------- | +| loading | `boolean` | `true` | 是否显示骨架屏,传 `false` 时会展示子组件内容 | +| animate | `boolean` | `true` | 是否开启动画 | +| avatar | `boolean` | `false` | 是否显示头像占位图 | +| title | `boolean` | `true` | 是否显示标题占位图 | +| paragraph | `boolean` | `true` | 是否显示段落占位图 | +| round | `boolean` | `false` | 是否将标题和段落显示为圆角风格 | + +d-skeleton-avatar-props +| 参数 | 类型 | 默认 | 说明 | +| :-----: | :-------: | :-----: | :-------------------------------------------- | +| avatar-size | `number \| string` | `40px` | 头像占位图大小 | +| avatar-shape | `string` | `round` | 头像占位图形状,可选值为`square` | + + +d-skeleton-title-props +| 参数 | 类型 | 默认 | 说明 | +| :-----: | :-------: | :-----: | :-------------------------------------------- | +| title-width | `number \| string` | `40%` | 设置标题占位图的宽度 | + + +d-skeleton-paragraph-props +| 参数 | 类型 | 默认 | 说明 | +| :-----: | :-------: | :-----: | :-------------------------------------------- | +| row | `number` | `0` | 段落占位图行数 | +| row-width | `number \| string \| (number \| string)[]` | `["100%"]` | 段落占位图宽度,可传数组来设置每一行的宽度 | + + diff --git a/packages/devui-vue/docs/components/slider/index.md b/packages/devui-vue/docs/components/slider/index.md new file mode 100644 index 0000000000000000000000000000000000000000..641dd54ff920692ad85bb60e20fb471eeba66e31 --- /dev/null +++ b/packages/devui-vue/docs/components/slider/index.md @@ -0,0 +1,171 @@ +# Slider 滑动输入条 + +### 何时使用 + +当用户需要在数值区间内进行选择时使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <div class="slider-wrapper" style="padding:20px"> + <d-slider :min="minValue" :max="maxValue" v-model="inputValue"></d-slider> + </div> +</template> + +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const inputValue = ref(12); + const minValue = ref(0); + const maxValue = ref(20); + return { + inputValue, + maxValue, + minValue, + }; + }, +}); +</script> +``` + +::: + +### 可设置 Step 的滑动组件 + +:::demo + +```vue +<template> + <div class="slider-wrapper" style="padding:20px"> + <d-slider :min="minValue" :max="maxValue" v-model="inputValue" :step="step"></d-slider> + </div> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const inputValue = ref(8); + const minValue = ref(0); + const maxValue = ref(20); + const step = ref(4); + return { + inputValue, + maxValue, + minValue, + step, + }; + }, +}); +</script> +``` + +::: + +### 带有输入框的滑动组件 + +:::demo + +```vue +<template> + <div class="slider-wrapper" style="padding:20px"> + <d-slider :min="minValue" :max="maxValue" v-model="inputValue" showInput></d-slider> + </div> +</template> +<script lang="ts"> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const inputValue = ref(10); + const minValue = ref(0); + const maxValue = ref(20); + return { + inputValue, + maxValue, + minValue, + }; + }, +}); +</script> +``` + +::: + +### 禁止输入态 + +:::demo + +```vue +<template> + <div class="slider-wrapper" style="padding:20px"> + <d-slider :min="minValue" :max="maxValue" disabled v-model="disabledValue"></d-slider> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const disabledValue = ref(5); + const maxValue = ref(50); + const minValue = ref(2); + return { + disabledValue, + maxValue, + minValue, + }; + }, +}); +</script> +``` + +::: + +### 定制 Popover 的显示内容 + +通过 tipsRenderer 参数传入定制 Popover 内的显示内容。 +:::demo + +```vue +<template> + <div> + <div class="slider-wrapper" style="padding:20px"> + <d-slider :min="minValue" :max="maxValue" v-model="inputValue" tipsRenderer="apple"></d-slider> + <br style="margin-bottom: 20px" /> + <d-slider :min="minValue" :max="maxValue" v-model="inputValue" tipsRenderer="null" ></d-slider> + </div> + </div> +</template> +<script> +import { defineComponent, ref } from 'vue'; +export default defineComponent({ + setup() { + const inputValue = ref(5); + const maxValue = ref(50); + const minValue = ref(2); + return { + inputValue, + maxValue, + minValue, + }; + }, +}); +</script> +``` + +::: + +### API + +d-slider 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 | +| ------------ | ------- | ----- | ------------------------------------------------------------------- | ------------------------------------ | +| max | number | 100 | 可选,滑动输入条的最大值 | [基本用法](#基本用法) | +| min | number | 0 | 可选,滑动输入条的最小值 | [基本用法](#基本用法) | +| step | number | 1 | 可选,滑动输入条的步长,取值必须大于等于 1,且必须可被(max-min)整除 | [基本用法](#可设置Step的滑动组件) | +| disabled | boolean | false | 可选,值为 true 时禁止用户输入 | [基本用法](#禁止输入态) | +| showInput | boolean | false | 可选,值为 true 显示输入框 | [基本用法](#带有输入框的滑动组件) | +| tipsRenderer | string | | 可选,渲染 Popover 内容的函数,传入 null 时不显示 Popover | [基本用法](#异定制popover的显示内容) | diff --git a/packages/devui-vue/docs/components/splitter/index.md b/packages/devui-vue/docs/components/splitter/index.md new file mode 100644 index 0000000000000000000000000000000000000000..c231ea9e9cf85c8ff422f27901d37653142bd961 --- /dev/null +++ b/packages/devui-vue/docs/components/splitter/index.md @@ -0,0 +1,338 @@ +# Splitter 分割器 + +页面分割器。 + +**何时使用** + +需要动态调整不同页面布局区域大小的时候选择使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <section> + <d-splitter class="splitter-border" :orientation="orientation" :splitBarSize="splitBarSize" style="height: 300px"> + <template v-slot:DSplitterPane> + <d-splitter-pane collapseDirection="before" :size="size" :minSize="minSize" :collapsible="true" @sizeChange="sizeChange" @collapsedChange="collapsedChange"> + <div class="pane-content"> + <h2>Left</h2> + <div>width: 30%, min-width: 20%</div> + </div> + </d-splitter-pane> + <d-splitter-pane minSize="15%"> + <div class="pane-content"> + <h2>Right</h2> + <div>Content</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + </section> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + name: "DSplitterDemoBasic", + setup() { + const orientation = ref("horizontal"); + const splitBarSize = '2px'; + // splitter pane input + const size = ref("30%"); + const minSize = ref("20%"); + const maxSize = ref("60%"); + const sizeChange = (size) => { + console.log(size); + } + const collapsedChange = (event) => { + console.log(event); + } + + return { + orientation, + splitBarSize, + size, + minSize, + maxSize, + sizeChange, + collapsedChange + } + }, +}) +</script> + +<style> +.pane-content { + padding: 0 12px; +} + +.splitter-border { + border: 1px solid #dfe1e6; +} + +</style> +``` +::: + + + <!-- `<style lang="scss"></style>` 的写法,在 `:::demo 语法中` 不起作用, 看了依赖包 `vitepress-theme-demoblock` 源码 +是渲染的正则表达式只匹配 `<style></style>` 这种写法,TODO:待后续优化 +<style lang="scss"> +@import "@devui/style/theme/color"; + +.pane-content { + padding: 0 12px; +} + +.splitter-border { + border: 1px solid $devui-dividing-line; +}--> + +### 垂直布局用法 + +:::demo + +```vue +<template> + <section> + <d-splitter style="height: 500px" class="splitter-border" orientation="vertical" :disableBarSize="disableBarSize" > + <template v-slot:DSplitterPane> + <d-splitter-pane size="200px" minSize="150px" :collapsed="collapsed" :collapsible="true" @sizeChange="sizeChange"> + <div class="pane-content"> + <h2>Top</h2> + <div>height: 200px</div> + </div> + </d-splitter-pane> + <d-splitter-pane style="overflow: hidden"> + <div class="pane-content"> + <h2>Center</h2> + <div>height: auto</div> + </div> + </d-splitter-pane> + <d-splitter-pane size="150px" :resizable="false" :collapsible="true"> + <div class="pane-content"> + <h2>Bottom</h2> + <div>height: 150px, resizable: false</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + </section> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + name: "DSplitterDemoVertical", + setup() { + const collapsed = ref(true); + const disableBarSize = '2px'; + + const sizeChange = (size) => { + console.log(size); + } + + return { + disableBarSize, + collapsed, + sizeChange, + } + }, +}) +</script> + +<style> +.pane-content { + padding: 0 12px; +} + +.splitter-border { + border: 1px solid #dfe1e6; +} + +</style> +``` + +::: + +### 组合布局用法 + +:::demo + +```vue +<template> + <section> + <d-splitter class="splitter-border" style="height: 600px" orientation="vertical"> + <template v-slot:DSplitterPane> + <d-splitter-pane size="400px" minSize="100px" :sizeChange="sizeChange"> + <d-splitter style="height: 100%"> + <template v-slot:DSplitterPane> + <d-splitter-pane size="30%" minSize="20%" :sizeChange="sizeChange"> + <div class="pane-content"> + <h2>Left</h2> + <div>width: 30%, min-width: 20%</div> + </div> + </d-splitter-pane> + <d-splitter-pane minSize="15%"> + <d-splitter style="height: 100%" orientation="vertical"> + <template v-slot:DSplitterPane> + <d-splitter-pane size="50%" style="overflow: hidden"> + <div class="pane-content"> + <h2>Top</h2> + <div>height: 50%</div> + </div> + </d-splitter-pane> + <d-splitter-pane style="overflow: hidden"> + <div class="pane-content"> + <h2>Bottom</h2> + <div>height: auto</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + </d-splitter-pane> + </template> + </d-splitter> + </d-splitter-pane> + <d-splitter-pane style="overflow: hidden"> + <div class="pane-content"> + <h2>Bottom</h2> + <div>height: auto</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + </section> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + name: "DSplitterDemoMulti", + setup() { + + const sizeChange = (size) => { + console.log(size); + } + + return { + sizeChange, + } + }, +}) +</script> + +<style> +.pane-content { + padding: 0 12px; +} + +.splitter-border { + border: 1px solid #dfe1e6; +} + +</style> +``` + +::: + +### 指定折叠收起方向 + +:::demo + +```vue +<template> + <section> + <d-splitter class="splitter-border" style="height: 300px"> + <template v-slot:DSplitterPane> + <d-splitter-pane size="30%" minSize="20%" :sizeChange="sizeChange"> + <div class="pane-content"> + <h2>Left</h2> + <div>width: 30%, min-width: 20%</div> + </div> + </d-splitter-pane> + <d-splitter-pane minSize="15%" :collapsible="true" collapseDirection="before"> + <div class="pane-content"> + <h2>Center</h2> + <div>Specify the folding and retracting direction to fold forward</div> + </div> + </d-splitter-pane> + <d-splitter-pane minSize="15%"> + <div class="pane-content"> + <h2>Right</h2> + <div>Content</div> + </div> + </d-splitter-pane> + </template> + </d-splitter> + </section> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + name: "DSplitterDemoDirection", + setup() { + + const sizeChange = (size) => { + console.log(size); + } + + return { + sizeChange, + } + }, +}) +</script> + +<style> +.pane-content { + padding: 0 12px; +} + +.splitter-border { + border: 1px solid #dfe1e6; +} + +</style> +``` + +::: + +### 折叠收缩显示菜单 【TODO】 + +### API + +### d-splitter 参数 + +| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | +| :----------------: | :----------: | :-----------: | :-------------------------------: | :--------------------------------------------- | +| orientation | `'vertical' \| 'horizontal'` | 'horizontal' | 可选,指定 Splitter 分割方向,可选值 'vertical' \| 'horizontal' | [基本用法](#基本用法) +| splitBarSize | `string` | '2px' | 可选,分隔条大小,默认 2px | [基本用法](#基本用法) | +| disabledBarSize | `string` | '1px' | 可选,pane 设置不可调整宽度时生效 | [垂直布局用法](#垂直布局用法) | +| showCollapseButton | `boolean` | true | 可选,是否显示收起/展开按钮 | [折叠收缩显示菜单](#折叠收缩显示菜单) | + +### d-splitter-pane 参数 + +| 参数 | 类型 | 默认值 | 描述 | 跳转 Demo | +| :---------------: | :--------: | :------: | :---------------------------------------------------: | :------------------------------------ | +| size | `string` | -- | 可选,指定 pane 宽度,设置像素值或者百分比 | [基本用法](#基本用法) | +| minSize | `string` | -- | 可选,指定 pane 最小宽度,设置像素值或者百分比 | [基本用法](#基本用法) | +| maxSize | `string` | -- | 可选,指定 pane 最大宽度,设置像素值或者百分比 | [基本用法](#基本用法) | +| resizable | `boolean` | true | 可选,指定 pane 是否可调整大小,会影响相邻 pane | [垂直布局用法](#垂直布局用法) | +| collapsible | `boolean` | false | 可选,指定 pane 是否可折叠收起 | [基本用法](#基本用法) | +| collapsed | `boolean` | false | 可选,指定 pane 初始化是否收起,配合`collapsible`使用 | [垂直布局用法](#垂直布局用法) | +| collapseDirection | `'before' \| 'after' \| 'both'` | 'both' | 可选,指定非边缘 pane 收起方向,配合`collapsible`使用 | [指定折叠收起方向](#指定折叠收起方向) + +### d-splitter-pane 事件 + +| 事件 | 类型 | 描述 | 跳转 Demo | +| :----------------: | :---------------------: | :-----------------------------------------: | ------------------------------------- | +| sizeChange | `EventEmitter<string>` | 大小变动时,返回改变后的值,像素值或者百分比 | [基本用法](#基本用法) | +| collapsedChange | `EventEmitter<boolean>` | 折叠和展开时,返回当前 pane 是否折叠 | [基本用法](#基本用法) | diff --git a/packages/devui-vue/docs/components/status/index.md b/packages/devui-vue/docs/components/status/index.md new file mode 100644 index 0000000000000000000000000000000000000000..fc143388c68575044f91d42e2b365b6dd6151c53 --- /dev/null +++ b/packages/devui-vue/docs/components/status/index.md @@ -0,0 +1,30 @@ +# Status 状态 + +传达交互结果的组件。 + +### 何时使用 + +表示一个任务的执行结果时使用。 + +### 基本用法 + +:::demo +```vue +<template> + <d-status>Default</d-status> + <d-status type="success">Success</d-status> + <d-status type="error">Error</d-status> + <d-status type="warning">Warning</d-status> + <d-status type="initial">Initial</d-status> + <d-status type="waiting">Waiting</d-status> + <d-status type="running">Running</d-status> + <d-status type="invalid">Invalid</d-status> +</template> +``` +::: + +### d-status 参数 + +| 参数 | 类型 | 默认 | 说明 | +| :--: | :------------------------------------------------------------: | :-------: | :--------------------------------------------------------------------------: | +| type | `success\|error\|warning\|initial\|waiting\|running\| invalid` | 'initial' | 必选,类型,值有 success、error、warning、initial、waiting、running、invalid | diff --git a/packages/devui-vue/docs/components/steps-guide/index.md b/packages/devui-vue/docs/components/steps-guide/index.md new file mode 100644 index 0000000000000000000000000000000000000000..4744d655014125029c194ed6273c4848e6937098 --- /dev/null +++ b/packages/devui-vue/docs/components/steps-guide/index.md @@ -0,0 +1,185 @@ +# steps-guide 操作指引 + +引导用户了解业务使用逻辑组件。 + +### 何时使用 + +业务推出新特性,或复杂的业务逻辑需要指引用户时使用。 + +### 基本用法 +设定一组操作指引信息顺序显示。 +:::demo +```vue +<template> + <d-button btnStyle="common" class="step-1">Step 1</d-button> + <d-button btnStyle="common" class="step-2">Step 2</d-button> + <d-button btnStyle="common" class="step-3">Step 3</d-button> + <d-steps-guide :steps="steps" ref="stepsRef"></d-steps-guide> +</template> +<script> + import { defineComponent, reactive, ref, onMounted } from 'vue' + export default defineComponent({ + setup() { + const steps = reactive([ + { title: '基础用法1', content: '业务推出新特性,或复杂的业务逻辑需要指引用户时使用。', trigger: '.step-1' }, + { title: '基础用法2', content: '业务推出新特性,或复杂的业务逻辑需要指引用户时使用。', trigger: '.step-2' }, + { title: '基础用法3', content: '业务推出新特性,或复杂的业务逻辑需要指引用户时使用。', trigger: '.step-3' } + ]); + const stepsRef = ref(null) + + return { + steps, + stepsRef + } + } + }) +</script> +<style> + .devui-btn-host { + margin-left: 10px; + } +</style> +``` +::: + +### 弹出位置 +总共支持 8 个弹出位置。 +:::demo +```vue +<template> + <div class="top-group"> + <d-button btnStyle="common" class="top-left" width="120px" @click="handleClick(0)">Top-left</d-button> + <d-button btnStyle="common" class="top" width="120px" @click="handleClick(1)">Top</d-button> + <d-button btnStyle="common" class="top-right" width="120px" @click="handleClick(2)">Top-right</d-button> + </div> + <div class="middle-group"> + <d-button btnStyle="common" class="left" width="120px" @click="handleClick(7)">Left</d-button> + <d-button btnStyle="common" class="right" width="120px" @click="handleClick(3)">Right</d-button> + </div> + <div class="bottom-group"> + <d-button btnStyle="common" class="bottom-left" width="120px" @click="handleClick(6)">Bottom-left</d-button> + <d-button btnStyle="common" class="bottom" width="120px" @click="handleClick(5)">Bottom</d-button> + <d-button btnStyle="common" class="bottom-right" width="120px" @click="handleClick(4)">Bottom-right</d-button> + </div> + <d-steps-guide :steps="stepsPosition" ref="stepsPositionRef"></d-steps-guide> +</template> +<script> + import { defineComponent, reactive, ref } from 'vue' + export default defineComponent({ + setup() { + const stepsPosition = reactive([ + { title: '弹出位置 top-left', + content: 'Steps Guide', + trigger: '.top-left', + position: 'top-left' + }, + { title: '弹出位置 top', + content: 'Steps Guide', + trigger: '.top', + position: 'top' + }, + { title: '弹出位置 top-right', + content: 'Steps Guide', + trigger: '.top-right', + position: 'top-right' + }, + { title: '弹出位置 right', + content: 'Steps Guide', + trigger: '.right', + position: 'right' + }, + { title: '弹出位置 bottom-right', + content: 'Steps Guide', + trigger: '.bottom-right', + position: 'bottom-right' + }, + { title: '弹出位置 bottom', + content: 'Steps Guide', + trigger: '.bottom', + position: 'bottom' + }, + { title: '弹出位置 bottom-left', + content: 'Steps Guide', + trigger: '.bottom-left', + position: 'bottom-left' + }, + { title: '弹出位置 left', + content: 'Steps Guide', + trigger: '.left', + position: 'left' + } + ]); + + const stepsPositionRef = ref(null) + + const handleClick = (index) => { + stepsPositionRef.value.setCurrentIndex(index) + } + return { + stepsPosition, + handleClick, + stepsPositionRef + } + } + }) +</script> +<style> + .top-group, .middle-group, .bottom-group { + margin-bottom: 10px; + display: flex; + justify-content: center; + } + .middle-group { + justify-content: space-between; + } +</style> +``` +::: + +### 自定义 +自定义操作指引信息弹出的位置和元素。 +:::demo +```vue +<template> + <d-button btnStyle="common" class="bottom">Custom Position</d-button> + <d-steps-guide :steps="customSteps" :showDots="false" :showClose="false"></d-steps-guide> +</template> +<script> +import { defineComponent, reactive } from 'vue' +export default defineComponent({ + setup() { + const customSteps = reactive([ + { title: '自定义用法', + content: '自定义操作指引信息弹出的位置和元素。', + trigger: '.custom-1', + position: { + left: 0, + top: 0, + type: 'top-left' + } }, + { + title: '自定义用法', + content: '自定义操作指引信息弹出的位置和元素。', + trigger: '.custom-2', + target: '.nav-links', + position: 'bottom' + }, + ]); + return { + customSteps + } + } +}) +</script> +``` +::: + +### API + +d-steps-guide 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 | +| ----- | ----- | ---- | ---------------------- | --------------------- | +| steps | array | Step[] | 必选,操作指引步骤数组 | [基本用法](#基本用法) | +| showClose | boolean | true | 可选,是否显示关闭按钮 | [自定义](#基本用法) | +| showDots | boolean | true | 可选,是否显示表示导航指引顺序的圆点 | [自定义](#基本用法) | \ No newline at end of file diff --git a/packages/devui-vue/docs/components/sticky/index.md b/packages/devui-vue/docs/components/sticky/index.md new file mode 100644 index 0000000000000000000000000000000000000000..e515c12260fbe5331d215d4a193fcbdea110392c --- /dev/null +++ b/packages/devui-vue/docs/components/sticky/index.md @@ -0,0 +1,139 @@ +# Sticky 便贴 + +便签组件。 + +### 何时使用 + +当用户在滚动屏幕时,需要某个区域内容在段落或者浏览器可视区域可见时。 + +### 基本用法 + +:::demo 默认容器为父元素 + +```vue +<template> + <div style="height: 400px"> + <d-sticky :view="view" :zIndex="zIndex" @statusChange="statusChangeHandler"> + <p>基本用法</p> + </d-sticky> + </div> +</template> + +<script> +export default { + setup(props) { + const view = { + top: 100, + bottom: 0 + } + const zIndex = 1000 + + function statusChangeHandler(status) { + console.log('status =', status) + } + + return { + view, + zIndex, + statusChangeHandler + } + } +} +</script> +``` + +::: + +### 指定容器 + +:::demo + +```vue +<template> + <div style="height: 200px"> + <d-sticky :view="view" :container="container"> + <p>指定容器</p> + </d-sticky> + </div> +</template> + +<script> +import { reactive, onMounted, toRefs } from 'vue' +export default { + setup(props) { + let state = reactive({ + container: null + }) + const view = { + top: 100, + bottom: 0 + } + onMounted(() => { + state.container = document.getElementsByClassName('container')[0] + }) + return { + view, + ...toRefs(state) + } + } +} +</script> +``` + +::: + +### 指定滚动容器 + +:::demo + +```vue +<template> + <div style="height:200px; overflow-y: scroll; " class="scrollTarget"> + <div style="height: 1000px"> + <d-sticky :view="view" :scrollTarget="scrollTarget"> + <p>指定滚动容器</p> + </d-sticky> + </div> + </div> +</template> + +<script> +import { reactive, onMounted, toRefs } from 'vue' + +export default { + setup(props) { + let state = reactive({ + scrollTarget: null + }) + const view = { + top: 100, + bottom: 0 + } + onMounted(() => { + state.scrollTarget = document.getElementsByClassName('scrollTarget')[0] + }) + return { + view, + ...toRefs(state) + } + } +} +</script> +``` + +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :----------: | :----------------------------: | :----------------------: | :------------------------------------------------------------------------------------- | ----------------------------- | ---------- | +| zIndex | `number` | -- | 可选,指定包裹层的 z-index,用于浮动的时候控制 z 轴的叠放 | [基本用法](#基本用法) | | +| container | `Element` | 父容器 | 可选,触发的容器,可不同于父容器 | [指定容器](#指定容器) | | +| view | `{top?:number,bottom?:number}` | `{top:0,bottom:0}` | 可选,用于可视区域的调整,比如顶部有固定位置的头部等,数值对应被遮挡的顶部或底部的高度 | [基本用法](#基本用法) | | +| scrollTarget | `Element` | document.documentElement | 可选,设置要发生滚动的容器,一般为滚动条所在容器,为主页面的滚动条时候可以不设置 | [指定滚动容器](#指定滚动容器) | | + +### d-sticky 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| :----------: | :------: | :------------------------------------------: | :-------------------: | +| statusChange | `string` | 可选,状态变化的时候触发,值为变化后的状态值 | [基本用法](#基本用法) | diff --git a/packages/devui-vue/docs/components/switch/index.md b/packages/devui-vue/docs/components/switch/index.md new file mode 100644 index 0000000000000000000000000000000000000000..e3b97ac7e71d48a7d12eb3462130bcdfef3db8f9 --- /dev/null +++ b/packages/devui-vue/docs/components/switch/index.md @@ -0,0 +1,115 @@ +# Switch 开关 + +开/关切换组件。 + +### 何时使用 + +当两种状态需要来回切换控制时,比如启用/禁用。 + +### size + +:::demo size可选:`small | middle | large`,默认为middle +```vue +<template> + <d-switch v-model:checked="checkedSmall" size="small"></d-switch> + <d-switch v-model:checked="uncheckedMiddle" ></d-switch> + <d-switch v-model:checked="checkedLarge" size="large"></d-switch> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const checkedSmall = ref(true) + const uncheckedMiddle = ref(false) + const checkedLarge = ref(true) + return { + checkedSmall, + uncheckedMiddle, + checkedLarge + } + } +}) +</script> +``` +::: + +### disabled + +:::demo 可选,是否禁用开关,默认为false +```vue +<template> + <d-switch v-model:checked="checkedDisabled" :disabled='true'></d-switch> + <d-switch v-model:checked="checkedDisabled1" :disabled='true'></d-switch> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const checkedDisabled = ref(true) + const checkedDisabled1 = ref(false) + return { + checkedDisabled, + checkedDisabled1 + } + } +}) +</script> +``` +::: + +### 自定义样式 + +:::demo 可选,可设置文字说明/图标 +```vue +<template> + <d-switch v-model:checked="checkedColor" color="#FECC55"></d-switch> + <d-switch v-model:checked="checkedContent"> + <template #checkedContent>开</template> + <template #uncheckedContent>关</template> +</d-switch> + <d-switch color="#50D4AB" v-model:checked="checkedIcon"> + <template #checkedContent> + <i class="icon-right"></i> + </template> + <template #uncheckedContent> + <i class="icon-error"></i> + </template> +</d-switch> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const checkedColor = ref(true) + const checkedContent = ref(false) + const checkedIcon = ref(true) + return { + checkedColor, + checkedContent, + checkedIcon + } + } +}) +</script> +``` +::: + +### d-switch 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :--------------: | :------------------------: | :------: | :--------------------------: | :------------------------ | +| size | `small \| middle \| large` | `middle` | 可选,开关尺寸大小 | [size](#size) | +| color | `string` | -- | 可选,开关打开时的自定义颜色 | [自定义样式](#自定义样式) | +| checked | `boolean` | false | 可选,开关是否打开,默认关闭 | [基本用法](#size) | +| disabled | `boolean` | false | 可选,是否禁用开关 | [基本用法](#size) | +| checkedContent | `string \| HTMLElement` | '' | 可选,开关打开时说明 | [自定义样式](#自定义样式) | +| uncheckedContent | `string \| HTMLElement` | '' | 可选,开关关闭时说明 | [自定义样式](#自定义样式) | + +### d-switch 事件 + +| 事件 | 类型 | 说明 | +| :----: | :---------------------: | :------------------------------------ | +| change | `EventEmitter<boolean>` | 可选,开关打开返回 true,关闭返回 false | \ No newline at end of file diff --git a/packages/devui-vue/docs/components/table/index.md b/packages/devui-vue/docs/components/table/index.md new file mode 100644 index 0000000000000000000000000000000000000000..fb305b27c2e127afe91f737d63027c7a10b902aa --- /dev/null +++ b/packages/devui-vue/docs/components/table/index.md @@ -0,0 +1,232 @@ +# Table 表格 + +展示行列数据。 + +### 何时使用 + +1. 当有大量结构化的数据需要展现时; +2. 当需要对数据进行排序、过滤、自定义操作等复杂行为时。 + +### 基本用法 + +:::demo 简单表格,`d-table`组件上的`data`属性传入要展示的数据,`d-table-column`组件上通过`field`传入对应列内容的字段名,`header`传入对应列的标题。 + +```vue +<template> + <d-table :data="baseTableData"> + <d-column field="firstName" header="First Name"></d-column> + <d-column field="lastName" header="Last Name"></d-column> + <d-column field="gender" header="Gender"></d-column> + <d-column field="date" header="Date of birth"></d-column> + </d-table> +</template> + +<script> + import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup() { + const baseTableData = ref([ + { + firstName: 'Mark', + lastName: 'Otto', + date: '1990/01/11', + gender: 'Male', + }, + { + firstName: 'Jacob', + lastName: 'Thornton', + gender: 'Female', + date: '1990/01/12', + }, + { + firstName: 'Danni', + lastName: 'Chen', + gender: 'Male', + date: '1990/01/13', + }, + { + firstName: 'green', + lastName: 'gerong', + gender: 'Male', + date: '1990/01/14', + } + ]) + + return { baseTableData } + } + }) + +</script> +``` + +::: + +### 表格样式 + +:::demo + +```vue +<template> +<div class="table-btn-groups"> + <div class="table-btn"> + 自动表格布局: + <d-switch v-model:checked="tableLayout" /> + </div> + <div class="table-btn"> + 斑马纹: + <d-switch v-model:checked="striped" /> + </div> + <div class="table-btn"> + 表头背景色: + <d-switch v-model:checked="headerBg" /> + </div> + </div> + <d-table :table-layout="tableLayout?'auto':'fixed'" :striped="striped" :header-bg="headerBg" :data="stripedTableData"> + <d-column field="firstName" header="First Name"></d-column> + <d-column field="lastName" header="Last Name"></d-column> + <d-column field="gender" header="Gender"></d-column> + <d-column field="date" header="Date of birth"></d-column> + </d-table> +</template> + +<script> + + import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup() { + const tableLayout = ref(false) + const striped = ref(false) + const headerBg = ref(false) + const stripedTableData = ref([ + { + firstName: 'Mark', + lastName: 'Otto', + date: '1990/01/11', + gender: 'Male', + }, + { + firstName: 'Jacob', + lastName: 'Thornton', + gender: 'Female', + date: '1990/01/12', + }, + { + firstName: 'Danni', + lastName: 'Chen', + gender: 'Male', + date: '1990/01/13', + }, + { + firstName: 'green', + lastName: 'gerong', + gender: 'Male', + date: '1990/01/14', + } + ]) + + return { + stripedTableData, + striped, + headerBg, + tableLayout + } + } + }) +</script> + +<style lang="scss"> +.table-btn-groups{ + display: flex; + margin-bottom: 1rem; +} +.table-btn{ + display: flex; + flex-direction: column; + justify-content: space-between; +} +</style> +``` + +::: + +### 空数据模板 + +:::demo 当传入的数据为空时,默认展示空数据模板。 + +```vue +<template> + <div> + <d-button type="primary" @click="handleClick">更新数据</d-button> + <d-table :data="emptyData"> + <d-column field="firstName" header="First Name"></d-column> + <d-column field="lastName" header="Last Name"></d-column> + <d-column field="gender" header="Gender"></d-column> + <d-column field="date" header="Date of birth"></d-column> + </d-table> + </div> +</template> + +<script> + + import { defineComponent, ref } from 'vue' + + export default defineComponent({ + setup() { + const emptyData = ref([]) + const handleClick = () => { + emptyData.value = [ + { + firstName: 'po', + lastName: 'Lang', + gender: 'Male', + date: '1990/01/15', + }, + { + firstName: 'john', + lastName: 'Li', + gender: 'Female', + date: '1990/01/16', + }, + { + firstName: 'peng', + lastName: 'Li', + gender: 'Male', + date: '1990/01/17', + }, + { + firstName: 'Dale', + lastName: 'Yu', + gender: 'Female', + date: '1990/01/18', + } + ] + } + + return { emptyData, handleClick } + } + }) +</script> +``` + +::: + + +### d-table Props + +| 参数 | 类型 | 默认值 | 说明 | +| ------------ | ------------------- | --------- | ------------------------ | +| data | `Array` | `[]` | 显示的数据 | +| striped | `Boolean` | `false` | 是否显示斑马纹间隔 | +| header-bg | `Boolean` | `false` | 可选,表头是否显示背景色 | +| table-layout | `String` | `'fixed'` | 表格布局,可选值为`'auto'`| + +### d-column Props + +| 参数 | 类型 | 默认值 | 说明 | +| --------- | ------------------ | ------ | -------------------------- | +| header | `String` | `-` | 对应列的标题 | +| field | `String` | `-` | 对应列内容的字段名 | +| width | `String \| Number` | `-` | 对应列的宽度,单位`px` | +| min-width | `String \| Number` | `-` | 对应列的最小宽度,单位`px` | \ No newline at end of file diff --git a/packages/devui-vue/docs/components/tabs/index.md b/packages/devui-vue/docs/components/tabs/index.md new file mode 100644 index 0000000000000000000000000000000000000000..b7f2486136c4c4bf63d627f9c861666442b91289 --- /dev/null +++ b/packages/devui-vue/docs/components/tabs/index.md @@ -0,0 +1,326 @@ +# Tabs 选项卡切换 + +选项卡切换组件。 + +### 何时使用 + +用户需要通过平级的区域将大块内容进行收纳和展现,保持界面整洁。 + +### 基本用法 + +:::demo + +```vue +<template> + <d-tabs type="tabs" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab1'); + return { + id + }; + } +}); +</script> +``` + +::: + +### Pills 类型 + +:::demo + +```vue +<template> + <d-tabs type="pills" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab1'); + return { + id + }; + } +}); +</script> +``` + +::: + +### Options 类型 + +:::demo + +```vue +<template> + <d-tabs type="options" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab1'); + return { + id + }; + } +}); +</script> +``` + +::: + +### Wrapped 类型 + +:::demo + +```vue +<template> + <d-tabs type="wrapped" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab1'); + return { + id + }; + } +}); +</script> +``` + +::: + +### Slider 类型 + +:::demo + +```vue +<template> + <d-tabs type="slider" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab1'); + return { + id + }; + } +}); +</script> +``` + +::: + +### 禁用选项卡 + +:::demo + +```vue +<template> + <d-tabs type="tabs" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1" :disabled="true"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab2'); + return { + id + }; + } +}); +</script> +``` + +::: + +### 拦截 tab 切换 + +:::demo + +```vue +<template> + <d-tabs + type="tabs" + v-model="id" + :beforeChange="beforeChange" + @activeTabChange="activeTabChange" + > + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab3'); + const beforeChange = (tab) => { + if (tab === 'tab1') { + id.value = 'tab2'; + return false; + } else { + return true; + } + }; + const activeTabChange = (id) => { + console.log(id, 'activeTabChange'); + }; + return { + id, + beforeChange, + activeTabChange + }; + } +}); +</script> +``` + +::: + +### 自定义模板 + +:::demo + +```vue +<template> + <d-tabs type="tabs" v-model="id"> + <d-tab id="tab1" title="Tab1" tabId="tab1"> + <template v-slot:dTabTitle> 就是这样 </template> + <p>Tab1 Content</p> + </d-tab> + <d-tab id="tab2" title="Tab2" tabId="tab2"> + <template v-slot:dTabTitle> 就是这样1 </template> + <p>Tab2 Content</p> + </d-tab> + <d-tab id="tab3" title="Tab3" tabId="tab3"> + <template v-slot:dTabTitle> 就是这样2 </template> + <p>Tab3 Content</p> + </d-tab> + </d-tabs> +</template> +<script> +import { defineComponent, ref } from 'vue'; + +export default defineComponent({ + setup() { + const id = ref('tab3'); + return { + id + }; + } +}); +</script> +``` + +::: + +### API + +| 参数 | 类型 | 默认 | 说明 | | +| :----------: | :---------------------------------------------: | :----: | :---------------------------------------------------------------------------------------------------: | --- | +| type | `tabs \| pills \| options \| wrapped \| slider` | 'tabs' | 可选,选项卡组的类型 | +| showContent | `boolean` | true | 可选,是否显示选项卡对应的内容 | +| v-model | `string` | -- | 可选,当前激活的选项卡,值为选项卡的 id | +| customWidth | `string` | -- | 可选,自定义选项卡的宽 | +| vertical | `boolean` | false | 可选,是否垂直显 | +| beforeChange | `function\|Promise` | -- | tab 切换前的回调函数,返回 boolean 类型,返回 false 可以阻止 tab 的切换 | +| reactivable | `boolean` | false | 可选,点击当前处于激活态的 tab 时是否触发`activeTabChange`事件,`true`为允许触发,`false`为不允许触发 | + +### d-tabs 事件 + +| 参数 | 类型 | 说明 | +| :-------------: | :------------------------: | :-------------------------------------------------- | +| activeTabChange | `function(string\|number)` | 可选,选项卡切换的回调函数,返回当前激活选项卡的 id | + +### d-tab 参数 + +| 参数 | 类型 | 默认 | 说明 | +| :------: | :--------------: | :---: | :------------------------------------- | +| id | `number\|string` | -- | 可选,选项卡的 id 值, 需要设置为唯一值 | +| title | `string` | -- | 可选,选项卡的标题 | +| disabled | `boolean` | false | 可选,选项卡是否不可用 | diff --git a/packages/devui-vue/docs/components/tag-input/index.md b/packages/devui-vue/docs/components/tag-input/index.md new file mode 100644 index 0000000000000000000000000000000000000000..36586edb7a0de9fe19d7107d54d078d533cc627a --- /dev/null +++ b/packages/devui-vue/docs/components/tag-input/index.md @@ -0,0 +1,145 @@ +# TagInput 标签输入框 + +输入标签组件。 + +### 何时使用 + +当用户需要输入多个标签时。 + +### 基本用法 + +:::demo + +```vue +<template> + <d-tag-input + v-model:tags="state.tags" + v-model:suggestionList="state.suggestionList" + displayProperty="name" + placeholder="Add a tag" + no-data="暂无数据" + :minLength='1' + :caseSensitivity="true" + @valueChange="changeValue" + @update:tags="changeTags" + @update:suggestionList="changeSuggestionList" + ></d-tag-input> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + setup() { + const state = reactive({ + tags: [{ name: "123" }], + suggestionList: [{ name: "item1" }] + }) + const changeTags = (val) => { + console.log(val) + } + const changeSuggestionList = (val) => { + console.log(val) + } + const changeValue = (val) => { + console.log(val) + } + + return { + state, + changeTags, + changeSuggestionList, + changeValue + } + } +}) +</script> +``` +::: + +### disabled +:::demo + +```vue +<template> + <d-tag-input + v-model:tags="state.tags" + v-model:suggestionList="state.suggestionList" + :disabled="true" + ></d-tag-input> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + setup() { + const state = reactive({ + tags: [{ name: "123" }], + suggestionList: [{ name: "item1" }] + }) + + return { + state + } + } +}) +</script> +``` + +::: +### 标签最小长度&最大标签数 +:::demo + +```vue +<template> + <d-tag-input + v-model:tags="state.tags" + v-model:suggestionList="state.suggestionList" + :minLength="3" + :maxTags="5" + ></d-tag-input> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + setup() { + const state = reactive({ + tags: [{ name: "123" }], + suggestionList: [{ name: "item1" }] + }) + + return { + state + } + } +}) +</script> +``` + +::: + +### d-tag-input 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :-------------: | :-------: | :---------------------: | :----------------------------------: | :-------------------- | ---------- | +| tags | `Array` | [] | 必选,记录输入的标签和选择的标签列表 | [基本用法](#基本用法) | +| suggestionList | `Array` | [] | 可选,下拉选项,默认可选择的标签列表 | [基本用法](#基本用法) | +| displayProperty | `string` | 'name' | 可选,列表项使用的属性名 | [基本用法](#基本用法) | +| placeholder | `boolean` | '' | 可选,输入框的 placeholder | [基本用法](#基本用法) | +| noData | `boolean` | '' | 可选,无数据提示 | [基本用法](#基本用法) | +| maxTags | `number` | Number.MAX_SAFE_INTEGER | 可选,可输入标签的最大个数 | [标签最小长度&最大标签数](#标签最小长度-最大标签数) | +| minLength | `number` | `3` | 可选,可输入标签的最大个数 | [标签最小长度&最大标签数](#标签最小长度-最大标签数) | +| maxLength | `number` | Number.MAX_SAFE_INTEGER | 可选,可输入标签的最大个数 | [标签最小长度&最大标签数](#标签最小长度-最大标签数) | +| caseSensitivity | `boolean` | false | 可选,大小写敏感,默认忽略大小写 | | | +| spellcheck | `boolean` | true | 可选,input 输入框是否开启拼写检查的 | | | +| isAddBySpace | `boolean` | true | 可选,是否支持空格键输入标签 | | | +| disabled | `boolean` | false | 可选,disabled 灰化状态 | [disabled](#disabled) | +| showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | + +### d-tags-input 事件 + +| 事件 | 说明 | 跳转 Demo | +| :---------: | :------------------------------------------------------- | --------------------- | +| valueChange | 当选中某个选项项后,将会调用此函数,参数为当前选择项的值 | [基本用法](#基本用法) | +| update:tags | 当选项数据发生改变时,返回新的标签列表 | [基本用法](#基本用法) | +| update:suggestionList | 当选项数据发生变化时,返回新的可选择标签列表 | [基本用法](#基本用法) | diff --git a/packages/devui-vue/docs/components/tag/index.md b/packages/devui-vue/docs/components/tag/index.md new file mode 100644 index 0000000000000000000000000000000000000000..c96b6238269cb9840a566900ab74031101aada47 --- /dev/null +++ b/packages/devui-vue/docs/components/tag/index.md @@ -0,0 +1,53 @@ +# Tag 标签 + +标签展示组件。 + +## 何时使用 + +用户需要展示多个标签时。 + +## 基本用法 + +:::demo 由`type`属性来选择 tag 的类型,也可以通过`color`属性来自定义背景色 + +```vue +<template> + <d-tag>标签一</d-tag> + <d-tag type="primary">标签二</d-tag> + <d-tag type="success">标签三</d-tag> + <d-tag type="warning">标签四</d-tag> + <d-tag type="danger">标签五</d-tag> +</template> + +<script> +import { defineComponent } from 'vue' + +export default defineComponent({ + setup() { + return { + msg: 'Tag 标签 组件文档示例' + } + } +}) +</script> + +<style></style> +``` + +::: + +## API + +### Props + +| 参数 | 类型 | 默认值 | 说明 | 可选值 | 跳转至 Demo | +| :---: | :------: | :-----: | :----------------: | :------------------------------: | :---------------: | +| type | `string` | defalut | 可选,标签的类型 | `success\|info\|warning\|danger` | [示例](#基本用法) | +| color | `string` | '' | 可选,标签的主题色 | | | + +### Event + +| 名称 | 说明 | +| :------------ | --------------------------------- | +| tagDelete | 删除 tag 的时候触发的事件 | +| checkedChange | tag 的 check 状态改变时触发的事件 | diff --git a/packages/devui-vue/docs/components/textarea/index.md b/packages/devui-vue/docs/components/textarea/index.md new file mode 100644 index 0000000000000000000000000000000000000000..4ab5d3e00c72d612a3976937fe3cd1bab7bfb7c5 --- /dev/null +++ b/packages/devui-vue/docs/components/textarea/index.md @@ -0,0 +1,161 @@ +# Textarea 多行文本框 + +文本输入区域。 + +### 何时使用 + +需要手动输入文字,并且文字内容较多时使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <h4 style="margin: 10px 0">Default</h4> + + <d-textarea + value="我是默认值" + :autofocus="true" + id="textArea" + cssClass="my-text-area" + ></d-textarea> + + <h4 style="margin: 10px 0">Disabled</h4> + + <d-textarea placeholder="我是被禁用状态" :disabled="true"></d-textarea> + + <h4 style="margin: 10px 0">Error</h4> + + <d-textarea placeholder="我是出错状态" :error="true"></d-textarea> +</template> +<style> +.dinput { + width: 200px; +} +</style> +``` + +::: + +### 调整大小 + +:::demo + +```vue +<template> + <h4 style="margin: 10px 0">vertical</h4> + <d-textarea placeholder="我可以缩放" resize="vertical"></d-textarea> + + <h4 style="margin: 10px 0">horizontal</h4> + + <d-textarea resize="horizontal" placeholder="请输入"></d-textarea> + + <h4 style="margin: 10px 0">both</h4> + + <d-textarea resize="both" placeholder="请输入"></d-textarea> + + <h4 style="margin: 10px 0">none</h4> + + <d-textarea resize="none" placeholder="请输入"></d-textarea> + + <h4 style="margin: 10px 0">inherit</h4> + + <d-textarea resize="inherit" placeholder="请输入"></d-textarea> +</template> +``` + +::: + +### 显示字数 + +:::demo + +```vue +<template> + <h4 style="margin: 10px 0">默认</h4> + <d-textarea :showCount="true" placeholder="请输入"></d-textarea> + <h4 style="margin: 10px 0">显示最大字数</h4> + <d-textarea + :showCount="true" + :maxLength="20" + placeholder="请输入" + ></d-textarea> +</template> +<style> +.dinput { + width: 200px; +} +</style> +``` + +::: + +### 事件响应 + +:::demo + +```vue +<template> + <d-textarea + :showCount="true" + :maxLength="20" + placeholder="打开控制台输入文字看看" + @update:value="onUpdate" + @change="onChange" + @focus="onFocus" + @keydown="onKeydown" + ></d-textarea> +</template> +<script> +export default { + setup() { + const onUpdate = (value) => { + console.log("【d-textarea update value】: ", value); + }; + const onChange = (value) => { + console.log("【d-textarea change value】:", value); + }; + const onFocus = (e) => { + console.log("【d-textarea onFocus】:", e); + }; + const onKeydown = (e) => { + console.log("【d-textarea onKeydown:", e); + }; + return { + onUpdate, + onChange, + onFocus, + onKeydown, + }; + }, +}; +</script> +``` + +::: + +### d-textarea API + +d-textarea 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ----------- | --------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------ | --------------------- | ---------- | +| id | string | `-` | 可选,文本框 id | [基本用法](#基本用法) | | +| placeholder | string | `-` | 可选,文本框 placeholder | [基本用法](#基本用法) | | +| value | string | `-` | 可选,文本框默认值 | [基本用法](#基本用法) | | +| disabled | boolean | `false` | 可选,文本框是否被禁用 | [基本用法](#基本用法) | | +| autoFocus | boolean | `false` | 可选,文本框是否自动获得焦点 | [基本用法](#基本用法) | | +| error | boolean | `false` | 可选,文本框是否出现输入错误 | [基本用法](#基本用法) | | +| resize | `'none' \|'vertical' \|'horizontal' \|'both' \|'inherit'` | `'none'` | 可选,文本框是否可调整大小,可选项:不可调整,水平调整,垂直调整,自由调整,默认继承 | [调整大小](#调整大小) | | +| showCount | boolean | `false` | 可选,文本框是否是否展示字数 | [显示字数](#显示字数) | | + +d-textarea 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ------- | ---------------------- | ------------------------------ | --------------------- | +| update | `EventEmitter<string>` | 文本框内容变化(实时触发) | [事件响应](#事件响应) | +| focus | `EventEmitter<Event>` | 文本框获得焦点 | [事件响应](#事件响应) | +| blur | `EventEmitter<Event>` | 文本框失去焦点 | [事件响应](#事件响应) | +| change | `EventEmitter<string>` | 文本框内容变化(失去焦点触发) | [事件响应](#事件响应) | +| keydown | `EventEmitter<Event>` | 文本框按下键盘 | [事件响应](#事件响应) | diff --git a/packages/devui-vue/docs/components/time-axis/index.md b/packages/devui-vue/docs/components/time-axis/index.md new file mode 100644 index 0000000000000000000000000000000000000000..4740b68c2faca51c70c350ac347549b071285473 --- /dev/null +++ b/packages/devui-vue/docs/components/time-axis/index.md @@ -0,0 +1,87 @@ +# TimeAxis 时间轴 + +时间轴展示组件。 + +### 何时使用 + +当需要向用户展示时间进度和每个时间点的事件状态时。 + +### 基本用法 + +通过 direction 配置时间线排列方向,默认值为`vertical`。 +:::demo + +```vue + +<template> + <div> + <d-radio-group css-style="row" v-model="choose"> + <d-radio v-for="item in list" :key="item" :value="item"> + {{ item }} + </d-radio> + </d-radio-group> + <d-time-axis :direction="choose" :data="data"/> + </div> +</template> + +<script> +import {defineComponent, ref} from 'vue' + +export default defineComponent({ + setup() { + const list = ref(['horizontal', 'vertical']) + const choose = ref('horizontal') + const data = ref([ + { + text: 'Download', + time: '2021-07-28' + }, + { + text: 'Check', + time: '2021-07-29', + dotColor: 'var(--devui-success)' + }, + { + text: 'Build', + time: '2021-07-30', + dotColor: 'var(--devui-danger)' + }, + { + text: 'Depoy', + time: '2021-07-31', + dotColor: 'var(--devui-warning)' + }, + { + text: 'End', + time: '2021-08-01', + dotColor: 'var(--devui-waiting)' + } + ]) + return {data, list, choose} + } +}) +</script> + +<style> +</style> +``` + +::: + +### d-time-axis + +d-time-axis 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| ------------ | ---- | ---- | ---- | --------- | +| direction | `'vertical'\|'horizontal'` | `vertical` | 设置时间轴方向 | [基本用法](#基本用法) | +| data | `array` | `[]` | 列表数据(具体参数如下) | [基本用法](#基本用法) | + + +data 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | ---- | ---- | +| time|`string`| -- | 可选,时间 | | +| text |`string` | -- | 可选,文本内容 | | +| dotColor | `string` | -- | 可选,自定义时间圈颜色 | | diff --git a/packages/devui-vue/docs/components/time-picker/index.md b/packages/devui-vue/docs/components/time-picker/index.md new file mode 100644 index 0000000000000000000000000000000000000000..858f7c11c6e1702936dd27c100bf5a8c6a2d39e5 --- /dev/null +++ b/packages/devui-vue/docs/components/time-picker/index.md @@ -0,0 +1,250 @@ +# TimePicker组件 + +时间选择器。 + +### 何时使用 + +当用户需要输入一个时间,可以点击标准输入框,弹出面板进行选择 + +### 基本用法 +:::demo +```vue +<template> + <div> + <h4 class='my-10'>basic</h4> + <d-time-picker placeholder='请选择时间'/> + </div> + <div> + <h4 class='my-10'>default open</h4> + <d-time-picker v-model='vModelValue' :time-picker-width='300' :autoOpen='true'/> + </div> + <div> + <h4 class='my-10'>disabled</h4> + <d-time-picker disabled/> + </div> +</template> + +<script> + import { ref,defineComponent,nextTick } from 'vue' + export default defineComponent({ + setup(props,ctx){ + let vModelValue = ref('12:30:40') + return{ + vModelValue + } + } + }) +</script> + +<style> +.my-10{ margin:10px 0px;} +</style> +``` +::: + +### 时间区间限制 +:::demo +```vue +<template> + <div> + <h4 class='my-10'>minTime</h4> + <d-time-picker min-time='01:04:30'/> + </div> + <div> + <h4 class='my-10'>maxTime</h4> + <d-time-picker max-time='22:30:30' v-model='vModelValues'/> + </div> + <div> + <h4 class='my-10'>maxTime && minTime</h4> + <d-time-picker min-time='02:04:40' max-time='22:30:30' /> + </div> +</template> + +<script> + import { ref,defineComponent,watch } from 'vue' + export default defineComponent({ + setup(props,ctx){ + let vModelValues = ref('23:30:20') + + return{ + vModelValues + } + } + }) +</script> + +``` +::: + +### 格式化 +:::demo +```vue +<template> + <div> + <h4 class='my-10'>hh:mm:ss</h4> + <d-time-picker min-time='01:04:30' /> + </div> + <div> + <h4 class='my-10'>mm:HH:ss</h4> + <d-time-picker format='mm:HH:ss' v-model="vModelValues"/> + </div> + <div> + <h4 class='my-10'>hh:mm</h4> + <d-time-picker format='hh:mm' v-model="vModelValues"/> + </div> + <div> + <h4 class='my-10'>MM:ss</h4> + <d-time-picker format='MM:ss' v-model="vModelValues"/> + </div> +</template> +<script> + import { ref,defineComponent,watch } from 'vue' + export default defineComponent({ + setup(props,ctx){ + let vModelValues = ref('23:30:20') + + watch(vModelValues,(newValue,oldValue)=>{ + console.log(newValue,oldValue) + }) + + return{ + vModelValues + } + } + }) +</script> +``` +::: + +### 传入模板 +:::demo +```vue +<template> + <div> + <h4 class='my-10'>自定义 customViewTemplate</h4> + <d-time-picker ref='slotDemo'> + <template v-slot:customViewTemplate> + <div class='slot-box'> + <div class='slot-bottom' @click='chooseNowFun'>choose now</div> + <div class='slot-bottom' @click='chooseTime' >choose 23:00</div> + </div> + </template> + </d-time-picker> + </div> +</template> + +<script> +import { ref,defineComponent,nextTick } from 'vue' + +export default defineComponent({ + setup(props,ctx){ + let slotDemo = ref(null) + + const chooseTime = ()=>{ + let timeObj ={ + time:'23', + type:'mm' + } + slotDemo.value.chooseTime(timeObj) + } + + // 插槽内方法 -- 选择当前时间 + const chooseNowFun = ()=>{ + let date = new Date() + let hour = date.getHours()>9?date.getHours():'0'+date.getHours() + let minute = date.getMinutes()>9?date.getMinutes():'0'+date.getMinutes() + let second = date.getSeconds()>9?date.getSeconds():'0'+date.getSeconds() + let timeObj = { + time: hour+':'+minute+':'+second + } + slotDemo.value.chooseTime(timeObj) + } + + return{ + chooseNowFun, + chooseTime, + slotDemo + } + } +}) +</script> + +<style> +.slot-box{ + overflow:hidden; + height:100%; +} +.slot-bottom{ + font-size:14px; + cursor: pointer; +} +.slot-bottom:hover{ + color: #7693f5; + text-decoration: underline; +} +</style> +``` +::: + +### 获取数据方式 +:::demo +```vue +<template> + <div> + <h4 class='my-10'>selectedTimeChage</h4> + <d-time-picker @selectedTimeChage='selectedTimeChage'/> + <br> + 当前选中时间:<button @click='getNewTimeFun'>{{time1}}</button> + </div> + <div> + <h4 class='my-10'>v-model</h4> + <d-time-picker v-model='time2'/> + <br> + 当前选中时间:<button @click='getNewTimeFun'>{{time2}}</button> + </div> +</template> + +<script> +import { ref,defineComponent,nextTick } from 'vue' + +export default defineComponent({ + setup(props,ctx){ + let time1 = ref('') + let time2 = ref('') + + // 返回选中的时间 + const selectedTimeChage =(timeValue)=>{ + time1.value = timeValue + } + + return{ + selectedTimeChage, + time1,time2 + } + } +}) +</script> +``` +::: + +### d-time-picker + +d-time-picker 参数 + + +|参数|类型|默认|说明|跳转 Demo| +|----|----|----|----|----| +|disabled| boolean |false|可选,禁用选择|[基本用法](#基本用法) +|timePickerWidth / time-picker-width |number|---| 可选,下拉框的宽度 |[基本用法](#基本用法)| +|autoOpen |boolean|false| 可选,初始化是否直接展开 |[基本用法](#基本用法)| +|format |string|'hh:mm:ss'|可选,传入格式化,控制时间格式|[格式化](#格式限制)| +|minTime / min-time|string|'00:00:00'|可选,限制最小可选时间|[格式化](#时间区间限制)| +|maxTime / max-time|string|'23:59:59'|可选,限制最大可选时间|[格式化](#时间区间限制)| +|customViewTemplate|TemplateRef|--|可选,自定义快捷设置时间或自定义操作区内容|[传入模板](#传入模板)| + +d-time-picker 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +|selectedTimeChange|EventEmitter|可选,确定的时候会发出新激活的子项的数据|[基本用法](#获取数据方式)| + diff --git a/packages/devui-vue/docs/components/toast/index.md b/packages/devui-vue/docs/components/toast/index.md new file mode 100644 index 0000000000000000000000000000000000000000..806f180b8c6ec1c41d053701b6d78acfb3e54962 --- /dev/null +++ b/packages/devui-vue/docs/components/toast/index.md @@ -0,0 +1,502 @@ +# Toast 全局通知 + +全局信息提示组件。 + +### 何时使用 + +当需要向用户全局展示提示信息时使用,显示数秒后消失。 + +### 基本用法 + +common 时不展示图标。 +:::demo + +```vue +<template> + <section class="toast-common-demo"> + <d-toast :value="msgs"> + <template v-slot:customTemplate="msg"> + <a class="devui-link" href="http://devui.huawei.com" target="_blank" + >Back to {{ msg.myInfo }} Home Page</a + > + </template> + </d-toast> + <d-button bsStyle="success" @click.native="showToast('success')" + >Success</d-button + > + <d-button bsStyle="warning" @click.native="showToast('warn')" + >Warn</d-button + > + <d-button bsStyle="danger" @click.native="showToast('error')" + >Error</d-button + > + <d-button bsStyle="primary" @click.native="showToast('multiple')" + >Multiple</d-button + > + <d-button bsStyle="common" @click.native="showToast('link')">link</d-button> + <d-button bsStyle="common" @click.native="showToast('plainText')" + >pure text</d-button + > + <d-button bsStyle="common" @click.native="showToast('common')" + >common</d-button + > + <d-button bsStyle="warning" @click.native="showToast('noTitle')" + >no title</d-button + > + </section> +</template> +<script> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup() { + const msgs = ref([]) + + function showToast(type) { + switch (type) { + case 'link': + msgs.value = [ + { + severity: 'info', + summary: 'Relative', + detail: `<a href="/home" target="_blank">Back to Home Page</a>`, + }, + { + severity: 'info', + summary: 'Absolute', + content: 'slot:customTemplate', + myInfo: 'Devui', + }, + ] + break + case 'multiple': + msgs.value = [ + { + severity: 'info', + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + { + severity: 'info', + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + break + case 'noTitle': + msgs.value = [ + { + severity: 'warn', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + break + case 'plainText': + msgs.value = [ + { + severity: 'info', + content: + 'data:<id:gc5aa71bfd86943db9e3e8f34dc347a15><label:content>', + }, + ] + break + default: + msgs.value = [ + { + severity: type, + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + } + } + + return { + msgs, + showToast, + } + }, +}) +</script> +<style> +.toast-common-demo .devui-btn { + margin-right: 10px; +} +</style> +``` + +::: + +### 超时时间 + +当设置超时时间、没有标题时,则不展示标题和关闭按钮。 +:::demo + +```vue +<template> + <section class="toast-timeout-demo"> + <d-toast :life="5000" :value="msgs2"></d-toast> + <d-button bsStyle="success" @click.native="showToast2('success')" + >Success</d-button + > + <d-button bsStyle="warning" @click.native="showToast2('warn')" + >Warn</d-button + > + <d-button bsStyle="danger" @click.native="showToast2('error')" + >Error</d-button + > + <d-button bsStyle="common" @click.native="showToast2('common')" + >common</d-button + > + </section> +</template> +<script> +import { defineComponent, ref } from 'vue' +export default defineComponent({ + setup() { + const msgs2 = ref([]) + + function showToast2(type) { + switch (type) { + case 'error': + msgs2.value = [ + { + severity: type, + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + break + case 'common': + msgs2.value = [ + { + severity: type, + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + break + default: + msgs2.value = [ + { + severity: type, + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + } + } + + return { + msgs2, + showToast2, + } + }, +}) +</script> +<style> +.toast-timeout-demo .devui-btn { + margin-right: 10px; +} +</style> +``` + +::: + +### 自定义样式 + +:::demo + +```vue +<template> + <section> + <d-toast + :value="msgs3" + :sticky="true" + :style="{ top: '20px' }" + :styleClass="'custom-class'" + ></d-toast> + <d-button bsStyle="common" @click.stop="showToast3()" + >Custom Style</d-button + > + </section> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const msgs3 = ref([]) + + function showToast3() { + msgs3.value = [ + { + severity: 'success', + summary: 'Success', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + } + + return { + msgs3, + showToast3, + } + }, +}) +</script> +<style lang="scss"> +.custom-class { + .devui-toast-item-container { + color: #252b3a; + background-color: #ffffff; + + .devui-toast-icon-close { + top: 10px; + right: 13px; + + & i.icon { + color: #252b3a !important; + } + } + + .devui-toast-image { + top: 15px; + } + + .devui-toast-message { + line-height: 23px; + + .devui-toast-title { + font-size: 16px; + } + + p { + font-size: 14px; + } + } + } +} +</style> +``` + +::: + +### 每个消息使用单独的超时时间 + +当设置超时时间模式为 single 时,每个消息使用自身的 life 作为超时时间,如果未设置则按 severity 判断,severity 也未设置时默认超时时间为 5000 毫秒。 + +:::demo + +```vue +<template> + <section> + <d-toast lifeMode="single" :value="msgs4"></d-toast> + <d-button bsStyle="common" @click.native="showToast4()">Single</d-button> + </section> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const msgs4 = ref([]) + + function showToast4() { + msgs4.value = [ + { + life: 3000, + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + { + life: 6000, + severity: 'info', + summary: 'Summary', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + { + severity: 'success', + summary: 'Success', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + { + severity: 'warn', + summary: 'Warn', + content: + 'This is a test text. This is a test text. This is a test text.', + }, + ] + } + + return { + msgs4, + showToast4, + } + }, +}) +</script> +``` + +::: + +### 服务方式调用 + +使用服务的方式创建 toast 全局通知。 + +:::demo + +```vue +<template> + <div class="toast-service-demo"> + <d-button @click.native="openToast()" + >click me show simplest toast!</d-button + > + <d-button v-if="!isShow" @click.native="openToast2()" bsStyle="common" + >click me show customer toast!</d-button + > + <d-button v-if="isShow" @click.native="closeToast2()" + >click me close customer toast!</d-button + > + <d-button v-if="isShow" @click.native="closeToast3()" bsStyle="common" + >only close first customer toast!</d-button + > + </div> +</template> +<script> +import { defineComponent, ref, h } from 'vue' + +export default defineComponent({ + setup() { + const isShow = ref(false) + const results = ref() + function openToast() { + const results = this.$toastService.open({ + value: [ + { + severity: 'info', + summary: 'summary', + content: () => h('p', 2132131), + }, + ], + }) + console.log('results', results) + } + function openToast2() { + results.value = this.$toastService.open({ + value: [ + { severity: 'info', summary: 'summary', content: '1. I am content' }, + { severity: 'error', summary: 'summary', content: '2. I am content' }, + { severity: 'error', summary: 'summary', content: '3. I am content' }, + ], + sticky: true, + style: { width: '600px', color: 'red' }, + styleClass: 'myCustom-toast', + life: 5000, + lifeMode: 'global', + /* + 接收发射过来的数据 + */ + onCloseEvent(value) { + console.log('closeEvent', value) + }, + onValueChange(value) { + console.log('valueChange', value) + }, + }) + + console.log('results', results.value) + + isShow.value = true + } + + function closeToast2() { + results.value.toastInstance.close() + isShow.value = false + } + + function closeToast3() { + /* + 1.可以根据指定下标关闭 results.value.toastInstance.close(0); + 2.可以根据value对象去关闭,作用跟1是等同的,如下所示: + */ + results.value.toastInstance.close({ + severity: 'info', + summary: 'summary', + content: '1. I am content', + }) + } + + return { + isShow, + openToast, + openToast2, + closeToast2, + closeToast3, + } + }, +}) +</script> +<style> +.toast-service-demo .devui-btn-host { + margin-right: 10px; +} +</style> +``` + +::: + +### Toast Api + +| 参数 | 类型 | 默认 | 说明 | 跳转 | +| :--------- | :--------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | +| value | `Array<Message>` | -- | 必选,消息内容数组,Message 对象定义见下文 | [基本用法](#基本用法) | +| life | `number` | 5000 | 可选,超时时间,超时后自动消失,鼠标悬停可以阻止消失,单位毫秒。普通、成功、提示类默认为 5000 毫秒,错误、警告类默认为 10000 毫秒 | [超时时间](#超时时间) | +| lifeMode | `string` | global | 可选,超时时间模式,预设值为 global 和 single 。默认为 global,所有消息使用 life 或群组第一个消息的预设超时时间; 设置为 single 时, 每个消息使用自身的超时时间,参见 Message 中的 life 定义 | [每个消息使用单独的超时时间](#每个消息使用单独的超时时间) | +| sticky | `boolean` | false | 可选,是否常驻,默认自动关闭 | | +| style | `object` | - | 可选,样式 | [自定义样式](#自定义样式) | +| styleClass | `string` | - | 可选,类名 | [自定义样式](#自定义样式) | + +### Toast Event + +| 参数 | 类型 | 说明 | 跳转 | +| :---------- | :------------------------------ | :--------------------- | :---------------------------- | +| closeEvent | `(message: Message) => void` | 消息关闭回调 | [服务方式调用](#服务方式调用) | +| valueChange | `(messages: Message[]) => void` | 消息关闭后剩余消息回调 | [服务方式调用](#服务方式调用) | + +### 接口 & 类型定义 + +```ts +export interface Message { + severity?: string // 预设值有 common、success、error、warn、info,超时时间参见 life 说明,未设置或非预设值时超时时间为 5000 毫秒,warn 和 error 为 10000 毫秒 + summary?: string // 消息标题。当设置超时时间,未设置标题时,不展示标题和关闭按钮 + detail?: string // 消息内容,推荐使用content替换 + content?: string | `slot:${string}` | (message: Message) => ReturnType<typeof h> // 消息内容,支持纯文本和插槽,推荐使用 + life?: number // 单个消息超时时间,需设置 lifeMode 为 single 。每个消息使用自己的超时时间,开启该模式却未设置时按 severity 判断超时时间 + id?: any // 消息ID +} +``` + +### Service 引入方式 + +```ts +import { ToastService } from 'devui' +``` + +### Service 使用 + +```ts +// 方式 1,局部引入 ToastService +ToastService.open({ xxx }) + +// 方式2,全局属性 +app.config.globalProperties.$toastService.open({ xxx }) +``` diff --git a/packages/devui-vue/docs/components/tooltip/index.md b/packages/devui-vue/docs/components/tooltip/index.md new file mode 100644 index 0000000000000000000000000000000000000000..8ae9d4829c80d14482a1e6a33bcf4676c3dc89f8 --- /dev/null +++ b/packages/devui-vue/docs/components/tooltip/index.md @@ -0,0 +1,81 @@ +# Tooltip 提示 + +文字提示组件。 + +### 何时使用 + +用户鼠标移动到文字上,需要进一步的提示时使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <div class="tooltip-buttons"> + <d-tooltip position="left" content="I am a HTML Element!"> + <d-button btnStyle="common">left</d-button> + </d-tooltip> + <d-tooltip position="top" content="I am a HTML Element!"> + <d-button btnStyle="common">top</d-button> + </d-tooltip> + <d-tooltip position="bottom" content="I am a HTML Element!"> + <d-button btnStyle="common">bottom</d-button> + </d-tooltip> + <d-tooltip position="right" content="I am a HTML Element!"> + <d-button btnStyle="common">right</d-button> + </d-tooltip> + <d-tooltip content="No Animation" :showAnimation="false"> + <d-button btnStyle="common">No Animation</d-button> + </d-tooltip> + </div> +</template> +<style> +.tooltip-buttons { + display: flex; +} +.tooltip-buttons .devui-tooltip { + margin-right: 10px; +} +</style> +``` + +::: + +### 延时触发 + +鼠标移入的时长超过 [mouseEnterDelay] 毫秒之后才会触发,以防止用户无意划过导致的闪现,默认值是 150 毫秒;鼠标移出之后,再经过[mouseLeaveDelay]毫秒后,toolTip 组件才会隐藏,默认值是 100 毫秒。 + +:::demo + +```vue +<template> + <d-tooltip + position="top" + content="Mouse enter 500ms later." + mouseEnterDelay="500" + > + <d-button>MouseEnter delay 500ms</d-button> + </d-tooltip> + <br /> + <d-tooltip + position="top" + content="Mouse leave 1000ms later." + mouseLeaveDelay="1000" + > + <d-button btnStyle="common">MouseEnter delay 1000ms</d-button> + </d-tooltip> +</template> +``` + +::: + +### Tooltip Api + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :-------------: | :----------------------------: | :--------------------------------: | :------------------------------------------------ | --------------------- | ---------- | +| content | `string\|DOMString` | -- | 必选,tooltip 显示内容 | [基本用法](#基本用法) | | +| position | `PositionType\|PositionType[]` | ['top', 'right', 'bottom', 'left'] | 可选,tooltip 显示位置 | [基本用法](#基本用法) | | +| showAnimation | `boolean` | true | 可选,是否显示划出动画 | | ✔ | +| mouseEnterDelay | `number` | 150 | 可选,鼠标移入后延时多少才显示 Tooltip,单位是 ms | [延时触发](#延时触发) | +| mouseLeaveDelay | `number` | 100 | 可选,鼠标移出后延时多少才隐藏 Tooltip,单位是 ms | [延时触发](#延时触发) | diff --git a/packages/devui-vue/docs/components/transfer/index.md b/packages/devui-vue/docs/components/transfer/index.md new file mode 100644 index 0000000000000000000000000000000000000000..304c507fdb23d639a1fadb99f76fc9ae10f38923 --- /dev/null +++ b/packages/devui-vue/docs/components/transfer/index.md @@ -0,0 +1,385 @@ +# Transfer 穿梭框 + +双栏穿梭选择框。 + +### 何时使用 + +需要在多个可选项中进行多选时。穿梭选择框可用只管的方式在两栏中移动数据,完成选择行为。其中左边一栏为 source,右边一栏为 target。最终返回两栏的数据,提供给开发者使用。 + +### 基本用法 + +:::demo + +```vue +<template> + <d-transfer + v-model="options.modelValues" + :titles="options.titles" + :sourceOption="options.source" + :targetOption="options.target" + :isSearch="options.isSearch" + > + </d-transfer> +</template> +<script> +import { defineComponent, reactive } from 'vue' + +export default defineComponent({ + setup() { + const options = reactive({ + titles: ['sourceHeader', 'targetHeader'], + source: [ + { + key: '北京', + value: '北京', + disabled: false, + }, + { + key: '上海', + value: '上海', + disabled: true, + }, + { + key: '广州', + value: '广州', + disabled: false, + }, + { + key: '深圳', + value: '深圳', + disabled: false, + }, + { + key: '成都', + value: '成都', + disabled: false, + }, + { + key: '武汉', + value: '武汉', + disabled: false, + }, + { + key: "西安", + value: "西安", + disabled: false, + }, + { + key: '福建', + value: '福建', + disabled: false, + }, + { + key: '大连', + value: '大连', + disabled: false, + }, + { + key: '重庆', + value: '重庆', + disabled: false, + }, + ], + target: [ + { + key: '南充', + value: '南充', + disabled: false, + }, + { + key: '广元', + value: '广元', + disabled: true, + }, + { + key: '绵阳', + value: '绵阳', + disabled: false, + }, + ], + isSearch: true, + modelValues: ['深圳', '成都', '绵阳'] + }) + + return { + options + } + } +}) +</script> +``` + +::: + +### 自定义穿梭框 + +:::demo + +```vue +<template> + <d-transfer> + <template #left-header> + <div class="custom-transfer__header">Customize Header</div> + </template> + <template #left-body> + <div class="custom-transfer__body"> + <div class="custom-transfer__body__list custom-transfer__body__header"> + <DCheckbox + class="custom-transfer__body__list__checkout" + v-model="leftOptions.allChecked" + @change="changeAllSource(leftOptions)" + ></DCheckbox> + <div class="custom-transfer__body__list__part">Id</div> + <div class="custom-transfer__body__list__part">Name</div> + <div class="custom-transfer__body__list__part">Age</div> + </div> + <DCheckboxGroup v-model="leftOptions.checkedValues"> + <div class="custom-transfer__body__list" v-for="(item, idx) in leftOptions.filterData"> + <DCheckbox + class="devui-transfer__panel__body__list__item" + :value="item.value" + :disabled="item.disabled" + :key="idx"> + </DCheckbox> + <div class="custom-transfer__body__list__part">{{item.key}}</div> + <div class="custom-transfer__body__list__part">{{item.value}}</div> + <div class="custom-transfer__body__list__part">{{item.age}}</div> + </div> + </DCheckboxGroup> + </div> + </template> + <template #operation> + <div class="custom-transfer__operation"> + <div class="custom-transfer__operation__group"> + <DButton :disabled="leftOptions.disabled" @Click="updateRightFilterData" >Left</DButton> + <DButton style="margin-top: 12px;" :disabled="rightOptions.disabled" @click="updateLeftFilterData">Right</DButton> + </div> + </div> + </template> + <template #right-header> + <div class="custom-transfer__header">Customize Header</div> + </template> + <template #right-body> + <div class="custom-transfer__body"> + <div class="custom-transfer__body__list custom-transfer__body__header"> + <DCheckbox + class="custom-transfer__body__list__checkout" + v-model="rightOptions.allChecked" + @change="changeAllSource(rightOptions)" + ></DCheckbox> + <div class="custom-transfer__body__list__part">Id</div> + <div class="custom-transfer__body__list__part">Name</div> + <div class="custom-transfer__body__list__part">Age</div> + </div> + <DCheckboxGroup v-model="rightOptions.checkedValues"> + <div class="custom-transfer__body__list" v-for="(item, idx) in rightOptions.filterData"> + <DCheckbox + class="devui-transfer__panel__body__list__item" + :value="item.value" + :disabled="item.disabled" + :key="idx"> + </DCheckbox> + <div class="custom-transfer__body__list__part">{{item.key}}</div> + <div class="custom-transfer__body__list__part">{{item.value}}</div> + <div class="custom-transfer__body__list__part">{{item.age}}</div> + </div> + </DCheckboxGroup> + </div> + </template> + </d-transfer> +</template> +<script> +import { defineComponent, reactive, watch } from 'vue' + +export default defineComponent({ + setup() { + const leftOptions = reactive({ + allChecked: false, + filterData: [ + { + key: '1', + value: 'Mark', + age: 11, + disabled: false, + }, + { + key: '2', + value: 'Jacob', + age: 12, + disabled: false, + }, + { + key: '3', + value: 'Danni', + age: 13, + disabled: false, + }, + { + key: '4', + value: 'green', + age: 14, + disabled: false, + }, + { + key: '5', + value: 'po', + age: 15, + disabled: false, + }, + { + key: '6', + value: 'Book', + age: 16, + disabled: false, + } + ], + checkedValues: [], + disabled: true, + }); + + const rightOptions = reactive({ + allChecked: false, + filterData: [ + { + key: '21', + value: 'john', + age: 17, + disabled: false, + }, + { + key: '22', + value: 'Joke', + age: 28, + disabled: false, + }, + { + key: '23', + value: 'Echo', + age: 18, + disabled: false, + }, + ], + checkedValues: [], + disabled: true, + }) + + watch( + () => leftOptions.checkedValues, + (nVal) => { + rightOptions.disabled = nVal.length !== 0 ? false : true + leftOptions.allChecked = isEqual(nVal, leftOptions.filterData) + }, + { + deep: true + } + ) + + watch( + () => rightOptions.checkedValues, + (nVal) => { + leftOptions.disabled = nVal.length !== 0 ? false : true + rightOptions.allChecked = isEqual(nVal, rightOptions.filterData) + }, + { + deep: true + } + ) + + const isEqual = (source, target) => { + return target.length !== 0 && source.length === target.length + } + + const changeAllSource = (source) => { + if(source.allChecked) { + source.checkedValues = source.filterData.map(item => item.value) + } else { + source.checkedValues = [] + } + } + + const updateRightFilterData = () => { + rightOptions.filterData = rightOptions.filterData.filter(item => { + let hasItem = rightOptions.checkedValues.includes(item.value) + if(hasItem) { + leftOptions.filterData.push(item) + } + return !hasItem + }) + rightOptions.checkedValues = [] + } + + const updateLeftFilterData = () => { + leftOptions.filterData = leftOptions.filterData.filter(item => { + let hasItem = leftOptions.checkedValues.includes(item.value) + if(hasItem) { + rightOptions.filterData.push(item) + } + return !hasItem + }) + leftOptions.checkedValues = [] + } + + return { + leftOptions, + rightOptions, + changeAllSource, + updateRightFilterData, + updateLeftFilterData + } + } +}) +</script> +<style> +.custom-transfer__header { + height: 40px; + line-height: 40px; + border-bottom: 1px solid #dfe1e6; +} +.custom-transfer__body { + height: calc(100% - 40px); + overflow-y: auto; +} +.custom-transfer__body__list { + display: flex; + justify-content: space-between; + height: 36px; + line-height: 36px; + border-bottom: 1px solid #dfe1e6; +} +.custom-transfer__body__list__part { + width: 30%; + text-align: center; +} +.custom-transfer__body__list__checkout, .custom-transfer__body__list__item { + width: 10%; +} +.custom-transfer__header, .custom-transfer__body__list { + padding: 0 10px; +} +.custom-transfer__operation { + display: flex; + width: 10%; + flex-wrap: wrap; + justify-content: center; + align-items: center; +} +.custom-transfer__operation__group , .custom-transfer__operation__group .devui-btn{ + width: 64px; +} +</style> +``` + +::: + + +### API + +| **参数** | **类型** | **默认** | **说明** | **跳转 Demo** | +| ------------------ | ------------------------------------------------------------ | ------------------------- | ------------------------------------------------------------ | ---------------------------- | +| sourceOption | Array | [] | 可选参数,穿梭框源数据 | [基本用法](#基本用法) | +| targetOption | Array | [] | 可选参数,穿梭框目标数据 | [基本用法](#基本用法) | +| titles | Array | [] | 可选参数,穿梭框标题 | [基本用法](#基本用法) | +| height | string | 320px | 可选参数,穿梭框高度 | [基本用法](#基本用法) | +| isSearch | boolean | true | 可选参数,是否可以搜索 | [基本用法](#基本用法) | +| disabled | boolean | false | 可选参数 穿梭框禁止使用 | [基本用法](#基本用法) | + diff --git a/packages/devui-vue/docs/components/tree-select/index.md b/packages/devui-vue/docs/components/tree-select/index.md new file mode 100644 index 0000000000000000000000000000000000000000..03a6a90407e78c74ecc4972b7b7d71627871c9d5 --- /dev/null +++ b/packages/devui-vue/docs/components/tree-select/index.md @@ -0,0 +1,249 @@ +# TreeSelect 树形选择框 + +一种从列表中选择嵌套结构数据的组件。 + +### 基本用法 + +:::demo + +```vue +<template> + <d-tree-select v-model="value" :treeData="data"></d-tree-select> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const value = ref('') + const data = ref([{ + label: '一级 1', + level: 1, + isOpen: false, + children: [{ + label: '二级 1-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 1-1-1', + level: 3, + }] + }] + }, { + label: '一级 2', + level: 1, + isOpen: false, + children: [{ + label: '二级 2-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-1-1', + level: 3, + }] + }, { + label: '二级 2-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-2-1', + level: 3, + }] + }] + }, { + label: '一级 3', + level: 1, + isOpen: false, + children: [{ + label: '二级 3-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-1-1', + level: 3, + }] + }, { + label: '二级 3-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-2-1', + level: 3, + }] + }] + }]) + + return { + data, + value + } + } +}) +</script> +``` + +::: + +### 禁用 + +:::demo + +```vue +<template> + <d-tree-select v-model="value" :treeData="data" :disabled="true"></d-tree-select> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const value = ref('') + const data = ref([{ + label: '一级 1', + level: 1, + isOpen: false, + children: [{ + label: '二级 1-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 1-1-1', + level: 3, + }] + }] + }, { + label: '一级 2', + level: 1, + isOpen: false, + children: [{ + label: '二级 2-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-1-1', + level: 3, + }] + }, { + label: '二级 2-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-2-1', + level: 3, + }] + }] + }, { + label: '一级 3', + level: 1, + isOpen: false, + children: [{ + label: '二级 3-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-1-1', + level: 3, + }] + }, { + label: '二级 3-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-2-1', + level: 3, + }] + }] + }]) + + return { + data, + value + } + } +}) +</script> +``` + +::: + +### 可清空 + +:::demo + +```vue +<template> + <d-tree-select v-model="value" :treeData="data" :allowClear="true"></d-tree-select> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const value = ref('') + const data = ref([{ + label: '一级 1', + level: 1, + isOpen: false, + children: [{ + label: '二级 1-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 1-1-1', + level: 3, + }] + }] + }, { + label: '一级 2', + level: 1, + isOpen: false, + children: [{ + label: '二级 2-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-1-1', + level: 3, + }] + }, { + label: '二级 2-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 2-2-1', + level: 3, + }] + }] + }, { + label: '一级 3', + level: 1, + isOpen: false, + children: [{ + label: '二级 3-1', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-1-1', + level: 3, + }] + }, { + label: '二级 3-2', + level: 2, + isOpen: false, + children: [{ + label: '三级 3-2-1', + level: 3, + }] + }] + }]) + + return { + data, + value + } + } +}) +</script> +``` + +::: \ No newline at end of file diff --git a/packages/devui-vue/docs/components/tree/index.md b/packages/devui-vue/docs/components/tree/index.md new file mode 100644 index 0000000000000000000000000000000000000000..3251f14788864f4fdd0d6b834c757e800c390137 --- /dev/null +++ b/packages/devui-vue/docs/components/tree/index.md @@ -0,0 +1,741 @@ +# Tree 树 + +一种表现嵌套结构的组件。 + +### 何时使用 + +文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。 + +:::demo + +```vue +<template> + <d-tree :data="data"></d-tree> +</template> +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const data = ref([ + { + label: 'parent node 1 - expanded', + open: true, + disabled: true, + level: 1, + children: [ + { + label: 'parent node 11 - folded', + level: 2, + children: [ + { + label: 'leaf node 111', + level: 3, + }, + { + label: 'leaf node 112', + level: 3, + }, + { + label: 'leaf node 113', + level: 3, + }, + { + label: 'leaf node 114', + level: 3, + } + ] + }, + { + label: 'parent node 12 - folded', + disableToggle: true, + level: 2, + children: [ + { + label: 'leaf node 121', + level: 3, + }, + { + label: 'leaf node 122', + level: 3, + }, + { + label: 'leaf node 123', + level: 3, + }, + { + label: 'leaf node 124', + level: 3, + } + ] + }, + { + id: 'dynamic 12', + label: 'parent node 13 - without children - dynamic loading', + isParent: true, + level: 2, + } + ] + }, + { + label: 'parent node 2 - folded', + level: 1, + children: [ + { + label: 'parent node 21 - expanded', + open: true, + level: 2, + children: [ + { + label: 'leaf node 211', + level: 3, + }, + { + label: 'leaf node 212', + level: 3, + }, + { + label: 'leaf node 213', + level: 3, + }, + { + label: 'leaf node 214', + level: 3, + } + ] + }, + { + label: 'parent node 22 - folded', + level: 2, + children: [ + { + label: 'leaf node 221', + level: 3, + }, + { + label: 'leaf node 222', + level: 3, + }, + { + label: 'leaf node 223', + level: 3, + }, + { + label: 'leaf node 224', + level: 3, + } + ] + }, + { + label: 'parent node 23 - folded', + level: 2, + children: [ + { + label: 'leaf node 231', + level: 3, + }, + { + label: 'leaf node 232', + level: 3, + }, + { + label: 'leaf node 233', + level: 3, + }, + { + label: 'leaf node 234', + level: 3, + } + ] + } + ] + }, + { + id: 'dynamicNode', + label: 'parent node 3 - without children - dynamic loading', + isParent: true, + level: 1, + data: { + id: 'newChildNode', + name: 'new child node' + } + } + ]) + + return { + data + } + } +}) +</script> +``` + +::: + +### 合并节点 + +:::demo 当节点下只有一个子节点时,合并该节点。 + +```vue +<template> + <d-tree :data="data"></d-tree> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + + const data = ref([ + { + label: 'parent node 1', + level: 1, + children: [ + { + label: 'parent node 11', + open: true, + level: 2, + children: [ + { + label: 'parent node 111', + level: 3, + children: [ + { + label: 'parent node 1111', + level: 4, + children: [ + { + label: 'leaf node 11111', + level: 5, + } + ] + } + ] + } + ] + }, + ] + }, + { + label: 'parent node 2', + level: 1, + children: [ + { + label: 'parent node 21', + level: 2, + open: true, + children: [ + { + label: 'leaf node 211', + level: 3, + }, + { + label: 'leaf node 212', + level: 3, + }, + { + label: 'leaf node 213', + level: 3, + }, + { + label: 'leaf node 214', + level: 3, + }, + { + label: 'leaf node 215', + level: 3, + }, + ] + }, + ] + }, + { + label: 'parent node 3', + level: 1, + children: [ + { + label: 'leaf node 31', + level: 2, + children: [ + { + label: 'leaf node 311', + level: 3, + children: [ + { + label: 'leaf node 3111', + level: 4, + } + ] + } + ] + }, + { + label: 'leaf node 32', + level: 2, + }, + { + label: 'leaf node 33', + level: 2, + } + ] + } + ]); + + return { + data + } + } +}) +</script> +``` +::: + +### 自定义图标 + +:::demo 自定义操作按钮图标、节点图标。 + +```vue +<template> + <div style="width: 100%"> + <div class="tree-title"> + <h4>Node</h4> + <h4>Status</h4> + </div> + <d-tree :data="data"> + <template #default="{ node }"> + <span class="my-icon-next"></span> + <span :class="[node?.data?.type && 'my-icon', node?.data?.type]" ></span> + <span class="op-title">{{ node.label }}</span> + <span class="op-status"></span> + <span class="op-icons icon icon-add"></span> + <span class="op-icons icon icon-edit"></span> + <span class="op-icons icon icon-close"></span> + <span class="op-right">{{ node.status }}</span> + </template> + </d-tree> + </div> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + + const data = ref([ + { + label: "parent node 1", + data: { type: "mix" }, + open: true, + status: "status1", + children: [ + { + label: "leaf node 1-1", + data: { type: "mix" }, + open: false, + status: "status1", + children: [ + { + label: "leaf node 1-1-1", + data: { type: "ppt" }, + status: "status2", + }, + { + label: "leaf node 1-1-2", + data: { type: "xls" }, + status: "status2", + }, + ], + }, + { + label: "leaf node 1-2", + data: { type: "mix" }, + open: false, + status: "status1", + children: [ + { + label: "leaf node 1-2-1", + data: { type: "ppt" }, + status: "status2", + }, + { + label: "leaf node 1-2-2", + data: { type: "doc" }, + status: "status2", + }, + ], + }, + ], + }, + { + label: "parent node 2", + data: { type: "ppt" }, + open: false, + status: "status1", + children: [ + { + label: "leaf node 2-1", + data: { type: "ppt" }, + status: "status1", + }, + { + label: "leaf node 2-2", + data: { type: "ppt" }, + status: "status1", + }, + ], + }, + { + label: "parent node 3", + data: { type: "xls" }, + open: false, + status: "status1", + children: [ + { + label: "leaf node 3-1", + data: { type: "xls" }, + status: "status1", + }, + { + label: "leaf node 3-2", + data: { type: "xls" }, + status: "status1", + }, + ], + }, + ]); + + return { + data + } + } +}) +</script> +<style> + +.my-icon::before { + width: 16px; + height: 16px; + font-style: italic; + font-size: 12px; + line-height: 14px; + display: inline-block; + text-align: center; + color: #fff; + border-radius: 2px; +} + +.my-icon.doc::before { + content: 'W'; + background-color: #295396; + border: 1px #224488 solid; +} + +.my-icon.pdf::before { + content: 'A'; + background-color: #da0a0a; + border: 1px #dd0000 solid; +} + +.my-icon.xls::before { + content: 'X'; + background-color: #207044; + border: 1px #18683c solid; +} + +.my-icon.ppt::before { + content: 'P'; + background-color: #d14424; + border: 1px #dd4422 solid; +} + +.my-icon.mix::before { + content: '?'; + font-style: normal; + background-color: #aaaaaa; + border: 1px #999999 solid; +} +.my-icon-next { + margin-left: 8px; +} + +.op-title { + display: flex; + justify-content: space-between; + padding: 0 10px; +} + +.op-icons { + display: inline-block; + margin-left: 8px; + cursor: pointer; + color: #575d6c; + font-size: 16px; +} + +.op-status { + width: 12px; + height: 12px; + border-radius: 50%; + background-color: #50d4ab; +} + +.op-right { + position: absolute; + right: 25px; +} + +.status-position { + position: absolute; + right: 8px; +} + +.tree-title { + display: flex; + justify-content: space-between; + padding-left: 24px; + padding-right: 16px; +} + +.op-icons:focus { + outline: none; +} + +.devui-tree-node__edit { + margin: 0 8px; +} + + +</style> +``` +::: + +### 可勾选树 + +:::demo 可以进行勾选的树。 + +```vue +<template> + <d-tree :data="data" :checkable="true" ></d-tree> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const data = ref([ + { + label: "parent node 1", + }, + { + label: "parent node 2", + open: true, + children: [ + { + label: "leaf node 2-1", + children: [ + { + label: "leaf node 2-1-1", + }, + { + label: "leaf node 2-1-2", + }, + ], + }, + { + label: "leaf node 2-2", + open: true, + children: [ + { + label: "leaf node 2-2-1", + disabled: true, + isChecked: true, + }, + { + label: "leaf node 2-2-2", + disableSelect: true, + }, + ], + }, + ], + }, + { + label: "parent node 3", + disableToggle: true, + children: [ + { + label: "leaf node 3-1", + }, + { + label: "leaf node 3-2", + }, + ], + }, + { + label: "parent node 4", + children: [ + { + label: "leaf node 4-1", + }, + { + label: "leaf node 4-2", + }, + ], + }, + { + label: "parent node 5", + children: [ + { + label: "leaf node 5-1", + }, + { + label: "leaf node 5-2", + }, + ], + }, + ]); + + return { + data, + } + } +}) +</script> +``` +::: + +### 控制父子check关系 + +:::demo 通过 checkableRelation 控制check时父子节点的表现。 + +```vue +<template> + <h6><p>checkableRelation = "both"</p></h6> + <d-tree :data="data" :checkable="true" checkableRelation="both" ></d-tree> + <h6><p>checkableRelation = "upward"</p></h6> + <d-tree :data="data" :checkable="true" checkableRelation="upward" ></d-tree> + <h6><p>checkableRelation = "downward"</p></h6> + <d-tree :data="data" :checkable="true" checkableRelation="downward" ></d-tree> + <h6><p>checkableRelation = "none"</p></h6> + <d-tree :data="data" :checkable="true" checkableRelation="none" ></d-tree> +</template> + +<script> +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const data = ref([ + { + label: 'parent node 1 - expanded', + open: true, + children: [ + { + label: 'parent node 11 - folded', + children: [ + { + label: 'leaf node 111', + }, + { + label: 'leaf node 112', + }, + { + label: 'leaf node 113', + }, + { + label: 'leaf node 114', + }, + ], + }, + { + label: 'parent node 12 - folded', + children: [ + { + label: 'leaf node 121', + }, + { + label: 'leaf node 122', + }, + { + label: 'leaf node 123', + }, + { + label: 'leaf node 124', + }, + ], + }, + { + label: 'parent node 13 - without children', + isparent: true, + }, + ], + }, + { + label: 'parent node 2 - folded', + children: [ + { + label: 'parent node 21 - expanded', + open: true, + children: [ + { + label: 'leaf node 211', + }, + { + label: 'leaf node 212', + }, + { + label: 'leaf node 213', + }, + { + label: 'leaf node 214', + }, + ], + }, + { + label: 'parent node 22 - folded', + children: [ + { + label: 'leaf node 221', + }, + { + label: 'leaf node 222', + }, + { + label: 'leaf node 223', + }, + { + label: 'leaf node 224', + }, + ], + }, + { + label: 'parent node 23 - folded', + children: [ + { + label: 'leaf node 231', + }, + { + label: 'leaf node 232', + }, + { + label: 'leaf node 233', + }, + { + label: 'leaf node 234', + }, + ], + }, + ], + }, + ]); + + return { + data, + } + } +}) +</script> +``` +::: \ No newline at end of file diff --git a/packages/devui-vue/docs/components/upload/index.md b/packages/devui-vue/docs/components/upload/index.md new file mode 100644 index 0000000000000000000000000000000000000000..425c5b82195bad1cd91f6801a141ca36243d0c9e --- /dev/null +++ b/packages/devui-vue/docs/components/upload/index.md @@ -0,0 +1,1284 @@ +# Upload 上传 + +文件上传组件。 + +### 何时使用 + +当需要将文件上传到后端服务器时。 + +### 基本用法 + +单文件上传、拖动文件上传、禁止上传。 + +<h4>Basic Usage</h4> + +:::demo + +```vue +<template> + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'file', + responseType: 'json', + }) + return { + fileOptions, + uploadedFiles, + uploadOptions, + } + }, +} +</script> +``` + +::: + +<h4>Dragdrop</h4> + +:::demo + +```vue +<template> + <d-single-upload + ref="uploadRef" + :enable-drop="true" + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Drag files" + :without-btn="true" + :before-upload="beforeUpload" + @success-event="onSuccess" + @error-event="onError" + @file-drop="fileDrop" + @file-over="fileOver" + /> + <div style="margin-top: 8px"> + <d-button @click="submit">Upload</d-button> + </div> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadRef = ref(null) + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '.png,.zip', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'file', + responseType: 'json', + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + const fileDrop = (files) => { + console.log(files) + } + + const fileOver = (event) => { + console.log(event) + } + const submit = () => { + uploadRef.value.fileUpload() + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + uploadedFiles, + beforeUpload, + onSuccess, + onError, + fileDrop, + fileOver, + uploadRef, + submit, + } + }, +} +</script> +``` + +::: + +<h4>Disabled</h4> + +:::demo + +```vue +<template> + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Upload" + :before-upload="beforeUpload" + @success-event="onSuccess" + @error-event="onError" + :disabled="true" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: '/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'dFile', + withCredentials: true, + responseType: 'json', + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + } + }, +} +</script> +``` + +::: + +### 多文件上传 + +多文件上传,支持拖动文件上传、禁止上传。 + +<h4>Basic Usage</h4> + +:::demo + +```vue +<template> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + @success-event="onSuccess" + @error-event="onError" + :showTip="true" + @file-select="fileSelect" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: 'image/png,image/jpeg', + multiple: true, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + additionalParameter, + maximumSize: 2, + method: 'POST', + checkSameName: true, + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + const fileSelect = (files) => { + console.log('fileSelect ', files) + } + const deleteUploadedFile = (filePath) => { + console.log(`delete ${filePath}`) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + fileSelect, + deleteUploadedFile, + } + }, +} +</script> +``` + +::: + +<h4>Upload Directory</h4> + +:::demo + +```vue +<template> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + @success-event="onSuccess" + @error-event="onError" + :showTip="true" + @file-select="fileSelect" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + multiple: true, + webkitdirectory: true, + }) + const uploadOptions = reactive({ + uri: '/upload', + method: 'post', + maximumSize: 20, + checkSameName: true, + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + const fileSelect = (files) => { + console.log('fileSelect ', files) + } + const deleteUploadedFile = (filePath) => { + console.log(`delete ${filePath}`) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + fileSelect, + deleteUploadedFile, + } + }, +} +</script> +``` + +::: + +<h4>Dragdrop</h4> + +:::demo + +```vue +<template> + <d-multiple-upload + :enable-drop="true" + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + @success-event="onSuccess" + @error-event="onError" + :showTip="true" + @file-select="fileSelect" + :one-time-upload="true" + @file-drop="fileDrop" + @file-over="fileOver" + @delete-uploaded-file-event="deleteUploadedFile" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + multiple: true, + accept: '.xls,.xlsx,.pages,.mp3,.png', + webkitdirectory: true, + }) + const uploadOptions = reactive({ + uri: '/upload', + method: 'post', + additionalParameter: additionalParameter, + maximumSize: 20, + checkSameName: true, + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + const fileSelect = (files) => { + console.log('fileSelect ', files) + } + const deleteUploadedFile = (filePath) => { + console.log(`delete ${filePath}`) + } + const fileDrop = (files) => { + console.log(files) + } + const fileOver = (event) => { + console.log(event) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + fileSelect, + deleteUploadedFile, + fileDrop, + fileOver, + } + }, +} +</script> +``` + +::: + +<h4>Disabled</h4> + +:::demo + +```vue +<template> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Upload" + :before-upload="beforeUpload" + @success-event="onSuccess" + @error-event="onError" + :disabled="true" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: '/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'dFile', + withCredentials: true, + responseType: 'json', + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + } + }, +} +</script> +``` + +::: + +### 自动上传 + +通过 autoUpload 设置自动上传。 + +:::demo + +```vue +<template> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="选择文件" + @success-event="onSuccess1" + @error-event="onError" + @delete-uploaded-file-event="deleteUploadedFile" + :showTip="true" + v-model:uploadedFiles="uploadedFiles" + :auto-upload="true" + /> +</template> +<script> +import { reactive, ref, watch } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + multiple: true, + accept: '.xls,.xlsx,.pages,.mp3,.png', + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + method: 'post', + additionalParameter: additionalParameter, + maximumSize: 20, + checkSameName: true, + }) + const onSuccess1 = (result) => { + console.log('success', result, uploadedFiles) + } + const onError = (error) => { + console.log(error) + } + const deleteUploadedFile = (file) => { + console.log('deleteUploadedFile ', file) + } + watch(uploadedFiles, (val) => { + console.log('uploadedFiles ', val) + }) + return { + fileOptions, + uploadedFiles, + uploadOptions, + onSuccess1, + onError, + deleteUploadedFile, + } + }, +} +</script> +``` + +::: + +### 自定义 + +自定义上传按钮,通过 slot preloadFiles 设置已选择文件列表模板,通过 slot uploadedFiles 设置已上传文件列表模版。 + +:::demo + +```vue +<template> + <div class="upload-row"> + <div class="upload-body"> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="选择文件" + @success-event="onSuccess" + @error-event="onError" + @delete-uploaded-file-event="deleteUploadedFile" + v-model:uploadedFiles="uploadedFiles" + :setCustomUploadOptions="setCustomUploadOptions" + :withoutBtn="true" + ref="uploadRef" + > + <template v-slot:preloadFiles="slotProps"> + <table + class="table preload-files" + v-if="slotProps.fileUploaders.length > 0" + > + <tr + v-for="(fileUploader, index) in slotProps.fileUploaders" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ fileUploader.file.name }}</span> + </td> + + <td width="25%"> + <span v-if="fileUploader.status === UploadStatus.preLoad" + >preLoad</span + > + <span v-if="fileUploader.status === UploadStatus.uploading" + >Uploading}</span + > + <span v-if="fileUploader.status === UploadStatus.uploaded" + >Uploaded</span + > + <span v-if="fileUploader.status === UploadStatus.failed" + >Upload Failed</span + > + </td> + + <td> + <d-button + size="xs" + v-if="fileUploader.status !== UploadStatus.uploaded" + :disabled="fileUploader.status === UploadStatus.uploading" + @click=" + (event) => slotProps.deleteFile(fileUploader.filePath) + " + > + Delete + </d-button> + </td> + </tr> + </table> + </template> + <template v-slot:uploadedFiles="slotProps"> + <table + class="table uploaded-files" + v-if="slotProps.uploadedFiles.length > 0" + > + <tbody> + <tr + v-for="(uploadedFile, index) in slotProps.uploadedFiles" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ uploadedFile.name }}</span> + </td> + <td width="25%"> + <span>Uploaded</span> + </td> + <td> + <d-button + size="xs" + @click="(event) => slotProps.deleteFile(uploadedFile)" + > + Delete + </d-button> + </td> + </tr> + </tbody> + </table> + </template> + </d-multiple-upload> + </div> + <div class="upload-btn"> + <d-button type="primary" @click="submit">自定义上传</d-button> + </div> + </div> +</template> +<script> +import { reactive, ref, watch } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const UploadStatus = ref({ + preLoad: 0, + uploading: 1, + uploaded: 2, + failed: 3, + }) + const uploadRef = ref(null) + const uploadedFiles = ref([]) + const fileOptions = reactive({ + multiple: true, + accept: '.xls,.xlsx,.pages,.mp3,.png', + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + method: 'post', + additionalParameter: additionalParameter, + maximumSize: 20, + checkSameName: true, + }) + const onSuccess = (result) => { + console.log('success', result, uploadedFiles) + } + const onError = (error) => { + console.log(error) + } + const deleteUploadedFile = (file) => { + console.log('deleteUploadedFile ', file) + } + const setCustomUploadOptions = (file, options) => { + let uploadOptions = options + if ( + file.type === + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) { + uploadOptions = { + uri: '/upload', + additionalParameter: additionalParameter, + maximumSize: 0.1, + checkSameName: true, + } + } + if (file.type === 'image/png') { + uploadOptions = { + uri: 'http://localhost:4000/files/upload', + additionalParameter: additionalParameter, + maximumSize: 0.5, + checkSameName: true, + } + } + return uploadOptions + } + const submit = () => { + console.log(uploadRef) + uploadRef.value.fileUpload() + } + watch(uploadedFiles, (val) => { + console.log('uploadedFiles ', val) + }) + return { + fileOptions, + uploadedFiles, + uploadOptions, + onSuccess, + onError, + deleteUploadedFile, + setCustomUploadOptions, + uploadRef, + submit, + UploadStatus, + } + }, +} +</script> +<style> +.upload-row { + display: flex; + align-items: center; + justify-content: space-between; +} +.upload-row .upload-body { + width: 65%; +} +.upload-row .upload-btn { + width: 30%; + align-self: baseline; +} +.upload-row .table { + width: 100%; + max-width: 100%; + margin: 8px 0 0 8px; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} +.upload-row .table .row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 5px; +} +.upload-row .table tr { + border: none; +} +.upload-row .table td { + border: none; + padding: 0; +} +</style> +``` + +::: + +### 动态上传参数 + +用户可通过 beforeUpload 动态修改上传参数。 + +:::demo + +```vue +<template> + <d-multiple-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Upload" + @success-event="onSuccess" + @error-event="onError" + :beforeUpload="beforeUpload" + /> +</template> +<script> +import { reactive, ref } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'file', + responseType: 'json', + }) + const beforeUpload = (files) => { + if (!files || !files.length) { + return + } + files[0].uploadOptions.uri = '/upload2' + console.log(files) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + } + }, +} +</script> +``` + +::: + +### 任意区域上传 + +用户可通过默认 slot 支持文件任意区域上传。 +:::demo + +```vue +<template> + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Upload" + @success-event="onSuccess" + @error-event="onError" + :beforeUpload="beforeUpload" + :showTip="true" + > + <d-button type="primary">选取文件</d-button> + <template v-slot:preloadFiles="slotProps"> + <table + class="table preload-files" + v-if="slotProps.fileUploaders.length > 0" + > + <tr + v-for="(fileUploader, index) in slotProps.fileUploaders" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ fileUploader.file.name }}</span> + </td> + + <td width="25%"> + <span v-if="fileUploader.status === UploadStatus.preLoad" + >preLoad</span + > + <span v-if="fileUploader.status === UploadStatus.uploading" + >Uploading}</span + > + <span v-if="fileUploader.status === UploadStatus.uploaded" + >Uploaded</span + > + <span v-if="fileUploader.status === UploadStatus.failed" + >Upload Failed</span + > + </td> + + <td> + <d-button + size="xs" + v-if="fileUploader.status !== UploadStatus.uploaded" + :disabled="fileUploader.status === UploadStatus.uploading" + @click="(event) => slotProps.deleteFile(event)" + > + Delete + </d-button> + </td> + </tr> + </table> + </template> + <template v-slot:uploadedFiles="slotProps"> + <table + class="table uploaded-files" + v-if="slotProps.uploadedFiles.length > 0" + > + <tbody> + <tr + v-for="(uploadedFile, index) in slotProps.uploadedFiles" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ uploadedFile.name }}</span> + </td> + <td width="25%"> + <span>Uploaded</span> + </td> + <td> + <d-button + size="xs" + @click="(event) => slotProps.deleteFile(uploadedFile)" + > + Delete + </d-button> + </td> + </tr> + </tbody> + </table> + </template> + </d-single-upload> +</template> +<script> +import { reactive, ref, watch } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const UploadStatus = ref({ + preLoad: 0, + uploading: 1, + uploaded: 2, + failed: 3, + }) + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '.png', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'file', + responseType: 'json', + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + watch(uploadedFiles, (newValue, oldValue) => { + console.log('uploadedFiles', { + newValue, + oldValue, + }) + }) + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + UploadStatus, + } + }, +} +</script> +``` + +::: + +自定义默认 slot,初始显示已上传文件。 + +:::demo + +```vue +<template> + <d-single-upload + :file-options="fileOptions" + :upload-options="uploadOptions" + v-model:uploaded-files="uploadedFiles" + placeholder-text="Upload" + @success-event="onSuccess" + @error-event="onError" + :beforeUpload="beforeUpload" + :showTip="true" + :withoutBtn="true" + class="upload-demo" + :autoUpload="true" + > + <div class="upload-trigger"> + <div> + <d-icon name="upload" size="24px" /> + </div> + <div style="marginTop: 20px"> + 将文件拖到此处,或 + <span class="link">点击上传</span> + </div> + </div> + <template v-slot:preloadFiles="slotProps"> + <table + class="table preload-files" + v-if="slotProps.fileUploaders.length > 0" + > + <tr + v-for="(fileUploader, index) in slotProps.fileUploaders" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ fileUploader.file.name }}</span> + </td> + + <td width="25%"> + <span v-if="fileUploader.status === UploadStatus.preLoad" + >preLoad</span + > + <span v-if="fileUploader.status === UploadStatus.uploading" + >Uploading</span + > + <span v-if="fileUploader.status === UploadStatus.uploaded" + >Uploaded</span + > + <span v-if="fileUploader.status === UploadStatus.failed" + >Upload Failed</span + > + </td> + + <td> + <d-button + size="xs" + v-if="fileUploader.status !== UploadStatus.uploaded" + :disabled="fileUploader.status === UploadStatus.uploading" + @click="(event) => slotProps.deleteFile(event)" + > + Delete + </d-button> + </td> + </tr> + </table> + </template> + <template v-slot:uploadedFiles="slotProps"> + <table + class="table uploaded-files" + v-if="slotProps.uploadedFiles.length > 0" + > + <tbody> + <tr + v-for="(uploadedFile, index) in slotProps.uploadedFiles" + :key="index" + class="row" + > + <td width="50%"> + <span>{{ uploadedFile.name }}</span> + </td> + <td width="25%"> + <span>Uploaded</span> + </td> + <td> + <d-button + size="xs" + @click="(event) => slotProps.deleteFile(uploadedFile)" + > + Delete + </d-button> + </td> + </tr> + </tbody> + </table> + </template> + </d-single-upload> +</template> +<script> +import { reactive, ref, watch } from 'vue' + +export default { + setup() { + const additionalParameter = { name: 'tom', age: 11 } + const UploadStatus = ref({ + preLoad: 0, + uploading: 1, + uploaded: 2, + failed: 3, + }) + const uploadedFiles = ref([]) + const fileOptions = reactive({ + accept: '.png', + multiple: false, + webkitdirectory: false, + }) + const uploadOptions = reactive({ + uri: 'http://localhost:4000/files/upload', + headers: {}, + additionalParameter, + maximumSize: 0.5, + method: 'POST', + fileFieldName: 'file', + responseType: 'json', + }) + const beforeUpload = (file) => { + console.log(file) + return true + } + const onSuccess = (result) => { + console.log('success', result) + } + const onError = (error) => { + console.log(error) + } + watch(uploadedFiles, (newValue, oldValue) => { + console.log('uploadedFiles', { + newValue, + oldValue, + }) + }) + return { + fileOptions, + uploadedFiles, + uploadOptions, + beforeUpload, + onSuccess, + onError, + UploadStatus, + } + }, +} +</script> +<style> +.upload-demo .upload-trigger { + background-color: #fff; + border: 1px dashed #d9d9d9; + border-radius: 6px; + box-sizing: border-box; + width: 360px; + height: 180px; + text-align: center; + cursor: pointer; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; + justify-content: center; +} +.upload-demo .upload-trigger .link { + color: blue; +} +</style> +``` + +::: + +### API + +d-single-upload 参数 + +| **参数** | **类型** | **默认** | 说明 | **跳转 Demo** | +| ---------------------- | --------------------------------- | ---------- | ---------------------------------------------------------------------------------------- | --------------------- | +| fileOptions | [IFileOptions](#ifileoptions) | -- | 必选,待上传文件配置 | [基本用法](#基本用法) | +| uploadOptions | [IUploadOptions](#iuploadoptions) | \-- | 必选,上传配置 | [基本用法](#基本用法) | +| autoUpload | `boolean` | false | 可选,是否自动上传 | [基本用法](#基本用法) | +| placeholderText | `string` | '选择文件' | 可选,上传输入框中的 Placeholder 文字 | [基本用法](#基本用法) | +| uploadText | `string` | '上传' | 可选,上传按钮文字 | [基本用法](#基本用法) | +| uploadedFiles | `Array<Object>` | [] | 可选,获取已上传的文件列表 | [基本用法](#基本用法) | +| withoutBtn | `boolean` | false | 可选,是否舍弃按钮 | [基本用法](#基本用法) | +| enableDrop | `boolean` | false | 可选,是否支持拖拽 | [基本用法](#基本用法) | +| beforeUpload | `boolean Promise<boolean> ` | \-- | 可选,上传前的回调,通过返回`true` or `false` ,控制文件是否上传,参数为文件信息及上传配置 | [基本用法](#基本用法) | +| dynamicUploadOptionsFn | [IUploadOptions](#iuploadoptions) | \-- | 为文件动态设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [基本用法](#基本用法) | +| disabled | `boolean` | false | 可选,是否禁用上传组件 | [基本用法](#基本用法) | +| showTip | `boolean` | false | 可选,是否显示上传提示信息 | [自动上传](#自动上传) | + +d-single-upload 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| ----------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------- | +| fileOver | `EventEmitter<boolean>` | 支持拖拽上传时,文件移动到可拖放区域触发事件,可拖动的元素移出放置目标时返回`false`,元素正在拖动到放置目标时返回`true` | [基本用法](#基本用法) | +| fileDrop | `EventEmitter<any>` | 支持拖拽上传时,当前拖拽的文件列表回调,单文件上传默认返回第一个文件 | [基本用法](#基本用法) | +| successEvent | `EventEmitter<Array<{file: File; response: any}>>` | 上传成功时的回调函数,返回文件及 xhr 的响应信息 | [基本用法](#基本用法) | +| errorEvent | `EventEmitter<{file: File; response: any}>` | 上传错误时的回调函数,返回上传失败的错误信息 | [基本用法](#基本用法) | +| deleteUploadedFileEvent | `EventEmitter<string>` | 删除上传文件的回调函数,返回删除文件的路径信息 | [基本用法](#基本用法) | +| fileSelect | `EventEmitter<File>` | 文件选择后的回调函数,返回已选择文件信息 | [基本用法](#基本用法) | + +d-multiple-upload 参数 + +| **参数** | **类型** | **默认** | 说明 | **跳转 Demo** | +| ---------------------- | --------------------------------- | -------------- | ---------------------------------------------------------------------------------------- | ------------------------- | +| fileOptions | [IFileOptions](#ifileoptions) | -- | 必选,待上传文件配置 | [多文件上传](#多文件上传) | +| uploadOptions | [IUploadOptions](#iuploadoptions) | \-- | 必选,上传配置 | [多文件上传](#多文件上传) | +| autoUpload | `boolean` | false | 可选,是否自动上传 | [自动上传](#自动上传) | +| placeholderText | `string` | '选择多个文件' | 可选,上传输入框中的 Placeholder 文字 | [基本用法](#基本用法) | +| uploadText | `string` | '上传' | 可选,上传按钮文字 | [基本用法](#基本用法) | +| uploadedFiles | `Array<Object>` | [] | 可选,获取已上传的文件列表 | [多文件上传](#多文件上传) | +| withoutBtn | `boolean` | false | 可选,是否舍弃按钮 | [自定义](#自定义) | +| enableDrop | `boolean` | false | 可选,是否支持拖拽 | [多文件上传](#多文件上传) | +| beforeUpload | `boolean Promise<boolean>` | \-- | 可选,上传前的回调,通过返回`true` or `false` ,控制文件是否上传,参数为文件信息及上传配置 | [多文件上传](#多文件上传) | +| dynamicUploadOptionsFn | [IUploadOptions](#iuploadoptions) | \-- | 为文件动态设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [多文件上传](#多文件上传) | +| disabled | `boolean` | false | 可选,是否禁用上传组件 | [多文件上传](#多文件上传) | +| showTip | `boolean` | false | 可选,是否显示上传提示信息 | [多文件上传](#多文件上传) | +| setCustomUploadOptions | [IUploadOptions](#iuploadoptions) | -- | 为每个文件设置自定义的上传参数, 参数为当前选中文件及`uploadOptions`的值 | [自定义](#自定义) | + +d-multiple-upload 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| ----------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------- | +| fileOver | `EventEmitter<boolean>` | 支持拖拽上传时,文件移动到可拖放区域触发事件,可拖动的元素移出放置目标时返回`false`,元素正在拖动到放置目标时返回`true` | [多文件上传](#多文件上传) | +| fileDrop | `EventEmitter<any>` | 支持拖拽上传时,当前拖拽的文件列表回调,单文件上传默认返回第一个文件 | [多文件上传](#多文件上传) | +| successEvent | `EventEmitter<Array<{file: File; response: any}>>` | 上传成功时的回调函数,返回文件及 xhr 的响应信息 | [多文件上传](#多文件上传) | +| errorEvent | `EventEmitter<{file: File; response: any}>` | 上传错误时的回调函数,返回上传失败的错误信息 | [多文件上传](#多文件上传) | +| deleteUploadedFileEvent | `EventEmitter<string>` | 删除上传文件的回调函数,返回删除文件的路径信息 | [多文件上传](#多文件上传) | +| fileSelect | `EventEmitter<File>` | 文件选择后的回调函数,返回已选择文件信息 | [多文件上传](#多文件上传) | + +### slot + +| name | 默认 | 说明 | 跳转 Demo | +| ------------- | ---- | ----------------------------------------------------------------------------- | ----------------- | +| preloadFiles | -- | 可选,用于创建自定义 已选择文件列表模板,参数为 `{fileUploaders, deleteFile}` | [自定义](#自定义) | +| uploadedFiles | -- | 可选,用于创建自定义 已上传文件列表模板,参数为 `{uploadedFiles, deleteFile}` | [自定义](#自定义) | + +### 接口 & 类型定义 + +### IUploadOptions + +```typescript +export class IUploadOptions { + // 上传接口地址 + uri: string + // http 请求方法 + method?: string + // 上传文件大小限制 + maximumSize?: number + // 自定义请求headers + headers?: { [key: string]: any } + // 认证token + authToken?: string + // 认证token header标示 + authTokenHeader?: string + // 上传额外自定义参数 + additionalParameter?: { [key: string]: any } + // 上传文件字段名称,默认file + fileFieldName?: string + // 多文件上传,是否检查文件重名,设置为true,重名文件不会覆盖,否则会覆盖上传 + checkSameName?: boolean + // 指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求 + withCredentials?: boolean + // 手动设置返回数据类型 + responseType?: 'arraybuffer' | 'blob' | 'json' | 'text' +} +``` + +### IFileOptions + +```typescript +export class IFileOptions { + // 规定能够通过文件上传进行提交的文件类型,例如 accept: '.xls,.xlsx,.pages,.mp3,.png' + accept?: string + // 输入字段可选择多个值 + multiple?: boolean + // 是否允许用户选择文件目录,而不是文件 + webkitdirectory?: boolean +} +``` diff --git a/packages/devui-vue/docs/index.md b/packages/devui-vue/docs/index.md new file mode 100644 index 0000000000000000000000000000000000000000..f6f46f1cc13da44436fff756e6f2be11f7a4b2c5 --- /dev/null +++ b/packages/devui-vue/docs/index.md @@ -0,0 +1,80 @@ +# 快速开始 + +引导您如何在项目中使用DevUI + +### Vue版本 + +当前支持的Vue版本 ^3.0.0 + +### 1. 创建一个项目 + +推荐使用@vite/cli创建你的项目 + +```shell +yarn create vite my-vue-app --template vue-ts +``` + +### 2. 安装 + +进入你的项目文件夹,使用yarn安装DevUI + +```shell +yarn add vue-devui + +# 可选,字体图标库, 部分Demo依赖此字体库 +# yarn add @devui-design/icons +# main.ts 文件引入 +# import '@devui-design/icons/icomoon/devui-icon.css' +``` + +### 3. 引入模块和样式 + +main.ts + +```js +// 全局引入 +import DevUI from 'vue-devui' +import 'vue-devui/style.css' + +createApp(App).use(DevUI).mount('#app') +``` + +```js +// 按需引入 +// main.ts文件 +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入单个组件 +import { Button } from 'vue-devui' +// or import Button from 'vue-devui/button' +// Step 2: 引入组件样式 +// 方式一:手动引入组件样式 +import 'vue-devui/button/style.css' + +// 方式二:自动按需引入组件 +// vite.config.ts文件 +// import styleImport from 'vite-plugin-style-import' +// plugins: [ +// vue(), +// styleImport({ +// libs: [ +// { +// libraryName: 'vue-devui', +// esModule: true, +// resolveStyle: (name) => `vue-devui/${name}/style`, +// }, +// ], +// }) +// ] + +createApp(App) +.use(Button) // Step 3: 使用组件 +.mount('#app') +``` + +### 4. 启动开发调试 + +```shell +yarn dev +``` \ No newline at end of file diff --git a/packages/devui-vue/docs/vite.config.ts b/packages/devui-vue/docs/vite.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..97e1662381f99ed8571db3abe2d244d1dcd4818b --- /dev/null +++ b/packages/devui-vue/docs/vite.config.ts @@ -0,0 +1,16 @@ +import path from 'path' +import { defineConfig } from 'vite' +import vueJsx from '@vitejs/plugin-vue-jsx' +import svgLoader from 'vite-svg-loader' + +export default defineConfig({ + resolve: { + alias: [ + { find: '@devui', replacement: path.resolve(__dirname, '../devui') }, + ] + }, + plugins: [ + vueJsx({}), + svgLoader(), + ], +}) \ No newline at end of file diff --git a/index.html b/packages/devui-vue/index.html similarity index 100% rename from index.html rename to packages/devui-vue/index.html diff --git a/packages/devui-vue/jest.config.js b/packages/devui-vue/jest.config.js new file mode 100644 index 0000000000000000000000000000000000000000..fb480498a9a4fbc5dd7b770fe650a92c1b23b9d5 --- /dev/null +++ b/packages/devui-vue/jest.config.js @@ -0,0 +1,37 @@ +module.exports = { + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // A map from regular expressions to paths to transformers + transform: { + '^.+\\.(ts|tsx|js|jsx)$': [ + 'babel-jest', + { + presets: [ + ['@babel/preset-env', { targets: { node: 'current' } }], + ['@babel/preset-typescript'], + ], + plugins: ['@vue/babel-plugin-jsx'], + }, + ], + }, + transformIgnorePatterns: ['node_modules/?!(lodash-es)'], + // The glob patterns Jest uses to detect test files + testMatch: ['**/**/*.spec.(ts|tsx)'], + + // An array of file extensions your modules use + moduleFileExtensions: ['js', 'json', 'ts', 'tsx'], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + moduleNameMapper: { + '\\.(css|less|scss|sass)$': '<rootDir>/__mocks__/style-mock.ts', + '\\.(gif|ttf|eot|svg|jpg|png)$': '<rootDir>/__mocks__/file-mock.ts', + }, + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + testPathIgnorePatterns: ['/node_modules/'], + + // The test environment that will be used for testing + testEnvironment: 'jest-environment-jsdom', + setupFiles: ['<rootDir>/jest.setup.js'], +} diff --git a/packages/devui-vue/jest.setup.js b/packages/devui-vue/jest.setup.js new file mode 100644 index 0000000000000000000000000000000000000000..88b32b6bfce791bbb17b96c726429ccafc482c05 --- /dev/null +++ b/packages/devui-vue/jest.setup.js @@ -0,0 +1,14 @@ +import { config } from '@vue/test-utils' +import Icon from './devui/icon/src/icon' +import Button from './devui/button/src/button' +import Progress from './devui/progress/src/progress' +import fileDropDirective from './devui/upload/src/file-drop-directive' +config.global.components = { + 'd-icon': Icon, + 'd-button': Button, + 'd-progress': Progress, +} + +config.global.directives = { + FileDrop: fileDropDirective, +} diff --git a/packages/devui-vue/package.json b/packages/devui-vue/package.json new file mode 100644 index 0000000000000000000000000000000000000000..46bc909102f149df661a2032339db2de7cf69ff2 --- /dev/null +++ b/packages/devui-vue/package.json @@ -0,0 +1,112 @@ +{ + "name": "vue-devui", + "version": "0.0.1", + "license": "MIT", + "description": "DevUI components based on Vite and Vue3", + "keywords": [ + "frontend", + "typescript", + "ui-component", + "components", + "vue-components", + "vue", + "vue3", + "vite", + "jsx", + "devui" + ], + "main": "vue-devui.umd.js", + "module": "vue-devui.es.js", + "style": "style.css", + "bin": { + "devui-cli": "./devui-cli/index.js" + }, + "scripts": { + "dev": "yarn generate:theme && vitepress dev docs", + "build": "yarn generate:theme && vitepress build docs && cp public/* docs/.vitepress/dist/assets", + "serve": "vitepress serve docs", + "app:dev": "vite", + "app:build": "vite build", + "build:lib": "yarn predev && yarn build:components && yarn generate:theme && yarn copy", + "test": "jest --config jest.config.js", + "ls-lint": "ls-lint", + "lint": "eslint \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", + "lint:fix": "eslint --fix \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", + "stylelint": "stylelint --fix \"{devui,src}/**/*.{scss,css}\"", + "build:components": "node ./devui-cli/index.js build", + "generate:theme": "node ./devui-cli/index.js generate:theme", + "copy": "cp package.json build && cp README.md build && cp devui/theme/theme.scss build/theme", + "clean:cli": "npm uninstall -g devui-cli & npm uninstall -g vue-devui", + "cli:create": "node ./devui-cli/index.js create -t component", + "predev": "node ./devui-cli/index.js create -t vue-devui --ignore-parse-error", + "prebuild": "node ./devui-cli/index.js create -t vue-devui --ignore-parse-error" + }, + "dependencies": { + "@devui-design/icons": "^1.3.0", + "@types/lodash-es": "^4.17.4", + "async-validator": "^4.0.2", + "lodash-es": "^4.17.20", + "mitt": "^3.0.0", + "vue": "^3.1.1", + "vue-router": "^4.0.3" + }, + "devDependencies": { + "@babel/parser": "^7.15.5", + "@babel/preset-env": "^7.14.5", + "@babel/preset-typescript": "^7.14.5", + "@babel/traverse": "^7.15.4", + "@commitlint/cli": "^11.0.0", + "@commitlint/config-conventional": "^11.0.0", + "@ls-lint/ls-lint": "^1.10.0", + "@types/chalk": "^2.2.0", + "@types/commander": "^2.12.2", + "@types/jest": "^26.0.23", + "@types/ora": "^3.2.0", + "@typescript-eslint/eslint-plugin": "^4.27.0", + "@typescript-eslint/parser": "^4.27.0", + "@vitejs/plugin-vue": "^1.3.0", + "@vitejs/plugin-vue-jsx": "^1.1.0", + "@vue/babel-plugin-jsx": "^1.0.6", + "@vue/compiler-sfc": "^3.0.5", + "@vue/test-utils": "^2.0.0-rc.9", + "@vuedx/typecheck": "^0.4.1", + "@vuedx/typescript-plugin-vue": "^0.4.1", + "babel-jest": "^27.0.2", + "chalk": "^4.1.2", + "commander": "^8.1.0", + "esbuild-register": "^2.6.0", + "eslint": "^7.28.0", + "eslint-plugin-import": "^2.24.2", + "eslint-plugin-vue": "^7.11.1", + "husky": "^4.3.7", + "inquirer": "^8.1.2", + "jest": "^27.0.4", + "lint-staged": "^11.0.0", + "ora": "^5.4.1", + "patch-vue-directive-ssr": "^0.0.1", + "sass": "^1.32.2", + "shelljs": "^0.8.4", + "stylelint": "^13.13.1", + "stylelint-config-recommended-scss": "^4.3.0", + "stylelint-config-standard": "^22.0.0", + "stylelint-scss": "^3.20.1", + "typescript": "^4.3.2", + "vite": "^2.4.4", + "vite-plugin-md": "^0.6.0", + "vite-svg-loader": "^2.2.0", + "vitepress": "0.20.1", + "vitepress-theme-demoblock": "1.3.2", + "vue-tsc": "^0.2.2", + "yarn": "^1.22.11" + }, + "husky": { + "hooks": { + "pre-commit": "ls-lint && lint-staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "lint-staged": { + "{src,devui}/**/*.{js,ts,jsx,tsx,vue}": "eslint --fix", + "{src,devui}/**/*.{scss,css}": "stylelint --fix" + } +} diff --git a/public/favicon.ico b/packages/devui-vue/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to packages/devui-vue/public/favicon.ico diff --git a/packages/devui-vue/public/logo.svg b/packages/devui-vue/public/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..31fed46a6872e56683a387bf2eaf1953684c2f63 --- /dev/null +++ b/packages/devui-vue/public/logo.svg @@ -0,0 +1,30 @@ +<svg width="80px" height="80px" viewBox="0 0 26 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient x1="89.5364583%" y1="21.60078%" x2="7.57349918%" y2="65.7395747%" id="linearGradient-1"> + <stop stop-color="#2954C8" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="89.5364583%" y1="21.4573588%" x2="7.57349918%" y2="65.8190624%" id="linearGradient-2"> + <stop stop-color="#2954C8" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="-11.5260417%" y1="24.3907324%" x2="87.1145833%" y2="74.8850926%" id="linearGradient-3"> + <stop stop-color="#89D2FF" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="0%" y1="18.4813953%" x2="75.9513522%" y2="81.5186047%" id="linearGradient-4"> + <stop stop-color="#89D2FF" offset="0%"></stop> + <stop stop-color="#5170FF" offset="100%"></stop> + </linearGradient> + </defs> + <g id="Devui-Logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Group-2" transform="translate(3.000000, 0.000000)"> + <g> + <path d="M4.28576801,9.22873192 L9.32098286,6.02205882 L13.1143389,8.49673203 L0.010890596,17.0193525 L0.010890596,17.0193525 C0.010890596,13.8625823 1.62310848,10.9244448 4.28576801,9.22873192 Z" id="Path-39-Copy-3" fill="url(#linearGradient-1)"></path> + <path d="M8.76945593,17.4828869 L14.1939212,14.0196078 L18.2867527,16.6963836 L4.14882163,25.9150327 L4.14882163,25.9150327 C4.14882163,22.4998846 5.89095741,19.3206798 8.76945593,17.4828869 Z" id="Path-39-Copy-2" fill="url(#linearGradient-2)" transform="translate(11.217787, 19.967320) scale(-1, 1) translate(-11.217787, -19.967320) "></path> + <path d="M0.183304389,2.48689958e-13 L13.1143389,8.49673203 L9.42310099,10.9017055 L9.42310099,10.9017055 C4.36778167,11.0371959 0.159798979,7.04888649 0.0243085926,1.99356717 C0.00937841938,1.43650334 0.0453320846,0.879239543 0.13172203,0.32871271 L0.183304389,2.48689958e-13 Z" id="Path-38-Copy-3" fill="url(#linearGradient-3)"></path> + <path d="M4.54131151,6.55708742 L19.8945577,16.6535948 L16.2033199,19.0585682 L11.1830136,17.9470593 C6.34348625,16.8755752 3.2888836,12.0837536 4.36036765,7.24422626 C4.41158805,7.01288123 4.47194996,6.78365535 4.54131151,6.55708742 L4.54131151,6.55708742 Z" id="Path-38-Copy-2" fill="url(#linearGradient-4)" transform="translate(12.021690, 12.807828) scale(-1, 1) translate(-12.021690, -12.807828) "></path> + </g> + </g> + </g> +</svg> \ No newline at end of file diff --git a/packages/devui-vue/src/app.vue b/packages/devui-vue/src/app.vue new file mode 100644 index 0000000000000000000000000000000000000000..76ccddf536fbf4e584fccc3c8b392789d0c2ce8c --- /dev/null +++ b/packages/devui-vue/src/app.vue @@ -0,0 +1,22 @@ +<template> + Vue DevUI +</template> + +<script lang="ts"> +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'App', +}) +</script> + +<style> +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; + margin-top: 60px; +} +</style> diff --git a/src/assets/logo.png b/packages/devui-vue/src/assets/logo.png similarity index 100% rename from src/assets/logo.png rename to packages/devui-vue/src/assets/logo.png diff --git a/packages/devui-vue/src/main.ts b/packages/devui-vue/src/main.ts new file mode 100644 index 0000000000000000000000000000000000000000..01433bca2ac76590c48fabfee8d69d7b223f48bb --- /dev/null +++ b/packages/devui-vue/src/main.ts @@ -0,0 +1,4 @@ +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/tsconfig.json b/packages/devui-vue/tsconfig.json similarity index 59% rename from tsconfig.json rename to packages/devui-vue/tsconfig.json index 8c7115f961a575290ddd638ea5b6ae6aa716d3fc..06b8e9827a2207c55b1a94ca9d8b7e061601d04c 100644 --- a/tsconfig.json +++ b/packages/devui-vue/tsconfig.json @@ -7,8 +7,12 @@ "jsx": "preserve", "sourceMap": true, "lib": ["esnext", "dom"], - "types": ["vite/client"], - "plugins": [{ "name": "@vuedx/typescript-plugin-vue" }] + "types": ["vite/client", "jest"], + "esModuleInterop": true, + "plugins": [{ "name": "@vuedx/typescript-plugin-vue" }], + "paths": { + "hooks/*": ["./devui/shared/hooks/*"] + } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] } diff --git a/packages/devui-vue/vite.config.build.ts b/packages/devui-vue/vite.config.build.ts new file mode 100644 index 0000000000000000000000000000000000000000..2605d49cf7246b3d8b9ab9ac755349d22e8f6d5e --- /dev/null +++ b/packages/devui-vue/vite.config.build.ts @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx'; +import markdown from 'vite-plugin-md'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue({ + include: [/\.vue$/, /\.md$/], + }), + vueJsx({}), + markdown() + ], + build: { + rollupOptions: { + // 请确保外部化那些你的库中不需要的依赖 + external: ['vue', 'vue-router'], + output: { + // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 + globals: { + vue: 'Vue' + } + } + }, + lib: { + entry: 'devui/vue-devui.ts', + name: 'vue-devui', + fileName: 'vue-devui', + formats: ['es', 'umd'] + } + } +}) diff --git a/vite.config.ts b/packages/devui-vue/vite.config.ts similarity index 63% rename from vite.config.ts rename to packages/devui-vue/vite.config.ts index dbcb0a70060b8d3d1026d41c2f5407e7b342d538..b563baa2e843d4df270c699cb69482ad0e92f45c 100644 --- a/vite.config.ts +++ b/packages/devui-vue/vite.config.ts @@ -2,8 +2,13 @@ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; import markdown from 'vite-plugin-md'; +import path from 'path'; export default defineConfig({ + server: { + port: 2021, + open: '/', + }, plugins: [ vue({ include: [/\.vue$/, /\.md$/], @@ -11,4 +16,9 @@ export default defineConfig({ vueJsx({}), markdown() ], + resolve: { + alias: { + 'hooks': path.resolve(__dirname, './devui/shared/hooks') + } + } }) diff --git a/packages/devui-vue/yarn.lock b/packages/devui-vue/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..fac69aac295d18c3c0830d2d5e12a6a13739a81b --- /dev/null +++ b/packages/devui-vue/yarn.lock @@ -0,0 +1,7902 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@algolia/cache-browser-local-storage@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/cache-browser-local-storage/download/@algolia/cache-browser-local-storage-4.10.5.tgz?cache=0&sync_timestamp=1629981112983&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Fcache-browser-local-storage%2Fdownload%2F%40algolia%2Fcache-browser-local-storage-4.10.5.tgz#961cf07cf59955de17af13bd74f7806bd2119553" + integrity sha1-lhzwfPWZVd4XrxO9dPeAa9IRlVM= + dependencies: + "@algolia/cache-common" "4.10.5" + +"@algolia/cache-common@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/cache-common/download/@algolia/cache-common-4.10.5.tgz?cache=0&sync_timestamp=1629981110619&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Fcache-common%2Fdownload%2F%40algolia%2Fcache-common-4.10.5.tgz#9510419e9dfb6d8814582c6b20615196f213a9d6" + integrity sha1-lRBBnp37bYgUWCxrIGFRlvITqdY= + +"@algolia/cache-in-memory@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/cache-in-memory/download/@algolia/cache-in-memory-4.10.5.tgz?cache=0&sync_timestamp=1629981102941&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Fcache-in-memory%2Fdownload%2F%40algolia%2Fcache-in-memory-4.10.5.tgz#de9331cb86734bf7f7624063cdaa639e43509be1" + integrity sha1-3pMxy4ZzS/f3YkBjzapjnkNQm+E= + dependencies: + "@algolia/cache-common" "4.10.5" + +"@algolia/client-account@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/client-account/download/@algolia/client-account-4.10.5.tgz#82f7c330fc5f0625b5b559afe9c6b1aa6722b6cf" + integrity sha1-gvfDMPxfBiW1tVmv6caxqmcits8= + dependencies: + "@algolia/client-common" "4.10.5" + "@algolia/client-search" "4.10.5" + "@algolia/transporter" "4.10.5" + +"@algolia/client-analytics@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/client-analytics/download/@algolia/client-analytics-4.10.5.tgz#269e47c9de7e53e9e05e4a2d3c380607c3d2631f" + integrity sha1-Jp5Hyd5+U+ngXkotPDgGB8PSYx8= + dependencies: + "@algolia/client-common" "4.10.5" + "@algolia/client-search" "4.10.5" + "@algolia/requester-common" "4.10.5" + "@algolia/transporter" "4.10.5" + +"@algolia/client-common@4.10.5": + version "4.10.5" + resolved "https://registry.npmmirror.com/@algolia/client-common/download/@algolia/client-common-4.10.5.tgz#a7d0833796a9a2da68be16be76b6dc3962bf2f18" + integrity sha1-p9CDN5apotpovha+drbcOWK/Lxg= + dependencies: + "@algolia/requester-common" "4.10.5" + "@algolia/transporter" "4.10.5" + +"@algolia/client-personalization@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/client-personalization/download/@algolia/client-personalization-4.10.5.tgz?cache=0&sync_timestamp=1629981113134&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Fclient-personalization%2Fdownload%2F%40algolia%2Fclient-personalization-4.10.5.tgz#78a8fb8161bdbeaa66b400b3283640ef689e155b" + integrity sha1-eKj7gWG9vqpmtACzKDZA72ieFVs= + dependencies: + "@algolia/client-common" "4.10.5" + "@algolia/requester-common" "4.10.5" + "@algolia/transporter" "4.10.5" + +"@algolia/client-search@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/client-search/download/@algolia/client-search-4.10.5.tgz?cache=0&sync_timestamp=1629981114060&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Fclient-search%2Fdownload%2F%40algolia%2Fclient-search-4.10.5.tgz#47907232a3e4ecf2aa4459b8de17242afd88147c" + integrity sha1-R5ByMqPk7PKqRFm43hckKv2IFHw= + dependencies: + "@algolia/client-common" "4.10.5" + "@algolia/requester-common" "4.10.5" + "@algolia/transporter" "4.10.5" + +"@algolia/logger-common@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/logger-common/download/@algolia/logger-common-4.10.5.tgz?cache=0&sync_timestamp=1629981114402&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Flogger-common%2Fdownload%2F%40algolia%2Flogger-common-4.10.5.tgz#cf807107e755ad4a72c5afc787e968ff1196f1cc" + integrity sha1-z4BxB+dVrUpyxa/Hh+lo/xGW8cw= + +"@algolia/logger-console@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/logger-console/download/@algolia/logger-console-4.10.5.tgz?cache=0&sync_timestamp=1629981114990&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Flogger-console%2Fdownload%2F%40algolia%2Flogger-console-4.10.5.tgz#f961a7a7c6718c3f3842fb9b522d47b03b9df8ad" + integrity sha1-+WGnp8ZxjD84QvubUi1HsDud+K0= + dependencies: + "@algolia/logger-common" "4.10.5" + +"@algolia/requester-browser-xhr@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/requester-browser-xhr/download/@algolia/requester-browser-xhr-4.10.5.tgz?cache=0&sync_timestamp=1629981115612&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Frequester-browser-xhr%2Fdownload%2F%40algolia%2Frequester-browser-xhr-4.10.5.tgz#7063e3bc6d9c72bc535e1794352eddf47459dfe6" + integrity sha1-cGPjvG2ccrxTXheUNS7d9HRZ3+Y= + dependencies: + "@algolia/requester-common" "4.10.5" + +"@algolia/requester-common@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/requester-common/download/@algolia/requester-common-4.10.5.tgz?cache=0&sync_timestamp=1629981115793&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Frequester-common%2Fdownload%2F%40algolia%2Frequester-common-4.10.5.tgz#52abfbf10b743d26afd3ce20f62771bc393ff4f0" + integrity sha1-Uqv78Qt0PSav084g9idxvDk/9PA= + +"@algolia/requester-node-http@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/requester-node-http/download/@algolia/requester-node-http-4.10.5.tgz?cache=0&sync_timestamp=1629981115971&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Frequester-node-http%2Fdownload%2F%40algolia%2Frequester-node-http-4.10.5.tgz#db7e9ece1fda1b71a28c8e623666aaa096320b5c" + integrity sha1-236ezh/aG3GijI5iNmaqoJYyC1w= + dependencies: + "@algolia/requester-common" "4.10.5" + +"@algolia/transporter@4.10.5": + version "4.10.5" + resolved "https://registry.nlark.com/@algolia/transporter/download/@algolia/transporter-4.10.5.tgz?cache=0&sync_timestamp=1629981116157&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40algolia%2Ftransporter%2Fdownload%2F%40algolia%2Ftransporter-4.10.5.tgz#9354989f12af3e2ce7d3109a94f519d467a960e0" + integrity sha1-k1SYnxKvPizn0xCalPUZ1GepYOA= + dependencies: + "@algolia/cache-common" "4.10.5" + "@algolia/logger-common" "4.10.5" + "@algolia/requester-common" "4.10.5" + +"@arr/every@^1.0.0": + version "1.0.1" + resolved "https://registry.npm.taobao.org/@arr/every/download/@arr/every-1.0.1.tgz#22fe1f8e6355beca6c7c7bde965eb15cf994387b" + integrity sha1-Iv4fjmNVvspsfHvell6xXPmUOHs= + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha1-9K1DWqJj25NbjxDyxVLSP7cWpj8= + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.15.8": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.15.8.tgz#45990c47adadb00c03677baa89221f7cc23d2503" + integrity sha1-RZkMR62tsAwDZ3uqiSIffMI9JQM= + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.nlark.com/@babel/compat-data/download/@babel/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha1-Lbr4uFM0eWyvuw9Xk6kKL8AQsXY= + +"@babel/core@>=7.9.0", "@babel/core@^7.1.0", "@babel/core@^7.15.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/core/download/@babel/core-7.15.8.tgz#195b9f2bffe995d2c6c159e72fe525b4114e8c10" + integrity sha1-GVufK//pldLGwVnnL+UltBFOjBA= + dependencies: + "@babel/code-frame" "^7.15.8" + "@babel/generator" "^7.15.8" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.8" + "@babel/helpers" "^7.15.4" + "@babel/parser" "^7.15.8" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.12.1", "@babel/generator@^7.15.4", "@babel/generator@^7.15.8", "@babel/generator@^7.7.2": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/generator/download/@babel/generator-7.15.8.tgz#fa56be6b596952ceb231048cf84ee499a19c0cd1" + integrity sha1-+la+a1lpUs6yMQSM+E7kmaGcDNE= + dependencies: + "@babel/types" "^7.15.6" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" + integrity sha1-PQ5DsAxeSf22xX5CFgGnpljV+DU= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-builder-binary-assignment-operator-visitor/download/@babel/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz#21ad815f609b84ee0e3058676c33cf6d1670525f" + integrity sha1-Ia2BX2CbhO4OMFhnbDPPbRZwUl8= + dependencies: + "@babel/helper-explode-assignable-expression" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" + integrity sha1-z22U8w++/BORI+J91rAvZa7tt7k= + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" + integrity sha1-f5d8F70SpfujY8sZvqCQOUvzfS4= + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + +"@babel/helper-create-regexp-features-plugin@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/helper-create-regexp-features-plugin/download/@babel/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" + integrity sha1-x9WsXpz2IcJgV3Ivt6ikxYiTWMQ= + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2": + version "0.2.3" + resolved "https://registry.nlark.com/@babel/helper-define-polyfill-provider/download/@babel/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" + integrity sha1-BSXt7FCUZTooJojTTYRuTHXpwLY= + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.15.4.tgz#f9aec9d219f271eaf92b9f561598ca6b2682600c" + integrity sha1-+a7J0hnycer5K59WFZjKayaCYAw= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.14.5", "@babel/helper-function-name@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-function-name/download/@babel/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" + integrity sha1-hFdE2vxDgaSl+2r6bD02+Yp4frw= + dependencies: + "@babel/helper-get-function-arity" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-get-function-arity@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" + integrity sha1-CYgYk0oTf854tTaj4BWGS+Hih5s= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-hoist-variables@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" + integrity sha1-CZk6MlnA6Rj5nRBCYd/fwDPxeN8= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-member-expression-to-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" + integrity sha1-v9NNybupgkpGWLAxfsL9VxpR5u8= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-module-imports/download/@babel/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" + integrity sha1-4YAH0jBjLeoZtHhTuYRHbntOED8= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4", "@babel/helper-module-transforms@^7.15.8": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.15.8.tgz#d8c0e75a87a52e374a8f25f855174786a09498b2" + integrity sha1-2MDnWoelLjdKjyX4VRdHhqCUmLI= + dependencies: + "@babel/helper-module-imports" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-simple-access" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" + +"@babel/helper-optimise-call-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" + integrity sha1-8xClEho7nMUtmrGRIr1ymCLe4XE= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha1-WsgizpfuxGdBq3ClF5ceRDpwxak= + +"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f" + integrity sha1-JjfAcx5MkPv1isWLULK1oZL8lw8= + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-wrap-function" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" + integrity sha1-UqirJrqRjH9t7ihiiwcHGse3NHo= + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-simple-access@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-simple-access/download/@babel/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" + integrity sha1-rDaJBavx3o6XgUNLY12PhnS8wTs= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-skip-transparent-expression-wrappers@^7.14.5", "@babel/helper-skip-transparent-expression-wrappers@^7.15.4": + version "7.15.4" + resolved "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/download/@babel/helper-skip-transparent-expression-wrappers-7.15.4.tgz#707dbdba1f4ad0fa34f9114fc8197aec7d5da2eb" + integrity sha1-cH29uh9K0Po0+RFPyBl67H1dous= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" + integrity sha1-rsq5Lc2+9qEKo7YqsgSwhfd24lc= + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.nlark.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha1-Ig35k7/pBKSmsCq08zhaXr9uI4k= + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/helper-validator-option/download/@babel/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha1-bnKh//GNXfy4eOHmLxoCHEty1aM= + +"@babel/helper-wrap-function@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.15.4.tgz#6f754b2446cfaf3d612523e6ab8d79c27c3a3de7" + integrity sha1-b3VLJEbPrz1hJSPmq415wnw6Pec= + dependencies: + "@babel/helper-function-name" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helpers@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/helpers/download/@babel/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" + integrity sha1-X0DwIFCjAnEho89I1JfAXFVer0M= + dependencies: + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/highlight/download/@babel/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha1-aGGlLwOWZAUAH2qlNKAaJNmejNk= + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@7.12.3": + version "7.12.3" + resolved "https://registry.npmmirror.com/@babel/parser/download/@babel/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" + integrity sha1-owVBXr56bHAjtAtRIqBmLZKDNM0= + +"@babel/parser@^7.1.0", "@babel/parser@^7.12.1", "@babel/parser@^7.12.3", "@babel/parser@^7.15.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.15.8", "@babel/parser@^7.6.0", "@babel/parser@^7.7.2", "@babel/parser@^7.9.6": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/parser/download/@babel/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" + integrity sha1-e6zcvnG9w/+TbVEMFdzqfPC5kBY= + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/download/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz#dbdeabb1e80f622d9f0b583efb2999605e0a567e" + integrity sha1-296rsegPYi2fC1g++ymZYF4KVn4= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + +"@babel/plugin-proposal-async-generator-functions@^7.15.8": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/plugin-proposal-async-generator-functions/download/@babel/plugin-proposal-async-generator-functions-7.15.8.tgz#a3100f785fab4357987c4223ab1b02b599048403" + integrity sha1-oxAPeF+rQ1eYfEIjqxsCtZkEhAM= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.15.4" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-class-properties/download/@babel/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" + integrity sha1-QNHuFAxbHjGjUPT17tlFCWVZtC4= + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-proposal-class-static-block/download/@babel/plugin-proposal-class-static-block-7.15.4.tgz#3e7ca6128453c089e8b477a99f970c63fc1cb8d7" + integrity sha1-PnymEoRTwInotHepn5cMY/wcuNc= + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-dynamic-import/download/@babel/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" + integrity sha1-DGYX30YcDB+P/ztHzVl3I2AQHSw= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-export-namespace-from/download/@babel/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" + integrity sha1-260kQxDObM0IMHIWfYzqg6Uvr3Y= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-json-strings/download/@babel/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" + integrity sha1-ON5g2zYug6PYyUSshY3fnwwiOes= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-logical-assignment-operators/download/@babel/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" + integrity sha1-bmIpwqmbAqspFfglceDMZGpAxzg= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-nullish-coalescing-operator/download/@babel/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" + integrity sha1-7jhYnOAOLMWbKZ7D6kBvzToP2vY= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-numeric-separator/download/@babel/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" + integrity sha1-g2Mb8z2aUd8YTCECoGmsDFjAXxg= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.15.6": + version "7.15.6" + resolved "https://registry.nlark.com/@babel/plugin-proposal-object-rest-spread/download/@babel/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" + integrity sha1-72gFDIcD0Hslr0AsuWz380po7RE= + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.15.4" + +"@babel/plugin-proposal-optional-catch-binding@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-optional-catch-binding/download/@babel/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" + integrity sha1-k53W7d7/Omf997PwRLU0cmJZjDw= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-optional-chaining/download/@babel/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" + integrity sha1-+oNlHmCjYOPxN5fu8AuNUZaVtgM= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-private-methods/download/@babel/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" + integrity sha1-N0RklZlrKUXzD1vltg1eKqT1eS0= + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-proposal-private-property-in-object/download/@babel/plugin-proposal-private-property-in-object-7.15.4.tgz#55c5e3b4d0261fd44fe637e3f624cfb0f484e3e5" + integrity sha1-VcXjtNAmH9RP5jfj9iTPsPSE4+U= + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-proposal-unicode-property-regex/download/@babel/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" + integrity sha1-D5XuDnV6XWR/N42qDsp+k/qou+g= + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-async-generators/download/@babel/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha1-qYP7Gusuw/btBCohD2QOkOeG/g0= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-bigint/download/@babel/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha1-TJpvZp9dDN8bkKFnHpoUa+UwDOo= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-class-properties/download/@babel/plugin-syntax-class-properties-7.12.13.tgz?cache=0&sync_timestamp=1612315684938&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-class-properties%2Fdownload%2F%40babel%2Fplugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha1-tcmHJ0xKOoK4lxR5aTGmtTVErhA= + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-syntax-class-static-block/download/@babel/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha1-GV34mxRrS3izv4l/16JXyEZZ1AY= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-dynamic-import/download/@babel/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha1-Yr+Ysto80h1iYVT8lu5bPLaOrLM= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.nlark.com/@babel/plugin-syntax-export-namespace-from/download/@babel/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha1-AolkqbqA28CUyRXEh618TnpmRlo= + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-import-meta/download/@babel/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha1-7mATSMNw+jNNIge+FYd3SWUh/VE= + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-json-strings/download/@babel/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.0.0": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" + integrity sha1-AA4uJdhnPM5JMAUXo+2kTCY+QgE= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.nlark.com/@babel/plugin-syntax-logical-assignment-operators/download/@babel/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha1-ypHvRjA1MESLkGZSusLp/plB9pk= + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.nlark.com/@babel/plugin-syntax-nullish-coalescing-operator/download/@babel/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-numeric-separator/download/@babel/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c= + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.nlark.com/@babel/plugin-syntax-object-rest-spread/download/@babel/plugin-syntax-object-rest-spread-7.8.3.tgz?cache=0&sync_timestamp=1629640504902&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-syntax-object-rest-spread%2Fdownload%2F%40babel%2Fplugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-catch-binding/download/@babel/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha1-YRGiZbz7Ag6579D9/X0mQCue1sE= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.nlark.com/@babel/plugin-syntax-optional-chaining/download/@babel/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io= + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-syntax-private-property-in-object/download/@babel/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha1-DcZnHsDqIrbpShEU+FeXDNOd4a0= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-syntax-top-level-await/download/@babel/plugin-syntax-top-level-await-7.14.5.tgz?cache=0&sync_timestamp=1623280603783&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-syntax-top-level-await%2Fdownload%2F%40babel%2Fplugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha1-wc/a3DWmRiQAAfBhOCR7dBw02Uw= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.14.5", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-syntax-typescript/download/@babel/plugin-syntax-typescript-7.14.5.tgz?cache=0&sync_timestamp=1623280600872&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-syntax-typescript%2Fdownload%2F%40babel%2Fplugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" + integrity sha1-uCxs5HGxZbXOQgz5KRTW+0YiVxY= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-arrow-functions/download/@babel/plugin-transform-arrow-functions-7.14.5.tgz?cache=0&sync_timestamp=1623280600880&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-arrow-functions%2Fdownload%2F%40babel%2Fplugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" + integrity sha1-9xh9lYinaN0IC/TJ/+EX6mL3hio= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-async-to-generator/download/@babel/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha1-cseJCE2PIJSsuUVjOUPvhEPTnmc= + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + +"@babel/plugin-transform-block-scoped-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-block-scoped-functions/download/@babel/plugin-transform-block-scoped-functions-7.14.5.tgz?cache=0&sync_timestamp=1623280604081&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-block-scoped-functions%2Fdownload%2F%40babel%2Fplugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" + integrity sha1-5IZB2ZnUvBV6Z+8zautUvET9OtQ= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-block-scoping@^7.15.3": + version "7.15.3" + resolved "https://registry.nlark.com/@babel/plugin-transform-block-scoping/download/@babel/plugin-transform-block-scoping-7.15.3.tgz?cache=0&sync_timestamp=1628667197568&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-block-scoping%2Fdownload%2F%40babel%2Fplugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha1-lMgabi/CMLzObvU3rJah5NKzr68= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-classes@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-transform-classes/download/@babel/plugin-transform-classes-7.15.4.tgz#50aee17aaf7f332ae44e3bce4c2e10534d5d3bf1" + integrity sha1-UK7heq9/MyrkTjvOTC4QU01dO/E= + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-computed-properties/download/@babel/plugin-transform-computed-properties-7.14.5.tgz?cache=0&sync_timestamp=1623280732318&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-computed-properties%2Fdownload%2F%40babel%2Fplugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" + integrity sha1-G514mHQg0RIj1BGVRhzEO5dLIE8= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.14.7": + version "7.14.7" + resolved "https://registry.nlark.com/@babel/plugin-transform-destructuring/download/@babel/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" + integrity sha1-CtWO034j4iCE0QnxhSYINeVVdXY= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-dotall-regex/download/@babel/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" + integrity sha1-L2v3bka9+AQ7Tn4WzyRTJim6DHo= + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-duplicate-keys/download/@babel/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" + integrity sha1-NlpIRIgb3xUB46nwJw5/D5EXeVQ= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-exponentiation-operator/download/@babel/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" + integrity sha1-UVS43Wo9/m2Qkj1hckvT3uuQtJM= + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-for-of@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-transform-for-of/download/@babel/plugin-transform-for-of-7.15.4.tgz#25c62cce2718cfb29715f416e75d5263fb36a8c2" + integrity sha1-JcYszicYz7KXFfQW511SY/s2qMI= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-function-name/download/@babel/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" + integrity sha1-6Bxl7LkAdG1/MYAva+0fUtkV1vI= + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-literals/download/@babel/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" + integrity sha1-QdBsf/XU0J489Fh70+zzkwxzD3g= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-member-expression-literals/download/@babel/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" + integrity sha1-s5zVISor8jWmF9Mg7CtIvMCRuKc= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-modules-amd/download/@babel/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" + integrity sha1-T9nOfjQRy4uDhISAtwQdgwBIWPc= + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-transform-modules-commonjs/download/@babel/plugin-transform-modules-commonjs-7.15.4.tgz#8201101240eabb5a76c08ef61b2954f767b6b4c1" + integrity sha1-ggEQEkDqu1p2wI72GylU92e2tME= + dependencies: + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.15.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-transform-modules-systemjs/download/@babel/plugin-transform-modules-systemjs-7.15.4.tgz#b42890c7349a78c827719f1d2d0cd38c7d268132" + integrity sha1-tCiQxzSaeMgncZ8dLQzTjH0mgTI= + dependencies: + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-modules-umd/download/@babel/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0" + integrity sha1-+2Yt/uaXzOJ0p82lJRkKeQlqpuA= + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": + version "7.14.9" + resolved "https://registry.nlark.com/@babel/plugin-transform-named-capturing-groups-regex/download/@babel/plugin-transform-named-capturing-groups-regex-7.14.9.tgz?cache=0&sync_timestamp=1627804729192&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fplugin-transform-named-capturing-groups-regex%2Fdownload%2F%40babel%2Fplugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" + integrity sha1-xo9cXRLS66ujdi5XwsT2NHpG57I= + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + +"@babel/plugin-transform-new-target@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-new-target/download/@babel/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" + integrity sha1-Mb2ui5JdyEB26/zSqZQBQ67X2/g= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-object-super/download/@babel/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" + integrity sha1-0LX66snphZehYanPeMUn7ZNM3EU= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.14.5" + +"@babel/plugin-transform-parameters@^7.15.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/plugin-transform-parameters/download/@babel/plugin-transform-parameters-7.15.4.tgz#5f2285cc3160bf48c8502432716b48504d29ed62" + integrity sha1-XyKFzDFgv0jIUCQycWtIUE0p7WI= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-property-literals/download/@babel/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" + integrity sha1-DduqH4PbNgbxzfSEb6HftHNFizQ= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.14.5": + version "7.14.5" + resolved "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/download/@babel/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" + integrity sha1-lnb9VwftKPUicnxbPAqoVERAsE8= + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-reserved-words/download/@babel/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" + integrity sha1-xEWJtmHP2++NQwDcx0ad/6kvgwQ= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" + integrity sha1-l/E4VfFAkzjYyty6ymcK154JGlg= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.15.8": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/plugin-transform-spread/download/@babel/plugin-transform-spread-7.15.8.tgz#79d5aa27f68d700449b2da07691dfa32d2f6d468" + integrity sha1-edWqJ/aNcARJstoHaR36MtL21Gg= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" + +"@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-sticky-regex/download/@babel/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" + integrity sha1-W2F1Qmdei3dhKUOB88KMYz9Arrk= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-template-literals/download/@babel/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" + integrity sha1-pfK8Izk32EU4hdxza92Nn/q/PZM= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-typeof-symbol/download/@babel/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" + integrity sha1-Oa8nOemJor0pG/a1PxaYFCPUV9Q= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typescript@^7.15.0", "@babel/plugin-transform-typescript@^7.15.4": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/plugin-transform-typescript/download/@babel/plugin-transform-typescript-7.15.8.tgz#ff0e6a47de9b2d58652123ab5a879b2ff20665d8" + integrity sha1-/w5qR96bLVhlISOrWoebL/IGZdg= + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.14.5" + +"@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-unicode-escapes/download/@babel/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" + integrity sha1-nUvSpoHjxdes9PV/qeURddkdDGs= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.nlark.com/@babel/plugin-transform-unicode-regex/download/@babel/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" + integrity sha1-TNCbbIQl3YElXHzrP7GDbnQUOC4= + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@^7.14.5": + version "7.15.8" + resolved "https://registry.npmmirror.com/@babel/preset-env/download/@babel/preset-env-7.15.8.tgz#f527ce5bcb121cd199f6b502bf23e420b3ff8dba" + integrity sha1-9SfOW8sSHNGZ9rUCvyPkILP/jbo= + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" + "@babel/plugin-proposal-async-generator-functions" "^7.15.8" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.15.4" + "@babel/plugin-proposal-dynamic-import" "^7.14.5" + "@babel/plugin-proposal-export-namespace-from" "^7.14.5" + "@babel/plugin-proposal-json-strings" "^7.14.5" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" + "@babel/plugin-proposal-numeric-separator" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.15.6" + "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-private-methods" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.15.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.14.5" + "@babel/plugin-transform-async-to-generator" "^7.14.5" + "@babel/plugin-transform-block-scoped-functions" "^7.14.5" + "@babel/plugin-transform-block-scoping" "^7.15.3" + "@babel/plugin-transform-classes" "^7.15.4" + "@babel/plugin-transform-computed-properties" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@babel/plugin-transform-dotall-regex" "^7.14.5" + "@babel/plugin-transform-duplicate-keys" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator" "^7.14.5" + "@babel/plugin-transform-for-of" "^7.15.4" + "@babel/plugin-transform-function-name" "^7.14.5" + "@babel/plugin-transform-literals" "^7.14.5" + "@babel/plugin-transform-member-expression-literals" "^7.14.5" + "@babel/plugin-transform-modules-amd" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.15.4" + "@babel/plugin-transform-modules-systemjs" "^7.15.4" + "@babel/plugin-transform-modules-umd" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" + "@babel/plugin-transform-new-target" "^7.14.5" + "@babel/plugin-transform-object-super" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.15.4" + "@babel/plugin-transform-property-literals" "^7.14.5" + "@babel/plugin-transform-regenerator" "^7.14.5" + "@babel/plugin-transform-reserved-words" "^7.14.5" + "@babel/plugin-transform-shorthand-properties" "^7.14.5" + "@babel/plugin-transform-spread" "^7.15.8" + "@babel/plugin-transform-sticky-regex" "^7.14.5" + "@babel/plugin-transform-template-literals" "^7.14.5" + "@babel/plugin-transform-typeof-symbol" "^7.14.5" + "@babel/plugin-transform-unicode-escapes" "^7.14.5" + "@babel/plugin-transform-unicode-regex" "^7.14.5" + "@babel/preset-modules" "^0.1.4" + "@babel/types" "^7.15.6" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.5" + babel-plugin-polyfill-regenerator "^0.2.2" + core-js-compat "^3.16.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.4": + version "0.1.4" + resolved "https://registry.npmmirror.com/@babel/preset-modules/download/@babel/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha1-Ni8raMZihClw/bXiVP/I/BwuQV4= + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-typescript@^7.14.5": + version "7.15.0" + resolved "https://registry.nlark.com/@babel/preset-typescript/download/@babel/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" + integrity sha1-6PymOKGg9k8U4RGff+RQAneECUU= + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.15.0" + +"@babel/runtime@^7.11.2", "@babel/runtime@^7.8.4": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.15.4.tgz?cache=0&sync_timestamp=1630620649875&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + integrity sha1-/RfRa/34eObdAtGXU6OfqKjZyEo= + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.0.0", "@babel/template@^7.12.7", "@babel/template@^7.15.4", "@babel/template@^7.3.3": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" + integrity sha1-UYmNNdzz+qZwxO5q/P1RfuE58ZQ= + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/traverse@7.12.1": + version "7.12.1" + resolved "https://registry.nlark.com/@babel/traverse/download/@babel/traverse-7.12.1.tgz?cache=0&sync_timestamp=1630620670195&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" + integrity sha1-lBOV4MXMhtXT51yqCV05JFJvDB4= + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.12.1" + "@babel/types" "^7.12.1" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": + version "7.15.4" + resolved "https://registry.nlark.com/@babel/traverse/download/@babel/traverse-7.15.4.tgz?cache=0&sync_timestamp=1630620670195&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" + integrity sha1-/4UQNnoUS/v/VS2eGOKPPiiJwi0= + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@7.12.1": + version "7.12.1" + resolved "https://registry.nlark.com/@babel/types/download/@babel/types-7.12.1.tgz?cache=0&sync_timestamp=1631221851556&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae" + integrity sha1-4QnZq5mo3nNb4ofuPWqZR6GQxK4= + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.9.6": + version "7.15.6" + resolved "https://registry.nlark.com/@babel/types/download/@babel/types-7.15.6.tgz?cache=0&sync_timestamp=1631221851556&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" + integrity sha1-mavcSCGLKIHAWN0KerBbmcm+dY8= + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmmirror.com/@bcoe/v8-coverage/download/@bcoe/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha1-daLotRy3WKdVPWgEpZMteqznXDk= + +"@commitlint/cli@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/cli/download/@commitlint/cli-11.0.0.tgz#698199bc52afed50aa28169237758fa14a67b5d3" + integrity sha1-aYGZvFKv7VCqKBaSN3WPoUpntdM= + dependencies: + "@babel/runtime" "^7.11.2" + "@commitlint/format" "^11.0.0" + "@commitlint/lint" "^11.0.0" + "@commitlint/load" "^11.0.0" + "@commitlint/read" "^11.0.0" + chalk "4.1.0" + core-js "^3.6.1" + get-stdin "8.0.0" + lodash "^4.17.19" + resolve-from "5.0.0" + resolve-global "1.0.0" + yargs "^15.1.0" + +"@commitlint/config-conventional@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/config-conventional/download/@commitlint/config-conventional-11.0.0.tgz#3fa300a1b639273946de3c3f15e1cda518333422" + integrity sha1-P6MAobY5JzlG3jw/FeHNpRgzNCI= + dependencies: + conventional-changelog-conventionalcommits "^4.3.1" + +"@commitlint/ensure@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/ensure/download/@commitlint/ensure-11.0.0.tgz#3e796b968ab5b72bc6f8a6040076406306c987fb" + integrity sha1-Pnlrloq1tyvG+KYEAHZAYwbJh/s= + dependencies: + "@commitlint/types" "^11.0.0" + lodash "^4.17.19" + +"@commitlint/execute-rule@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/execute-rule/download/@commitlint/execute-rule-11.0.0.tgz#3ed60ab7a33019e58d90e2d891b75d7df77b4b4d" + integrity sha1-PtYKt6MwGeWNkOLYkbddffd7S00= + +"@commitlint/format@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/format/download/@commitlint/format-11.0.0.tgz#ac47b0b9ca46540c0082c721b290794e67bdc51b" + integrity sha1-rEewucpGVAwAgschspB5Tme9xRs= + dependencies: + "@commitlint/types" "^11.0.0" + chalk "^4.0.0" + +"@commitlint/is-ignored@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/is-ignored/download/@commitlint/is-ignored-11.0.0.tgz#7b803eda56276dbe7fec51eb1510676198468f39" + integrity sha1-e4A+2lYnbb5/7FHrFRBnYZhGjzk= + dependencies: + "@commitlint/types" "^11.0.0" + semver "7.3.2" + +"@commitlint/lint@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/lint/download/@commitlint/lint-11.0.0.tgz#01e062cd1b0e7c3d756aa2c246462e0b6a3348a4" + integrity sha1-AeBizRsOfD11aqLCRkYuC2ozSKQ= + dependencies: + "@commitlint/is-ignored" "^11.0.0" + "@commitlint/parse" "^11.0.0" + "@commitlint/rules" "^11.0.0" + "@commitlint/types" "^11.0.0" + +"@commitlint/load@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/load/download/@commitlint/load-11.0.0.tgz#f736562f0ffa7e773f8808fea93319042ee18211" + integrity sha1-9zZWLw/6fnc/iAj+qTMZBC7hghE= + dependencies: + "@commitlint/execute-rule" "^11.0.0" + "@commitlint/resolve-extends" "^11.0.0" + "@commitlint/types" "^11.0.0" + chalk "4.1.0" + cosmiconfig "^7.0.0" + lodash "^4.17.19" + resolve-from "^5.0.0" + +"@commitlint/message@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/message/download/@commitlint/message-11.0.0.tgz#83554c3cbbc884fd07b473593bc3e94bcaa3ee05" + integrity sha1-g1VMPLvIhP0HtHNZO8PpS8qj7gU= + +"@commitlint/parse@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/parse/download/@commitlint/parse-11.0.0.tgz#d18b08cf67c35d02115207d7009306a2e8e7c901" + integrity sha1-0YsIz2fDXQIRUgfXAJMGoujnyQE= + dependencies: + conventional-changelog-angular "^5.0.0" + conventional-commits-parser "^3.0.0" + +"@commitlint/read@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/read/download/@commitlint/read-11.0.0.tgz#f24240548c63587bba139fa5a364cab926077016" + integrity sha1-8kJAVIxjWHu6E5+lo2TKuSYHcBY= + dependencies: + "@commitlint/top-level" "^11.0.0" + fs-extra "^9.0.0" + git-raw-commits "^2.0.0" + +"@commitlint/resolve-extends@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/resolve-extends/download/@commitlint/resolve-extends-11.0.0.tgz#158ecbe27d4a2a51d426111a01478e216fbb1036" + integrity sha1-FY7L4n1KKlHUJhEaAUeOIW+7EDY= + dependencies: + import-fresh "^3.0.0" + lodash "^4.17.19" + resolve-from "^5.0.0" + resolve-global "^1.0.0" + +"@commitlint/rules@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/rules/download/@commitlint/rules-11.0.0.tgz#bdb310cc6fc55c9f8d7d917a22b69055c535c375" + integrity sha1-vbMQzG/FXJ+NfZF6IraQVcU1w3U= + dependencies: + "@commitlint/ensure" "^11.0.0" + "@commitlint/message" "^11.0.0" + "@commitlint/to-lines" "^11.0.0" + "@commitlint/types" "^11.0.0" + +"@commitlint/to-lines@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/to-lines/download/@commitlint/to-lines-11.0.0.tgz#86dea151c10eea41e39ea96fa4de07839258a7fe" + integrity sha1-ht6hUcEO6kHjnqlvpN4Hg5JYp/4= + +"@commitlint/top-level@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/top-level/download/@commitlint/top-level-11.0.0.tgz#bb2d1b6e5ed3be56874633b59e1f7de118c32783" + integrity sha1-uy0bbl7TvlaHRjO1nh994RjDJ4M= + dependencies: + find-up "^5.0.0" + +"@commitlint/types@^11.0.0": + version "11.0.0" + resolved "https://registry.npmmirror.com/@commitlint/types/download/@commitlint/types-11.0.0.tgz#719cf05fcc1abb6533610a2e0f5dd1e61eac14fe" + integrity sha1-cZzwX8wau2UzYQouD13R5h6sFP4= + +"@devui-design/icons@^1.3.0": + version "1.3.0" + resolved "https://registry.nlark.com/@devui-design/icons/download/@devui-design/icons-1.3.0.tgz#5a3006a31ee4f62e3f9837b68c031898ff148b88" + integrity sha1-WjAGox7k9i4/mDe2jAMYmP8Ui4g= + +"@docsearch/css@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.nlark.com/@docsearch/css/download/@docsearch/css-1.0.0-alpha.28.tgz#c8a2cd8c1bb3a6855c51892e9dbdab5d42fe6e23" + integrity sha1-yKLNjBuzpoVcUYkunb2rXUL+biM= + +"@docsearch/js@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.nlark.com/@docsearch/js/download/@docsearch/js-1.0.0-alpha.28.tgz#f0fde7b8a6b1e1d8a7ae1e7655c43d959b457b2b" + integrity sha1-8P3nuKax4dinrh52VcQ9lZtFeys= + dependencies: + "@docsearch/react" "^1.0.0-alpha.28" + preact "^10.0.0" + +"@docsearch/react@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.nlark.com/@docsearch/react/download/@docsearch/react-1.0.0-alpha.28.tgz#4f039ed79f8b3332b19a57677b219aebc5010e9d" + integrity sha1-TwOe15+LMzKxmldneyGa68UBDp0= + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@francoischalifour/autocomplete-core" "^1.0.0-alpha.28" + "@francoischalifour/autocomplete-preset-algolia" "^1.0.0-alpha.28" + algoliasearch "^4.0.0" + +"@emmetio/abbreviation@^2.2.2": + version "2.2.2" + resolved "https://registry.nlark.com/@emmetio/abbreviation/download/@emmetio/abbreviation-2.2.2.tgz#746762fd9e7a8c2ea604f580c62e3cfe250e6989" + integrity sha1-dGdi/Z56jC6mBPWAxi48/iUOaYk= + dependencies: + "@emmetio/scanner" "^1.0.0" + +"@emmetio/css-abbreviation@^2.1.4": + version "2.1.4" + resolved "https://registry.nlark.com/@emmetio/css-abbreviation/download/@emmetio/css-abbreviation-2.1.4.tgz#90362e8a1122ce3b76f6c3157907d30182f53f54" + integrity sha1-kDYuihEizjt29sMVeQfTAYL1P1Q= + dependencies: + "@emmetio/scanner" "^1.0.0" + +"@emmetio/scanner@^1.0.0": + version "1.0.0" + resolved "https://registry.nlark.com/@emmetio/scanner/download/@emmetio/scanner-1.0.0.tgz#065b2af6233fe7474d44823e3deb89724af42b5f" + integrity sha1-Blsq9iM/50dNRII+PeuJckr0K18= + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.npmmirror.com/@eslint/eslintrc/download/@eslint/eslintrc-0.4.3.tgz?cache=0&sync_timestamp=1634178097886&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40eslint%2Feslintrc%2Fdownload%2F%40eslint%2Feslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha1-nkKYHvA1vrPdSa3ResuW6P9vOUw= + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@francoischalifour/autocomplete-core@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npm.taobao.org/@francoischalifour/autocomplete-core/download/@francoischalifour/autocomplete-core-1.0.0-alpha.28.tgz#6b9d8491288e77f831e9b345d461623b0d3f5005" + integrity sha1-a52EkSiOd/gx6bNF1GFiOw0/UAU= + +"@francoischalifour/autocomplete-preset-algolia@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npm.taobao.org/@francoischalifour/autocomplete-preset-algolia/download/@francoischalifour/autocomplete-preset-algolia-1.0.0-alpha.28.tgz#a5ad7996f42e43e4acbb4e0010d663746d0e9997" + integrity sha1-pa15lvQuQ+Ssu04AENZjdG0OmZc= + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.npmmirror.com/@humanwhocodes/config-array/download/@humanwhocodes/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha1-FAeWfUxu7Nc4j4Os8er00Mbljvk= + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.0" + resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/download/@humanwhocodes/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + integrity sha1-h956+cIxgm/daKxyWPd8Qp4OX88= + +"@intlify/core-base@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/core-base/download/@intlify/core-base-9.1.9.tgz#e4e8c951010728e4af3a0d13d74cf3f9e7add7f6" + integrity sha1-5OjJUQEHKOSvOg0T10zz+eet1/Y= + dependencies: + "@intlify/devtools-if" "9.1.9" + "@intlify/message-compiler" "9.1.9" + "@intlify/message-resolver" "9.1.9" + "@intlify/runtime" "9.1.9" + "@intlify/shared" "9.1.9" + "@intlify/vue-devtools" "9.1.9" + +"@intlify/core@^9.0.0-beta.15": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/core/download/@intlify/core-9.1.9.tgz#774e739a2ab4ac460a348a35eb0260e787d50556" + integrity sha1-d05zmiq0rEYKNIo16wJg54fVBVY= + dependencies: + "@intlify/core-base" "9.1.9" + +"@intlify/devtools-if@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/devtools-if/download/@intlify/devtools-if-9.1.9.tgz#a30e1dd1256ff2c5c98d8d75d075384fba898e5d" + integrity sha1-ow4d0SVv8sXJjY110HU4T7qJjl0= + dependencies: + "@intlify/shared" "9.1.9" + +"@intlify/message-compiler@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.1.9.tgz#1193cbd224a71c2fb981455b8534a3c766d2948d" + integrity sha1-EZPL0iSnHC+5gUVbhTSjx2bSlI0= + dependencies: + "@intlify/message-resolver" "9.1.9" + "@intlify/shared" "9.1.9" + source-map "0.6.1" + +"@intlify/message-resolver@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/message-resolver/download/@intlify/message-resolver-9.1.9.tgz#3155ccd2f5e6d0dc16cad8b7f1d8e97fcda05bfc" + integrity sha1-MVXM0vXm0NwWyti38djpf82gW/w= + +"@intlify/runtime@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/runtime/download/@intlify/runtime-9.1.9.tgz#2c12ce29518a075629efed0a8ed293ee740cb285" + integrity sha1-LBLOKVGKB1Yp7+0KjtKT7nQMsoU= + dependencies: + "@intlify/message-compiler" "9.1.9" + "@intlify/message-resolver" "9.1.9" + "@intlify/shared" "9.1.9" + +"@intlify/shared@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.1.9.tgz#0baaf96128b85560666bec784ffb01f6623cc17a" + integrity sha1-C6r5YSi4VWBma+x4T/sB9mI8wXo= + +"@intlify/vue-devtools@9.1.9": + version "9.1.9" + resolved "https://registry.npmmirror.com/@intlify/vue-devtools/download/@intlify/vue-devtools-9.1.9.tgz#2be8f4dbe7f7ed4115676eb32348141d411e426b" + integrity sha1-K+j02+f37UEVZ26zI0gUHUEeQms= + dependencies: + "@intlify/message-resolver" "9.1.9" + "@intlify/runtime" "9.1.9" + "@intlify/shared" "9.1.9" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npm.taobao.org/@istanbuljs/load-nyc-config/download/@istanbuljs/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha1-/T2x1Z7PfPEh6AZQu4ZxL5tV7O0= + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.npm.taobao.org/@istanbuljs/schema/download/@istanbuljs/schema-0.1.3.tgz?cache=0&sync_timestamp=1613227837612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40istanbuljs%2Fschema%2Fdownload%2F%40istanbuljs%2Fschema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha1-5F44TkuOwWvOL9kDr3hFD2v37Jg= + +"@jest/console@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/console/download/@jest/console-27.2.5.tgz?cache=0&sync_timestamp=1633701215678&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Fconsole%2Fdownload%2F%40jest%2Fconsole-27.2.5.tgz#bddbf8d41c191f17b52bf0c9e6c0d18605e35d6e" + integrity sha1-vdv41BwZHxe1K/DJ5sDRhgXjXW4= + dependencies: + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.2.5" + jest-util "^27.2.5" + slash "^3.0.0" + +"@jest/core@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/core/download/@jest/core-27.2.5.tgz#854c314708cee0d892ac4f531b9129f00a21ee69" + integrity sha1-hUwxRwjO4NiSrE9TG5Ep8Aoh7mk= + dependencies: + "@jest/console" "^27.2.5" + "@jest/reporters" "^27.2.5" + "@jest/test-result" "^27.2.5" + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.2.5" + jest-config "^27.2.5" + jest-haste-map "^27.2.5" + jest-message-util "^27.2.5" + jest-regex-util "^27.0.6" + jest-resolve "^27.2.5" + jest-resolve-dependencies "^27.2.5" + jest-runner "^27.2.5" + jest-runtime "^27.2.5" + jest-snapshot "^27.2.5" + jest-util "^27.2.5" + jest-validate "^27.2.5" + jest-watcher "^27.2.5" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/environment/download/@jest/environment-27.2.5.tgz?cache=0&sync_timestamp=1633701216219&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Fenvironment%2Fdownload%2F%40jest%2Fenvironment-27.2.5.tgz#b85517ccfcec55690c82c56f5a01a3b30c5e3c84" + integrity sha1-uFUXzPzsVWkMgsVvWgGjswxePIQ= + dependencies: + "@jest/fake-timers" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.2.5" + +"@jest/fake-timers@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/fake-timers/download/@jest/fake-timers-27.2.5.tgz?cache=0&sync_timestamp=1633701216484&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ffake-timers%2Fdownload%2F%40jest%2Ffake-timers-27.2.5.tgz#0c7e5762d7bfe6e269e7b49279b097a52a42f0a0" + integrity sha1-DH5XYte/5uJp57SSebCXpSpC8KA= + dependencies: + "@jest/types" "^27.2.5" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.2.5" + jest-mock "^27.2.5" + jest-util "^27.2.5" + +"@jest/globals@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/globals/download/@jest/globals-27.2.5.tgz?cache=0&sync_timestamp=1633701219915&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Fglobals%2Fdownload%2F%40jest%2Fglobals-27.2.5.tgz#4115538f98ed6cee4051a90fdbd0854062902099" + integrity sha1-QRVTj5jtbO5AUakP29CFQGKQIJk= + dependencies: + "@jest/environment" "^27.2.5" + "@jest/types" "^27.2.5" + expect "^27.2.5" + +"@jest/reporters@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/reporters/download/@jest/reporters-27.2.5.tgz#65198ed1f3f4449e3f656129764dc6c5bb27ebe3" + integrity sha1-ZRmO0fP0RJ4/ZWEpdk3Gxbsn6+M= + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.2.5" + "@jest/test-result" "^27.2.5" + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^27.2.5" + jest-resolve "^27.2.5" + jest-util "^27.2.5" + jest-worker "^27.2.5" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.0.6": + version "27.0.6" + resolved "https://registry.nlark.com/@jest/source-map/download/@jest/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f" + integrity sha1-vp6bk1ZdSbBUi4biMgkkkftgVR8= + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/test-result/download/@jest/test-result-27.2.5.tgz?cache=0&sync_timestamp=1633701211590&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ftest-result%2Fdownload%2F%40jest%2Ftest-result-27.2.5.tgz#e9f73cf6cd5e2cc6eb3105339248dea211f9320e" + integrity sha1-6fc89s1eLMbrMQUzkkjeohH5Mg4= + dependencies: + "@jest/console" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/test-sequencer/download/@jest/test-sequencer-27.2.5.tgz?cache=0&sync_timestamp=1633701216752&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ftest-sequencer%2Fdownload%2F%40jest%2Ftest-sequencer-27.2.5.tgz#ed5ae91c00e623fb719111d58e380395e16cefbb" + integrity sha1-7VrpHADmI/txkRHVjjgDleFs77s= + dependencies: + "@jest/test-result" "^27.2.5" + graceful-fs "^4.2.4" + jest-haste-map "^27.2.5" + jest-runtime "^27.2.5" + +"@jest/transform@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/transform/download/@jest/transform-27.2.5.tgz?cache=0&sync_timestamp=1633701212569&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ftransform%2Fdownload%2F%40jest%2Ftransform-27.2.5.tgz#02b08862a56dbedddf0ba3c2eae41e049a250e29" + integrity sha1-ArCIYqVtvt3fC6PC6uQeBJolDik= + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.2.5" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.2.5" + jest-regex-util "^27.0.6" + jest-util "^27.2.5" + micromatch "^4.0.4" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.npmmirror.com/@jest/types/download/@jest/types-26.6.2.tgz?cache=0&sync_timestamp=1633701209034&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha1-vvWlMgMOHYii9abZM/hOlyJu1I4= + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@jest/types@^27.2.5": + version "27.2.5" + resolved "https://registry.npmmirror.com/@jest/types/download/@jest/types-27.2.5.tgz?cache=0&sync_timestamp=1633701209034&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-27.2.5.tgz#420765c052605e75686982d24b061b4cbba22132" + integrity sha1-QgdlwFJgXnVoaYLSSwYbTLuiITI= + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@ls-lint/ls-lint@^1.10.0": + version "1.10.0" + resolved "https://registry.nlark.com/@ls-lint/ls-lint/download/@ls-lint/ls-lint-1.10.0.tgz#cad20085edc010a3e938aa01bb66d05e5e12b3f3" + integrity sha1-ytIAhe3AEKPpOKoBu2bQXl4Ss/M= + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.nlark.com/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U= + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.nlark.com/@nodelib/fs.stat/download/@nodelib/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha1-W9Jir5Tp0lvR5xsF3u1Eh2oiLos= + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.nlark.com/@nodelib/fs.walk/download/@nodelib/fs.walk-1.2.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40nodelib%2Ffs.walk%2Fdownload%2F%40nodelib%2Ffs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha1-6Vc36LtnRt3t9pxVaVNJTxlv5po= + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@polka/url@^0.5.0": + version "0.5.0" + resolved "https://registry.npmmirror.com/@polka/url/download/@polka/url-0.5.0.tgz#b21510597fd601e5d7c95008b76bf0d254ebfd31" + integrity sha1-shUQWX/WAeXXyVAIt2vw0lTr/TE= + +"@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.npmmirror.com/@polka/url/download/@polka/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" + integrity sha1-XeWiOFo1MJQn9gEZkrVEUU1VmqE= + +"@rollup/pluginutils@^4.1.1": + version "4.1.1" + resolved "https://registry.nlark.com/@rollup/pluginutils/download/@rollup/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec" + integrity sha1-HU2obdTt7RVlalfZM/2iuaCNR+w= + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.npm.taobao.org/@sinonjs/commons/download/@sinonjs/commons-1.8.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40sinonjs%2Fcommons%2Fdownload%2F%40sinonjs%2Fcommons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha1-OALd0hpQqUm2ch3dcto25n5/Gy0= + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.0.1" + resolved "https://registry.npmmirror.com/@sinonjs/fake-timers/download/@sinonjs/fake-timers-8.0.1.tgz#1c1c9a91419f804e59ae8df316a07dd1c3a76b94" + integrity sha1-HByakUGfgE5Zro3zFqB90cOna5Q= + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@stylelint/postcss-css-in-js@^0.37.2": + version "0.37.2" + resolved "https://registry.npm.taobao.org/@stylelint/postcss-css-in-js/download/@stylelint/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2" + integrity sha1-flqErRgfQjSiSAgDQipHuHSa89I= + dependencies: + "@babel/core" ">=7.9.0" + +"@stylelint/postcss-markdown@^0.36.2": + version "0.36.2" + resolved "https://registry.nlark.com/@stylelint/postcss-markdown/download/@stylelint/postcss-markdown-0.36.2.tgz#0a540c4692f8dcdfc13c8e352c17e7bfee2bb391" + integrity sha1-ClQMRpL43N/BPI41LBfnv+4rs5E= + dependencies: + remark "^13.0.0" + unist-util-find-all-after "^3.0.2" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.npmmirror.com/@tootallnate/once/download/@tootallnate/once-1.1.2.tgz?cache=0&sync_timestamp=1632734582200&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40tootallnate%2Fonce%2Fdownload%2F%40tootallnate%2Fonce-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha1-zLkURTYBeaBOf+av94wA/8Hur4I= + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.nlark.com/@trysound/sax/download/@trysound/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha1-zMqrdYr1Z2Hre/N69vA/Mm3XmK0= + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.16" + resolved "https://registry.nlark.com/@types/babel__core/download/@types/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha1-vBLHS31l6C0ph2tdC69cYlrFhwI= + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.3" + resolved "https://registry.nlark.com/@types/babel__generator/download/@types/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha1-9Fa0ss55E392iqEw0kI9LwzPq6U= + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.nlark.com/@types/babel__template/download/@types/babel__template-7.4.1.tgz?cache=0&sync_timestamp=1629706713150&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fbabel__template%2Fdownload%2F%40types%2Fbabel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha1-PRpI/Z1sDt/Vby/1eNrtSPNsiWk= + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.npmmirror.com/@types/babel__traverse/download/@types/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha1-/81HC7s/i/MEgWePtVAieMqDOkM= + dependencies: + "@babel/types" "^7.3.0" + +"@types/braces@*": + version "3.0.1" + resolved "https://registry.nlark.com/@types/braces/download/@types/braces-3.0.1.tgz#5a284d193cfc61abb2e5a50d36ebbc50d942a32b" + integrity sha1-WihNGTz8Yauy5aUNNuu8UNlCoys= + +"@types/chalk@^2.2.0": + version "2.2.0" + resolved "https://registry.npm.taobao.org/@types/chalk/download/@types/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" + integrity sha1-t/bkRvRRECnujj9DB1+1tz+6oLo= + dependencies: + chalk "*" + +"@types/commander@^2.12.2": + version "2.12.2" + resolved "https://registry.npm.taobao.org/@types/commander/download/@types/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae" + integrity sha1-GDBBojhC1CgUePpdI8XKeOb9CK4= + dependencies: + commander "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.nlark.com/@types/graceful-fs/download/@types/graceful-fs-4.1.5.tgz?cache=0&sync_timestamp=1629708809056&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fgraceful-fs%2Fdownload%2F%40types%2Fgraceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha1-If+6DZjaQ1DbZIkfkqnl2zzbThU= + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.nlark.com/@types/istanbul-lib-coverage/download/@types/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha1-S6jdtyAiH0MuRDvV+RF/0iz9R2I= + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.nlark.com/@types/istanbul-lib-report/download/@types/istanbul-lib-report-3.0.0.tgz?cache=0&sync_timestamp=1629708139059&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fistanbul-lib-report%2Fdownload%2F%40types%2Fistanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha1-wUwk8Y6oGQwRjudWK3/5mjZVJoY= + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.nlark.com/@types/istanbul-reports/download/@types/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha1-kVP+mLuivVZaY63ZQ21vDX+EaP8= + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^26.0.23": + version "26.0.24" + resolved "https://registry.nlark.com/@types/jest/download/@types/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" + integrity sha1-lD0Rl2sWc5GFkToZNuDeDEp9WVo= + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.nlark.com/@types/json-schema/download/@types/json-schema-7.0.9.tgz?cache=0&sync_timestamp=1629708116786&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha1-l+3JA36gw4WFMgsolk3eOznkZg0= + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npm.taobao.org/@types/json5/download/@types/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.nlark.com/@types/linkify-it/download/@types/linkify-it-3.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Flinkify-it%2Fdownload%2F%40types%2Flinkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha1-/SzS7bqn6qx+fzwXSLUqGRQ4Rsk= + +"@types/lodash-es@^4.17.4": + version "4.17.5" + resolved "https://registry.nlark.com/@types/lodash-es/download/@types/lodash-es-4.17.5.tgz#1c3fdd16849d84aea43890b1c60da379fb501353" + integrity sha1-HD/dFoSdhK6kOJCxxg2jeftQE1M= + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.175" + resolved "https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" + integrity sha1-t436lZGSsB+uCtkOFmR4dpshX0U= + +"@types/markdown-it@^12.0.1": + version "12.2.3" + resolved "https://registry.npmmirror.com/@types/markdown-it/download/@types/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha1-DW9uXkE/jaqiZSKQRZe+PWzZO1E= + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.nlark.com/@types/mdast/download/@types/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha1-RyQkSoKkWYiEy76bz9c9/5J+6K8= + dependencies: + "@types/unist" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.nlark.com/@types/mdurl/download/@types/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha1-4s6dg6YTus8oTHvn1JGUXjnh+Ok= + +"@types/micromatch@^4.0.1": + version "4.0.2" + resolved "https://registry.nlark.com/@types/micromatch/download/@types/micromatch-4.0.2.tgz?cache=0&sync_timestamp=1629708677514&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fmicromatch%2Fdownload%2F%40types%2Fmicromatch-4.0.2.tgz#ce29c8b166a73bf980a5727b1e4a4d099965151d" + integrity sha1-zinIsWanO/mApXJ7HkpNCZllFR0= + dependencies: + "@types/braces" "*" + +"@types/minimist@^1.2.0": + version "1.2.2" + resolved "https://registry.nlark.com/@types/minimist/download/@types/minimist-1.2.2.tgz?cache=0&sync_timestamp=1629708375091&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fminimist%2Fdownload%2F%40types%2Fminimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha1-7nceK6Sz3Fs3KTXVSf2WF780W4w= + +"@types/node@*": + version "16.11.0" + resolved "https://registry.npmmirror.com/@types/node/download/@types/node-16.11.0.tgz#4b95f2327bacd1ef8f08d8ceda193039c5d7f52e" + integrity sha1-S5XyMnus0e+PCNjO2hkwOcXX9S4= + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.nlark.com/@types/normalize-package-data/download/@types/normalize-package-data-2.4.1.tgz?cache=0&sync_timestamp=1629708548426&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnormalize-package-data%2Fdownload%2F%40types%2Fnormalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha1-0zV0eaD9/dWQf+Z+F+CoXJBuEwE= + +"@types/ora@^3.2.0": + version "3.2.0" + resolved "https://registry.nlark.com/@types/ora/download/@types/ora-3.2.0.tgz#b2f65d1283a8f36d8b0f9ee767e0732a2f429362" + integrity sha1-svZdEoOo822LD57nZ+BzKi9Ck2I= + dependencies: + ora "*" + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.nlark.com/@types/parse-json/download/@types/parse-json-4.0.0.tgz?cache=0&sync_timestamp=1629708940688&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fparse-json%2Fdownload%2F%40types%2Fparse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha1-L4u0QUNNFjs1+4/9zNcTiSf/uMA= + +"@types/prettier@^2.1.5": + version "2.4.1" + resolved "https://registry.npmmirror.com/@types/prettier/download/@types/prettier-2.4.1.tgz?cache=0&sync_timestamp=1632784130205&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fprettier%2Fdownload%2F%40types%2Fprettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" + integrity sha1-4TAwSNU4lWPhMPW92J03qZrLdes= + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.nlark.com/@types/stack-utils/download/@types/stack-utils-2.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fstack-utils%2Fdownload%2F%40types%2Fstack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha1-IPGClPeX8iCbX2XI47XI6CYdEnw= + +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": + version "2.0.6" + resolved "https://registry.nlark.com/@types/unist/download/@types/unist-2.0.6.tgz?cache=0&sync_timestamp=1629709942155&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Funist%2Fdownload%2F%40types%2Funist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha1-JQp7FsO5H2cqJFUuxkZ47rHToI0= + +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.nlark.com/@types/yargs-parser/download/@types/yargs-parser-20.2.1.tgz?cache=0&sync_timestamp=1629709931030&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fyargs-parser%2Fdownload%2F%40types%2Fyargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha1-O5ziSJkZ2eT+pDm3aRarw0st8Sk= + +"@types/yargs@^15.0.0": + version "15.0.14" + resolved "https://registry.npmmirror.com/@types/yargs/download/@types/yargs-15.0.14.tgz?cache=0&sync_timestamp=1634259802415&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fyargs%2Fdownload%2F%40types%2Fyargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha1-Jtgh3biecEkhYLZtEKDrbfj2+wY= + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.npmmirror.com/@types/yargs/download/@types/yargs-16.0.4.tgz?cache=0&sync_timestamp=1634259802415&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fyargs%2Fdownload%2F%40types%2Fyargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha1-JqrZjdLCo45CEIbqmtQrnlFkKXc= + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^4.27.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha1-wk3HyAacdwa8QNmfb6h+3LIAUnY= + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/experimental-utils/download/@typescript-eslint/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha1-byp4akIJ+iIimJ6TgLUzGygQ9/0= + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.27.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/parser/download/@typescript-eslint/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha1-3+eXVw2WlOVgUo0Y7srYbIx0SJk= + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/scope-manager/download/@typescript-eslint/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha1-045JKA2YPody4pEhz4xukiHygKM= + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/types/download/@typescript-eslint/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha1-oeWQNqO1OuhDDO6/KpGdx/mvbXI= + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha1-DftRwpCPaMXAjYKu/q8WahfCRgk= + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/download/@typescript-eslint/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha1-KiL3ekFgQom3oYZYbp7EjKku8d0= + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@vitejs/plugin-vue-jsx@^1.1.0": + version "1.2.0" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue-jsx/download/@vitejs/plugin-vue-jsx-1.2.0.tgz#a4216bdbb8b12800537d39e3b5711fcf2eb470ef" + integrity sha1-pCFr27ixKABTfTnjtXEfzy60cO8= + dependencies: + "@babel/core" "^7.15.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-transform-typescript" "^7.15.4" + "@rollup/pluginutils" "^4.1.1" + "@vue/babel-plugin-jsx" "^1.0.7" + hash-sum "^2.0.0" + +"@vitejs/plugin-vue@^1.2.3", "@vitejs/plugin-vue@^1.3.0", "@vitejs/plugin-vue@^1.4.0": + version "1.9.3" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/download/@vitejs/plugin-vue-1.9.3.tgz#93d61893ce6c723d0209af0483ec8b91a2cd811f" + integrity sha1-k9YYk85scj0CCa8Eg+yLkaLNgR8= + +"@volar/code-gen@^0.27.24": + version "0.27.24" + resolved "https://registry.npmmirror.com/@volar/code-gen/download/@volar/code-gen-0.27.24.tgz#ccdbe858951c1ee4e0c3979232d52412dc46756a" + integrity sha1-zNvoWJUcHuTgw5eSMtUkEtxGdWo= + dependencies: + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + +"@volar/html2pug@^0.27.13": + version "0.27.13" + resolved "https://registry.npmmirror.com/@volar/html2pug/download/@volar/html2pug-0.27.13.tgz#48dfa73ecf1ef1955a02a046d0c88845950fac85" + integrity sha1-SN+nPs8e8ZVaAqBG0MiIRZUPrIU= + dependencies: + domelementtype "^2.2.0" + domhandler "^4.2.0" + htmlparser2 "^6.1.0" + pug "^3.0.2" + +"@volar/shared@^0.27.24": + version "0.27.24" + resolved "https://registry.npmmirror.com/@volar/shared/download/@volar/shared-0.27.24.tgz#a33457ec8ac0b0d367ed54c9e21913a5f8c2d6c2" + integrity sha1-ozRX7IrAsNNn7VTJ4hkTpfjC1sI= + dependencies: + upath "^2.0.1" + vscode-jsonrpc "^8.0.0-next.2" + vscode-uri "^3.0.2" + +"@volar/source-map@^0.27.24": + version "0.27.24" + resolved "https://registry.npmmirror.com/@volar/source-map/download/@volar/source-map-0.27.24.tgz#60f2e070c169be82cbf7ffa296a30c2823c5205f" + integrity sha1-YPLgcMFpvoLL9/+ilqMMKCPFIF8= + dependencies: + "@volar/shared" "^0.27.24" + +"@volar/transforms@^0.27.24": + version "0.27.24" + resolved "https://registry.npmmirror.com/@volar/transforms/download/@volar/transforms-0.27.24.tgz#68ebc53dca2e36884e247c0866ec3d24ed815784" + integrity sha1-aOvFPcouNohOJHwIZuw9JO2BV4Q= + dependencies: + "@volar/shared" "^0.27.24" + vscode-languageserver "^8.0.0-next.2" + +"@vscode/emmet-helper@^2.7.0": + version "2.8.1" + resolved "https://registry.npmmirror.com/@vscode/emmet-helper/download/@vscode/emmet-helper-2.8.1.tgz#843c9a5704d72d6f3a30c76b22b518391029d508" + integrity sha1-hDyaVwTXLW86MMdrIrUYORAp1Qg= + dependencies: + emmet "^2.3.0" + jsonc-parser "^2.3.0" + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.15.1" + vscode-nls "^5.0.0" + vscode-uri "^2.1.2" + +"@vue/babel-helper-vue-transform-on@^1.0.2": + version "1.0.2" + resolved "https://registry.nlark.com/@vue/babel-helper-vue-transform-on/download/@vue/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc" + integrity sha1-m5xpHNBvyFUiGiR1w8yDHXdLx9w= + +"@vue/babel-plugin-jsx@^1.0.6", "@vue/babel-plugin-jsx@^1.0.7": + version "1.1.0" + resolved "https://registry.npmmirror.com/@vue/babel-plugin-jsx/download/@vue/babel-plugin-jsx-1.1.0.tgz#eb73871cbe468bc12141441a0052d8948ac4f67d" + integrity sha1-63OHHL5Gi8EhQUQaAFLYlIrE9n0= + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + "@vue/babel-helper-vue-transform-on" "^1.0.2" + camelcase "^6.0.0" + html-tags "^3.1.0" + svg-tags "^1.0.0" + +"@vue/compiler-core@3.2.20", "@vue/compiler-core@^3.0.0", "@vue/compiler-core@^3.0.1", "@vue/compiler-core@^3.0.2": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/compiler-core/download/@vue/compiler-core-3.2.20.tgz#af5a3c5237818835b0d0be837eb5885a8d21c160" + integrity sha1-r1o8UjeBiDWw0L6DfrWIWo0hwWA= + dependencies: + "@babel/parser" "^7.15.0" + "@vue/shared" "3.2.20" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.20", "@vue/compiler-dom@^3.2.19": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/compiler-dom/download/@vue/compiler-dom-3.2.20.tgz#8e0ef354449c0faf41519b00bfc2045eae01dcb5" + integrity sha1-jg7zVEScD69BUZsAv8IEXq4B3LU= + dependencies: + "@vue/compiler-core" "3.2.20" + "@vue/shared" "3.2.20" + +"@vue/compiler-sfc@3.2.20", "@vue/compiler-sfc@^3.0.11", "@vue/compiler-sfc@^3.0.5", "@vue/compiler-sfc@^3.1.1", "@vue/compiler-sfc@^3.2.1": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/compiler-sfc/download/@vue/compiler-sfc-3.2.20.tgz#2d7668e76f066c566dd7c09c15c9acce4e876e0a" + integrity sha1-LXZo528GbFZt18CcFcmszk6Hbgo= + dependencies: + "@babel/parser" "^7.15.0" + "@vue/compiler-core" "3.2.20" + "@vue/compiler-dom" "3.2.20" + "@vue/compiler-ssr" "3.2.20" + "@vue/ref-transform" "3.2.20" + "@vue/shared" "3.2.20" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.20": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/compiler-ssr/download/@vue/compiler-ssr-3.2.20.tgz#9cceb6261d9932cb5568202610c1c28f86c5e521" + integrity sha1-nM62Jh2ZMstVaCAmEMHCj4bF5SE= + dependencies: + "@vue/compiler-dom" "3.2.20" + "@vue/shared" "3.2.20" + +"@vue/devtools-api@^6.0.0-beta.18": + version "6.0.0-beta.19" + resolved "https://registry.npmmirror.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.19.tgz#f8e88059daa424515992426a0c7ea5cde07e99bf" + integrity sha1-+OiAWdqkJFFZkkJqDH6lzeB+mb8= + +"@vue/reactivity@3.2.20", "@vue/reactivity@^3.2.19": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/reactivity/download/@vue/reactivity-3.2.20.tgz#81fe1c368e7f20bc0ec1dec1045bbee253582de8" + integrity sha1-gf4cNo5/ILwOwd7BBFu+4lNYLeg= + dependencies: + "@vue/shared" "3.2.20" + +"@vue/ref-transform@3.2.20": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/ref-transform/download/@vue/ref-transform-3.2.20.tgz#2a59ec90caf8e5c7336776a0900bff0a8b81c090" + integrity sha1-KlnskMr45cczZ3agkAv/CouBwJA= + dependencies: + "@babel/parser" "^7.15.0" + "@vue/compiler-core" "3.2.20" + "@vue/shared" "3.2.20" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/runtime-core@3.2.20": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/runtime-core/download/@vue/runtime-core-3.2.20.tgz#8f63e956a3f88fb772541443c45a7701211012cb" + integrity sha1-j2PpVqP4j7dyVBRDxFp3ASEQEss= + dependencies: + "@vue/reactivity" "3.2.20" + "@vue/shared" "3.2.20" + +"@vue/runtime-dom@3.2.20": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/runtime-dom/download/@vue/runtime-dom-3.2.20.tgz#8aa56ae6c30f9cd4a71ca0e9ec3c4bdc67148d15" + integrity sha1-iqVq5sMPnNSnHKDp7DxL3GcUjRU= + dependencies: + "@vue/runtime-core" "3.2.20" + "@vue/shared" "3.2.20" + csstype "^2.6.8" + +"@vue/server-renderer@3.2.20", "@vue/server-renderer@^3.1.1", "@vue/server-renderer@^3.2.1": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/server-renderer/download/@vue/server-renderer-3.2.20.tgz#705e07ae9425132b2b6227d308a51a13f4d4ec81" + integrity sha1-cF4HrpQlEysrYifTCKUaE/TU7IE= + dependencies: + "@vue/compiler-ssr" "3.2.20" + "@vue/shared" "3.2.20" + +"@vue/shared@3.2.20", "@vue/shared@^3.2.19": + version "3.2.20" + resolved "https://registry.npmmirror.com/@vue/shared/download/@vue/shared-3.2.20.tgz#53746961f731a8ea666e3316271e944238dc31db" + integrity sha1-U3RpYfcxqOpmbjMWJx6UQjjcMds= + +"@vue/test-utils@^2.0.0-rc.9": + version "2.0.0-rc.16" + resolved "https://registry.npmmirror.com/@vue/test-utils/download/@vue/test-utils-2.0.0-rc.16.tgz#59380f02870f856ac002a29c02681d3f3fcbafeb" + integrity sha1-WTgPAocPhWrAAqKcAmgdPz/Lr+s= + +"@vuedx/analyze@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/analyze/download/@vuedx/analyze-0.4.1.tgz#9d5b888ee1b9a798794a44283100f8270bbb6e83" + integrity sha1-nVuIjuG5p5h5SkQoMQD4Jwu7boM= + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.12.7" + "@babel/traverse" "7.12.1" + "@babel/types" "7.12.1" + "@types/micromatch" "^4.0.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/compiler-tsx" "0.4.1" + "@vuedx/projectconfig" "0.4.1" + "@vuedx/template-ast-types" "0.4.1" + cli-highlight "^2.1.4" + commander "^6.1.0" + fast-glob "^3.2.4" + hash-sum "^2.0.0" + micromatch "^4.0.2" + +"@vuedx/compiler-sfc@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/compiler-sfc/download/@vuedx/compiler-sfc-0.4.1.tgz#e324bc9e0aaff8a4ddb35e40892a7d884f72f431" + integrity sha1-4yS8ngqv+KTds15AiSp9iE9y9DE= + dependencies: + "@vue/compiler-core" "^3.0.2" + lru-cache "^6.0.0" + source-map "^0.6.1" + +"@vuedx/compiler-tsx@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/compiler-tsx/download/@vuedx/compiler-tsx-0.4.1.tgz#c22b7632f7528bf7b3a4905ed1b932da49d4bf5c" + integrity sha1-wit2MvdSi/ezpJBe0bky2knUv1w= + dependencies: + "@babel/parser" "7.12.3" + "@babel/types" "7.12.1" + "@vue/compiler-core" "^3.0.1" + "@vuedx/template-ast-types" "0.4.1" + +"@vuedx/projectconfig@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/projectconfig/download/@vuedx/projectconfig-0.4.1.tgz#73db7ecf1ec38adc996d9180108d4b2ddde1d189" + integrity sha1-c9t+zx7DityZbZGAEI1LLd3h0Yk= + +"@vuedx/template-ast-types@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/template-ast-types/download/@vuedx/template-ast-types-0.4.1.tgz#5587b93ba0b2d4bf904f6e6cce76992860c0598a" + integrity sha1-VYe5O6Cy1L+QT25sznaZKGDAWYo= + dependencies: + "@vue/compiler-core" "^3.0.0" + +"@vuedx/typecheck@^0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/typecheck/download/@vuedx/typecheck-0.4.1.tgz#5235f6a464b3732c9481740d79e444a48bc58e06" + integrity sha1-UjX2pGSzcyyUgXQNeeREpIvFjgY= + dependencies: + "@vuedx/typescript-plugin-vue" "0.4.1" + "@vuedx/vue-virtual-textdocument" "0.4.1" + chalk "^4.1.0" + fast-glob "^3.2.4" + minimist "^1.2.5" + typescript "^4.0.3" + +"@vuedx/typescript-plugin-vue@0.4.1", "@vuedx/typescript-plugin-vue@^0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/typescript-plugin-vue/download/@vuedx/typescript-plugin-vue-0.4.1.tgz#5375ff9e25e1708d24a50b36bbb566a5fc82143f" + integrity sha1-U3X/niXhcI0kpQs2u7VmpfyCFD8= + dependencies: + "@intlify/core" "^9.0.0-beta.15" + "@vuedx/analyze" "0.4.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/projectconfig" "0.4.1" + "@vuedx/template-ast-types" "0.4.1" + "@vuedx/vue-virtual-textdocument" "0.4.1" + de-indent "^1.0.2" + json5 "^2.1.3" + quick-lru "^5.1.1" + vscode-uri "^2.1.2" + vscode-web-custom-data "^0.3.2" + +"@vuedx/vue-virtual-textdocument@0.4.1": + version "0.4.1" + resolved "https://registry.nlark.com/@vuedx/vue-virtual-textdocument/download/@vuedx/vue-virtual-textdocument-0.4.1.tgz#6d61dce6f71c71357ac3e9b5fc3b8d33e5fd4ea2" + integrity sha1-bWHc5vcccTV6w+m1/DuNM+X9TqI= + dependencies: + "@vuedx/analyze" "0.4.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/compiler-tsx" "0.4.1" + source-map "^0.6.1" + vscode-languageserver-textdocument "^1.0.1" + vscode-uri "^2.1.2" + +JSONStream@^1.0.4: + version "1.3.5" + resolved "https://registry.npm.taobao.org/JSONStream/download/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha1-MgjB8I06TZkmGrZPkjArwV4RHKA= + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.npm.taobao.org/abab/download/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha1-wLZ4+zLWD8EhnHhNaoJv44Wut5o= + +accepts@~1.3.5: + version "1.3.7" + resolved "https://registry.nlark.com/accepts/download/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha1-UxvHJlF6OytB+FACHGzBXqq1B80= + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.nlark.com/acorn-globals/download/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha1-Rs3Tnw+P8IqHZhm1X1rIptx3C0U= + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.nlark.com/acorn-jsx/download/acorn-jsx-5.3.2.tgz?cache=0&sync_timestamp=1625793627672&other_urls=https%3A%2F%2Fregistry.nlark.com%2Facorn-jsx%2Fdownload%2Facorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha1-ftW7VZCLOy8bxVxq8WU7rafweTc= + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.nlark.com/acorn-walk/download/acorn-walk-7.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Facorn-walk%2Fdownload%2Facorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w= + +acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo= + +acorn@^8.2.4: + version "8.5.0" + resolved "https://registry.nlark.com/acorn/download/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha1-RRLMuZs2mMdSWR6btEcuOK1DzuI= + +agent-base@6: + version "6.0.2" + resolved "https://registry.npm.taobao.org/agent-base/download/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c= + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/aggregate-error/download/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo= + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ= + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.6.3" + resolved "https://registry.nlark.com/ajv/download/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" + integrity sha1-EaZlJ3Ydw+mjhF6nddLTwEFOh2Q= + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +algoliasearch@^4.0.0: + version "4.10.5" + resolved "https://registry.npmmirror.com/algoliasearch/download/algoliasearch-4.10.5.tgz#1faf34a3ae5ac3bef27282eb141251c70c7f5db2" + integrity sha1-H680o65aw77ycoLrFBJRxwx/XbI= + dependencies: + "@algolia/cache-browser-local-storage" "4.10.5" + "@algolia/cache-common" "4.10.5" + "@algolia/cache-in-memory" "4.10.5" + "@algolia/client-account" "4.10.5" + "@algolia/client-analytics" "4.10.5" + "@algolia/client-common" "4.10.5" + "@algolia/client-personalization" "4.10.5" + "@algolia/client-search" "4.10.5" + "@algolia/logger-common" "4.10.5" + "@algolia/logger-console" "4.10.5" + "@algolia/requester-browser-xhr" "4.10.5" + "@algolia/requester-common" "4.10.5" + "@algolia/requester-node-http" "4.10.5" + "@algolia/transporter" "4.10.5" + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.nlark.com/ansi-colors/download/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha1-y7muJWv3UK8eqzRPIpqif+lLo0g= + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.nlark.com/ansi-escapes/download/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4= + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ= + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.nlark.com/ansi-regex/download/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha1-MYPjj66aZdfLXlOUXNWJfQJgoGo= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.nlark.com/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1618997040758&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0= + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1618997040758&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.nlark.com/ansi-styles/download/ansi-styles-5.2.0.tgz?cache=0&sync_timestamp=1618997040758&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s= + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.nlark.com/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz?cache=0&sync_timestamp=1617747544108&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha1-wFV8CWrzLxBhmPT04qODU343hxY= + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.nlark.com/argparse/download/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE= + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.nlark.com/argparse/download/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg= + +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/array-ify/download/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= + +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.npmmirror.com/array-includes/download/array-includes-3.1.4.tgz?cache=0&sync_timestamp=1633412407232&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Farray-includes%2Fdownload%2Farray-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha1-9bSTFix2DzU5Yx8AW6K7Rqy0W6k= + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.nlark.com/array-union/download/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha1-t5hCCtvrHego2ErNii4j0+/oXo0= + +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.npmmirror.com/array.prototype.flat/download/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha1-B+CXXYS7x8SM0YedYJ5oJZjTPhM= + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/arrify/download/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.npm.taobao.org/asap/download/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.npm.taobao.org/assert-never/download/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha1-EfDjY78UYgX7CBk7XHuQ9NHPRP4= + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/astral-regex/download/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha1-SDFDxWeu7UeFdZwIZXhtx319LjE= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/at-least-node/download/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha1-YCzUtG6EStTv/JKoARo8RuAjjcI= + +autoprefixer@^9.8.6: + version "9.8.8" + resolved "https://registry.npmmirror.com/autoprefixer/download/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha1-/UvUWVOF+m8GWZ3nSaTV96R0lXo= + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +babel-jest@^27.0.2, babel-jest@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/babel-jest/download/babel-jest-27.2.5.tgz?cache=0&sync_timestamp=1633701214958&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fbabel-jest%2Fdownload%2Fbabel-jest-27.2.5.tgz#6bbbc1bb4200fe0bfd1b1fbcbe02fc62ebed16aa" + integrity sha1-a7vBu0IA/gv9Gx+8vgL8YuvtFqo= + dependencies: + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^27.2.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.npm.taobao.org/babel-plugin-dynamic-import-node/download/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha1-hP2hnJduxcbe/vV/lCez3vZuF6M= + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.npm.taobao.org/babel-plugin-istanbul/download/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha1-4VnM3Jr5XgtXDHW0Vzt8NNZx12U= + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.2.0: + version "27.2.0" + resolved "https://registry.nlark.com/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277" + integrity sha1-efN9Q/flxP3Esso+EMxs9UViYnc= + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.2" + resolved "https://registry.nlark.com/babel-plugin-polyfill-corejs2/download/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" + integrity sha1-6RJHheb9lPlLYYp5VOVpMFO/Uyc= + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.5: + version "0.2.5" + resolved "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/download/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha1-J3mEahahZSJEriaLHpBq2hB/r5I= + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.16.2" + +babel-plugin-polyfill-regenerator@^0.2.2: + version "0.2.2" + resolved "https://registry.nlark.com/babel-plugin-polyfill-regenerator/download/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" + integrity sha1-sxDI1kKsraNIwfo7Pmzg6FG+4Hc= + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/babel-preset-current-node-syntax/download/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha1-tDmSObibKgEfndvj5PQB/EDP9zs= + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.2.0: + version "27.2.0" + resolved "https://registry.nlark.com/babel-preset-jest/download/babel-preset-jest-27.2.0.tgz#556bbbf340608fed5670ab0ea0c8ef2449fba885" + integrity sha1-VWu780Bgj+1WcKsOoMjvJEn7qIU= + dependencies: + babel-plugin-jest-hoist "^27.2.0" + babel-preset-current-node-syntax "^1.0.0" + +babel-walk@3.0.0-canary-5: + version "3.0.0-canary-5" + resolved "https://registry.npm.taobao.org/babel-walk/download/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" + integrity sha1-9m7Ncpg1eu5ElV8jWm71QhkQSxE= + dependencies: + "@babel/types" "^7.9.6" + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.nlark.com/bail/download/bail-1.0.5.tgz?cache=0&sync_timestamp=1621401842495&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbail%2Fdownload%2Fbail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha1-tvoTNASjksvB+MS/Y/WVM1Hnp3Y= + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz?cache=0&sync_timestamp=1617714343846&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbalanced-match%2Fdownload%2Fbalanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= + +balanced-match@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-2.0.0.tgz?cache=0&sync_timestamp=1617714343846&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbalanced-match%2Fdownload%2Fbalanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" + integrity sha1-3HD5INeNuLhYU1eVhnv0j4IGM9k= + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npm.taobao.org/base64-js/download/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo= + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/bl/download/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo= + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bl@^5.0.0: + version "5.0.0" + resolved "https://registry.npm.taobao.org/bl/download/bl-5.0.0.tgz#6928804a41e9da9034868e1c50ca88f21f57aea2" + integrity sha1-aSiASkHp2pA0ho4cUMqI8h9XrqI= + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/browser-process-hrtime/download/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha1-PJtLfXgsgSHlbxAQbYTA0P/JRiY= + +browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.17.3: + version "4.17.4" + resolved "https://registry.npmmirror.com/browserslist/download/browserslist-4.17.4.tgz?cache=0&sync_timestamp=1634137893850&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.17.4.tgz#72e2508af2a403aec0a49847ef31bd823c57ead4" + integrity sha1-cuJQivKkA67ApJhH7zG9gjxX6tQ= + dependencies: + caniuse-lite "^1.0.30001265" + electron-to-chromium "^1.3.867" + escalade "^3.1.1" + node-releases "^2.0.0" + picocolors "^1.0.0" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha1-5nh9og7OnQeZhTPP2d5vXDj0vAU= + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.nlark.com/buffer-from/download/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U= + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npm.taobao.org/buffer/download/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA= + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npm.taobao.org/buffer/download/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha1-Ks5XhFnMj74qcKqo9S7mO2p0xsY= + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/call-bind/download/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw= + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.nlark.com/callsites/download/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M= + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.npmmirror.com/camelcase-keys/download/camelcase-keys-6.2.2.tgz?cache=0&sync_timestamp=1633332959770&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcamelcase-keys%2Fdownload%2Fcamelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha1-XnVda6UaoiPsfT1S8ld4IQ+dw8A= + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA= + +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha1-kkr4gcnVJaydh/QNlk5c6pgqGAk= + +caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001265: + version "1.0.30001267" + resolved "https://registry.npmmirror.com/caniuse-lite/download/caniuse-lite-1.0.30001267.tgz?cache=0&sync_timestamp=1634187660404&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcaniuse-lite%2Fdownload%2Fcaniuse-lite-1.0.30001267.tgz#b1cf2937175afc0570e4615fc2d2f9069fa0ed30" + integrity sha1-sc8pNxda/AVw5GFfwtL5Bp+g7TA= + +chalk@*, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.nlark.com/chalk/download/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@4.1.0: + version "4.1.0" + resolved "https://registry.nlark.com/chalk/download/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha1-ThSHCmGNni7dl92DRf2dncMVZGo= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.nlark.com/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ= + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/char-regex/download/char-regex-1.0.2.tgz?cache=0&sync_timestamp=1622809452827&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchar-regex%2Fdownload%2Fchar-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha1-10Q1giYhf5ge1Y9Hmx1rzClUXc8= + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.nlark.com/character-entities-legacy/download/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha1-lLwYRdznClu50uzHSHJWYSk9j8E= + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.npm.taobao.org/character-entities/download/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha1-4Sw5Obfq9OWxXnrUxeKOHUjFsWs= + +character-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.npm.taobao.org/character-parser/download/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" + integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= + dependencies: + is-regex "^1.0.3" + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.npm.taobao.org/character-reference-invalid/download/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha1-CDMpzaDq4nKrPbvzfpo4LBOvFWA= + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npm.taobao.org/chardet/download/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha1-kAlISfCTfy7twkJdDSip5fDLrZ4= + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.2" + resolved "https://registry.nlark.com/chokidar/download/chokidar-3.5.2.tgz?cache=0&sync_timestamp=1623763831685&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchokidar%2Fdownload%2Fchokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha1-26OXb8rbAW9m/TZQIdkWANAcHnU= + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/ci-info/download/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y= + +ci-info@^3.1.1: + version "3.2.0" + resolved "https://registry.nlark.com/ci-info/download/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" + integrity sha1-KHbLlIpJh5e1I28AlbwFfQ3KOLY= + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.nlark.com/cjs-module-lexer/download/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha1-n4S6MkSlEvOlTlJ36O70xImGTkA= + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha1-7oRy27Ep5yezHooQpCfe6d/kAIs= + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/cli-cursor/download/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha1-JkMFp65JDR0Dvwybp8kl0XU68wc= + dependencies: + restore-cursor "^3.1.0" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/cli-cursor/download/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha1-POz+NzS/T+Aqg2HL3A9v4oxqV+o= + dependencies: + restore-cursor "^4.0.0" + +cli-highlight@^2.1.4: + version "2.1.11" + resolved "https://registry.npm.taobao.org/cli-highlight/download/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha1-SXNvpFLwqvT65YDjCssmgo0twb8= + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.6.0: + version "2.6.1" + resolved "https://registry.npmmirror.com/cli-spinners/download/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha1-rclU6+KBw3pjGb+kAebdJIj/tw0= + +cli-truncate@2.1.0, cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/cli-truncate/download/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha1-w54ovwXtzeW+O5iZKiLe7Vork8c= + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/cli-width/download/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha1-ovSEN6LKqaIkNueUvwceyeYc7fY= + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/cliui/download/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE= + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmmirror.com/cliui/download/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08= + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-regexp@^2.1.0: + version "2.2.0" + resolved "https://registry.nlark.com/clone-regexp/download/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" + integrity sha1-fWXgCIXNh5ZAXDWnN+eoa3Qp428= + dependencies: + is-regexp "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npm.taobao.org/clone/download/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/collect-v8-coverage/download/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha1-zCyOlPwYu9/+ZNZTRXDIpnOyf1k= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg= + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.nlark.com/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.nlark.com/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= + +colorette@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/colorette/download/colorette-1.4.0.tgz?cache=0&sync_timestamp=1633673439846&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcolorette%2Fdownload%2Fcolorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha1-UZD7uHJ2JZqGrXAL/yxtb6o/ykA= + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.nlark.com/combined-stream/download/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha1-w9RaizT9cwYxoRCoolIGgrMdWn8= + dependencies: + delayed-stream "~1.0.0" + +commander@*, commander@^8.1.0, commander@^8.2.0: + version "8.2.0" + resolved "https://registry.nlark.com/commander/download/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" + integrity sha1-N/4r3jAdh9R6U63v+LWRXbE4HKg= + +commander@^6.1.0: + version "6.2.1" + resolved "https://registry.nlark.com/commander/download/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha1-B5LraC37wyWZm7K4T93duhEKxzw= + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.nlark.com/commander/download/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc= + +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/compare-func/download/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + integrity sha1-+2XnXtvd/S5WhVTotbBf/3pR/LM= + dependencies: + array-ify "^1.0.0" + dot-prop "^5.1.0" + +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.npm.taobao.org/compare-versions/download/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha1-GlaJkTaF5ah2N7jT/8p1UU7EHWI= + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.npm.taobao.org/compressible/download/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o= + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.nlark.com/compression/download/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48= + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.nlark.com/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +constantinople@^4.0.1: + version "4.0.1" + resolved "https://registry.npm.taobao.org/constantinople/download/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" + integrity sha1-De8RP6Dk3I3oMzGlz3nIsyUhMVE= + dependencies: + "@babel/parser" "^7.6.0" + "@babel/types" "^7.6.1" + +conventional-changelog-angular@^5.0.0: + version "5.0.13" + resolved "https://registry.nlark.com/conventional-changelog-angular/download/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" + integrity sha1-iWiF1juRSnDUk0tZ0v573hgysow= + dependencies: + compare-func "^2.0.0" + q "^1.5.1" + +conventional-changelog-conventionalcommits@^4.3.1: + version "4.6.1" + resolved "https://registry.nlark.com/conventional-changelog-conventionalcommits/download/conventional-changelog-conventionalcommits-4.6.1.tgz#f4c0921937050674e578dc7875f908351ccf4014" + integrity sha1-9MCSGTcFBnTleNx4dfkINRzPQBQ= + dependencies: + compare-func "^2.0.0" + lodash "^4.17.15" + q "^1.5.1" + +conventional-commits-parser@^3.0.0: + version "3.2.2" + resolved "https://registry.nlark.com/conventional-commits-parser/download/conventional-commits-parser-3.2.2.tgz#190fb9900c6e02be0c0bca9b03d57e24982639fd" + integrity sha1-GQ+5kAxuAr4MC8qbA9V+JJgmOf0= + dependencies: + JSONStream "^1.0.4" + is-text-path "^1.0.1" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.nlark.com/convert-source-map/download/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha1-8zc8MtIbTXgN2ABFFGhPt5HKQ2k= + dependencies: + safe-buffer "~5.1.1" + +core-js-compat@^3.16.0, core-js-compat@^3.16.2: + version "3.18.3" + resolved "https://registry.npmmirror.com/core-js-compat/download/core-js-compat-3.18.3.tgz#e0e7e87abc55efb547e7fa19169e45fa9df27a67" + integrity sha1-4OfoerxV77VH5/oZFp5F+p3yemc= + dependencies: + browserslist "^4.17.3" + semver "7.0.0" + +core-js@^3.6.1: + version "3.18.3" + resolved "https://registry.npmmirror.com/core-js/download/core-js-3.18.3.tgz#86a0bba2d8ec3df860fefcc07a8d119779f01509" + integrity sha1-hqC7otjsPfhg/vzAeo0Rl3nwFQk= + +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.nlark.com/cosmiconfig/download/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha1-cU11ZSLKzoZ4Z8y0R0xdAbuuXW0= + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.nlark.com/cross-spawn/download/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.nlark.com/css-select/download/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha1-pwRA9wMX8maRGK10/xBeZYSccGc= + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.nlark.com/css-tree/download/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha1-60hw+2/XcHMn7JXC/yqwm16NuR0= + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^5.0.0: + version "5.1.0" + resolved "https://registry.npmmirror.com/css-what/download/css-what-5.1.0.tgz?cache=0&sync_timestamp=1633864304429&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcss-what%2Fdownload%2Fcss-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha1-P3tweq32M7r2LCzrhXm1RbtA9/4= + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4= + +csso@^4.2.0: + version "4.2.0" + resolved "https://registry.nlark.com/csso/download/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha1-6jpWE0bo3J9UbW/r7dUBh884lSk= + dependencies: + css-tree "^1.1.2" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.nlark.com/cssom/download/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha1-WmbPk9LQtmHYC/akT7ZfXC5OChA= + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.nlark.com/cssom/download/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o= + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.npm.taobao.org/cssstyle/download/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha1-/2ZaDdvcMYZLCWR/NBY0Q9kLCFI= + dependencies: + cssom "~0.3.6" + +csstype@^2.6.8: + version "2.6.18" + resolved "https://registry.nlark.com/csstype/download/csstype-2.6.18.tgz#980a8b53085f34af313410af064f2bd241784218" + integrity sha1-mAqLUwhfNK8xNBCvBk8r0kF4Qhg= + +dargs@^7.0.0: + version "7.0.0" + resolved "https://registry.nlark.com/dargs/download/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" + integrity sha1-BAFcQd4Ly2nshAUPPZvgyvjW1cw= + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/data-urls/download/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha1-FWSFpyljqXD11YIar2Qr7yvy25s= + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= + +debug@2.6.9, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.nlark.com/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1625448964720&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8= + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.2" + resolved "https://registry.nlark.com/debug/download/debug-4.3.2.tgz?cache=0&sync_timestamp=1625448964720&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha1-8KScGKyHeeMdSgxgKd+3aHPHQos= + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.nlark.com/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1625448964720&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o= + dependencies: + ms "^2.1.1" + +decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/decamelize-keys/download/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/decamelize/download/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.nlark.com/decimal.js/download/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha1-2MOkRKnGd0umDKatcmHDqU/V54M= + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.nlark.com/dedent/download/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.nlark.com/deep-is/download/deep-is-0.1.4.tgz?cache=0&sync_timestamp=1630774582016&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdeep-is%2Fdownload%2Fdeep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE= + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.nlark.com/deepmerge/download/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha1-RNLqNnm49NT/ujPwPYZfwee/SVU= + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE= + dependencies: + object-keys "^1.0.12" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/download/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/detect-newline/download/detect-newline-3.1.0.tgz?cache=0&sync_timestamp=1634200980351&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdetect-newline%2Fdownload%2Fdetect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha1-V29d/GOuGhkv8ZLYrTr2MImRtlE= + +diacritics@^1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/diacritics/download/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" + integrity sha1-PvqHMj67hj5mls67AILUj/PW96E= + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.nlark.com/diff-sequences/download/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha1-SLqZFX3hkjQS7tQdtrbUqpynwLE= + +diff-sequences@^27.0.6: + version "27.0.6" + resolved "https://registry.nlark.com/diff-sequences/download/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" + integrity sha1-MwXLLlWgM5JAVGlcxmAZ/X+OVyM= + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npm.taobao.org/dir-glob/download/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8= + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/doctrine/download/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha1-XNAfwQFiG0LEzX9dGmYkNxbT850= + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha1-rd6+rXKmV023g2OdyHoSF3OXOWE= + dependencies: + esutils "^2.0.2" + +doctypes@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/doctypes/download/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" + integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.nlark.com/dom-serializer/download/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha1-GvuB9TNxcXXUeGVd68XjMtn5u1E= + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.nlark.com/dom-serializer/download/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha1-YgZDfTLO767HFhgDIwx6ILwbTZE= + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@1, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.nlark.com/domelementtype/download/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8= + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.nlark.com/domelementtype/download/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc= + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/domexception/download/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha1-+0Su+6eT4VdLCvau0oAdBXUp8wQ= + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.nlark.com/domhandler/download/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha1-iAUJfpM9ZehVRvcm1g9euItE+AM= + dependencies: + domelementtype "1" + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.2" + resolved "https://registry.nlark.com/domhandler/download/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + integrity sha1-6CXXIdGahrjCAaNSZOImxnjudV8= + dependencies: + domelementtype "^2.2.0" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.nlark.com/domutils/download/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.nlark.com/domutils/download/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha1-RDfe9dtuLR9dbuhZvZXKfQIEgTU= + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-prop@^5.1.0: + version "5.3.0" + resolved "https://registry.nlark.com/dot-prop/download/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha1-kMzOcIzZzYLMTcjD3dmr3VWyDog= + dependencies: + is-obj "^2.0.0" + +electron-to-chromium@^1.3.867: + version "1.3.870" + resolved "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.3.870.tgz?cache=0&sync_timestamp=1634264440552&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.870.tgz#c15c921e66a46985181b261f8093b91c2abb6604" + integrity sha1-wVySHmakaYUYGyYfgJO5HCq7ZgQ= + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.nlark.com/emittery/download/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha1-uyPMhtA7MKp1p/c0gZ3uLhunCGA= + +emmet@^2.3.0: + version "2.3.4" + resolved "https://registry.nlark.com/emmet/download/emmet-2.3.4.tgz#5ba0d7a5569a68c7697dfa890c772e4f3179d123" + integrity sha1-W6DXpVaaaMdpffqJDHcuTzF50SM= + dependencies: + "@emmetio/abbreviation" "^2.2.2" + "@emmetio/css-abbreviation" "^2.1.4" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1632752084095&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= + +enquirer@^2.3.5, enquirer@^2.3.6: + version "2.3.6" + resolved "https://registry.npm.taobao.org/enquirer/download/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00= + dependencies: + ansi-colors "^4.1.1" + +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.nlark.com/entities/download/entities-1.1.2.tgz?cache=0&sync_timestamp=1628508343197&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fentities%2Fdownload%2Fentities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha1-vfpzUplmTfr9NFKe1PhSKidf6lY= + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.nlark.com/entities/download/entities-2.2.0.tgz?cache=0&sync_timestamp=1628508343197&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fentities%2Fdownload%2Fentities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU= + +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.nlark.com/entities/download/entities-2.1.0.tgz?cache=0&sync_timestamp=1628508343197&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fentities%2Fdownload%2Fentities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha1-mS0xKc999ocLlsV4WMJJoSD4uLU= + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha1-tKxAZIEH/c3PriQvQovqihTU8b8= + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.npmmirror.com/es-abstract/download/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha1-1IhXlodpFpWd547aoN9FZicRXsM= + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo= + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +esbuild-android-arm64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-android-arm64/download/esbuild-android-arm64-0.13.6.tgz#a109b4e5203e9ec144cadccdf18a5daf021423e5" + integrity sha1-oQm05SA+nsFEytzN8YpdrwIUI+U= + +esbuild-darwin-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-darwin-64/download/esbuild-darwin-64-0.13.6.tgz#1a00ef4d2b3b1fe9de28a5cf195df113d6461155" + integrity sha1-GgDvTSs7H+neKKXPGV3xE9ZGEVU= + +esbuild-darwin-arm64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/download/esbuild-darwin-arm64-0.13.6.tgz#f48954d441059e2d06c1675ddcc25af00b164935" + integrity sha1-9IlU1EEFni0GwWdd3MJa8AsWSTU= + +esbuild-freebsd-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-freebsd-64/download/esbuild-freebsd-64-0.13.6.tgz#b3bfea7e21f0d80796220927118fc76170cac06f" + integrity sha1-s7/qfiHw2AeWIgknEY/HYXDKwG8= + +esbuild-freebsd-arm64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/download/esbuild-freebsd-arm64-0.13.6.tgz#e6f5777a85012457ada049fc6b1e3e2c36161514" + integrity sha1-5vV3eoUBJFetoEn8ax4+LDYWFRQ= + +esbuild-linux-32@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-32/download/esbuild-linux-32-0.13.6.tgz#8b04058312a76faec6964b954f1f02ab32ce43fe" + integrity sha1-iwQFgxKnb67GlkuVTx8CqzLOQ/4= + +esbuild-linux-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-64/download/esbuild-linux-64-0.13.6.tgz#554d8edfe3f791f8b26978eb173b2e13643442c0" + integrity sha1-VU2O3+P3kfiyaXjrFzsuE2Q0QsA= + +esbuild-linux-arm64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-arm64/download/esbuild-linux-arm64-0.13.6.tgz#2142fadbdbc0ebd52a166f956f0ecb1f6602112a" + integrity sha1-IUL629vA69UqFm+Vbw7LH2YCESo= + +esbuild-linux-arm@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-arm/download/esbuild-linux-arm-0.13.6.tgz#ced8e35a94e0adbf134e5fa4e2b661f897e14b27" + integrity sha1-ztjjWpTgrb8TTl+k4rZh+JfhSyc= + +esbuild-linux-mips64le@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/download/esbuild-linux-mips64le-0.13.6.tgz#e5cbc050f5d44f8ecc0f79b1641bbad3919a2b3a" + integrity sha1-5cvAUPXUT47MD3mxZBu605GaKzo= + +esbuild-linux-ppc64le@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/download/esbuild-linux-ppc64le-0.13.6.tgz#57868a7eb762c1d19fa6d367b09a4610f0cbf7ca" + integrity sha1-V4aKfrdiwdGfptNnsJpGEPDL98o= + +esbuild-netbsd-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-netbsd-64/download/esbuild-netbsd-64-0.13.6.tgz#1c5daa62571f1065e4a1100a1db5e488ef259024" + integrity sha1-HF2qYlcfEGXkoRAKHbXkiO8lkCQ= + +esbuild-openbsd-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-openbsd-64/download/esbuild-openbsd-64-0.13.6.tgz#315fd85970365835f6a1eb7b6e9335d59f772564" + integrity sha1-MV/YWXA2WDX2oet7bpM11Z93JWQ= + +esbuild-register@^2.6.0: + version "2.6.0" + resolved "https://registry.nlark.com/esbuild-register/download/esbuild-register-2.6.0.tgz#9f19a54c82be751dd87673d6a66d7b9e1cdd8498" + integrity sha1-nxmlTIK+dR3YdnPWpm17nhzdhJg= + dependencies: + esbuild "^0.12.8" + jsonc-parser "^3.0.0" + +esbuild-sunos-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-sunos-64/download/esbuild-sunos-64-0.13.6.tgz#8422eeb9f3712daa4befd19e5da6d7c9af9fc744" + integrity sha1-hCLuufNxLapL79GeXabXya+fx0Q= + +esbuild-windows-32@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-windows-32/download/esbuild-windows-32-0.13.6.tgz#694eb4768ee72219d3bc6415b1d3a0f843aea9ec" + integrity sha1-aU60do7nIhnTvGQVsdOg+EOuqew= + +esbuild-windows-64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-windows-64/download/esbuild-windows-64-0.13.6.tgz#1adbf5367b08e735262f57098d19c07d0a2fec1c" + integrity sha1-Gtv1NnsI5zUmL1cJjRnAfQov7Bw= + +esbuild-windows-arm64@0.13.6: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild-windows-arm64/download/esbuild-windows-arm64-0.13.6.tgz#9279083740ec90a2d638485c97b1d003771d685a" + integrity sha1-knkIN0DskKLWOEhcl7HQA3cdaFo= + +esbuild@^0.12.8: + version "0.12.29" + resolved "https://registry.npmmirror.com/esbuild/download/esbuild-0.12.29.tgz#be602db7c4dc78944a9dbde0d1ea19d36c1f882d" + integrity sha1-vmAtt8TceJRKnb3g0eoZ02wfiC0= + +esbuild@^0.13.2: + version "0.13.6" + resolved "https://registry.npmmirror.com/esbuild/download/esbuild-0.13.6.tgz#b9be288108d47e814a6c8729e495dce0fddbf441" + integrity sha1-ub4ogQjUfoFKbIcp5JXc4P3b9EE= + optionalDependencies: + esbuild-android-arm64 "0.13.6" + esbuild-darwin-64 "0.13.6" + esbuild-darwin-arm64 "0.13.6" + esbuild-freebsd-64 "0.13.6" + esbuild-freebsd-arm64 "0.13.6" + esbuild-linux-32 "0.13.6" + esbuild-linux-64 "0.13.6" + esbuild-linux-arm "0.13.6" + esbuild-linux-arm64 "0.13.6" + esbuild-linux-mips64le "0.13.6" + esbuild-linux-ppc64le "0.13.6" + esbuild-netbsd-64 "0.13.6" + esbuild-openbsd-64 "0.13.6" + esbuild-sunos-64 "0.13.6" + esbuild-windows-32 "0.13.6" + esbuild-windows-64 "0.13.6" + esbuild-windows-arm64 "0.13.6" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.nlark.com/escalade/download/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA= + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha1-owME6Z2qMuI7L9IPUbq9B8/8o0Q= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ= + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/escodegen/download/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha1-XjKxKDPoqo+jXhvwvvqJOASEx90= + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.nlark.com/eslint-import-resolver-node/download/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha1-QEi5WDldqJZoJSAB29nsprg7rL0= + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.0: + version "2.7.1" + resolved "https://registry.npmmirror.com/eslint-module-utils/download/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha1-tDUAHJ+N1Kt/bQ78rkuWltTCS3w= + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.24.2: + version "2.25.2" + resolved "https://registry.npmmirror.com/eslint-plugin-import/download/eslint-plugin-import-2.25.2.tgz#b3b9160efddb702fc1636659e71ba1d10adbe9e9" + integrity sha1-s7kWDv3bcC/BY2ZZ5xuh0Qrb6ek= + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.0" + has "^1.0.3" + is-core-module "^2.7.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.11.0" + +eslint-plugin-vue@^7.11.1: + version "7.19.1" + resolved "https://registry.npmmirror.com/eslint-plugin-vue/download/eslint-plugin-vue-7.19.1.tgz?cache=0&sync_timestamp=1633510874321&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-plugin-vue%2Fdownload%2Feslint-plugin-vue-7.19.1.tgz#435fb2ce712842a9530b28eacb883680e8eaa4f3" + integrity sha1-Q1+yznEoQqlTCyjqy4g2gOjqpPM= + dependencies: + eslint-utils "^2.1.0" + natural-compare "^1.4.0" + semver "^6.3.0" + vue-eslint-parser "^7.10.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/eslint-scope/download/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw= + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.nlark.com/eslint-utils/download/eslint-utils-2.1.0.tgz?cache=0&sync_timestamp=1620976029755&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-utils%2Fdownload%2Feslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc= + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/eslint-utils/download/eslint-utils-3.0.0.tgz?cache=0&sync_timestamp=1620976029755&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-utils%2Fdownload%2Feslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha1-iuuvrOc0W7M1WdsKHxOh0tSMNnI= + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha1-MOvR73wv3/AcOk8VEESvJfqwUj4= + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha1-9lMoJZMFknOSyTjtROsKXJsr0wM= + +eslint@^7.28.0: + version "7.32.0" + resolved "https://registry.npmmirror.com/eslint/download/eslint-7.32.0.tgz?cache=0&sync_timestamp=1634180140384&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint%2Fdownload%2Feslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha1-xtMooUvj+wjI0dIeEsAv23oqgS0= + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.2.1: + version "6.2.1" + resolved "https://registry.nlark.com/espree/download/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o= + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.nlark.com/espree/download/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha1-8t8zC3Usb1UBn4vYm3ZgA5wbu7Y= + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.nlark.com/esprima/download/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha1-E7BM2z5sXRnfkatph6hpVhmwqnE= + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/esquery/download/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha1-IUj/w4uC6McFff7UhCWz5h8PJKU= + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha1-eteWTWeauyi+5yzsY3WLHF0smSE= + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0= + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/estraverse/download/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha1-MH30JUfmzHMk088DwVXVzbjFOIA= + +estree-walker@^2.0.1, estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npm.taobao.org/estree-walker/download/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw= + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q= + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.nlark.com/execa/download/execa-5.1.1.tgz?cache=0&sync_timestamp=1622853848914&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexeca%2Fdownload%2Fexeca-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0= + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execall@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/execall/download/execall-2.0.0.tgz?cache=0&sync_timestamp=1617893186184&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexecall%2Fdownload%2Fexecall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" + integrity sha1-FqBrX+UJnffQC+XZwG7s3tFmO0U= + dependencies: + clone-regexp "^2.1.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/expect/download/expect-27.2.5.tgz?cache=0&sync_timestamp=1633701217097&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fexpect%2Fdownload%2Fexpect-27.2.5.tgz#16154aaa60b4d9a5b0adacfea3e4d6178f4b93fd" + integrity sha1-FhVKqmC02aWwraz+o+TWF49Lk/0= + dependencies: + "@jest/types" "^27.2.5" + ansi-styles "^5.0.0" + jest-get-type "^27.0.6" + jest-matcher-utils "^27.2.5" + jest-message-util "^27.2.5" + jest-regex-util "^27.0.6" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.nlark.com/extend/download/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo= + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npm.taobao.org/external-editor/download/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha1-ywP3QL764D6k0oPK7SdBqD8zVJU= + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU= + +fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.5: + version "3.2.7" + resolved "https://registry.nlark.com/fast-glob/download/fast-glob-3.2.7.tgz?cache=0&sync_timestamp=1625795502965&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffast-glob%2Fdownload%2Ffast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha1-/Wy3otfpqnp4RhEehaGW1rL3ZqE= + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM= + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastest-levenshtein@^1.0.12: + version "1.0.12" + resolved "https://registry.nlark.com/fastest-levenshtein/download/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" + integrity sha1-mZD306iMxan/0fF0V0UlFwDUl+I= + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.nlark.com/fastq/download/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha1-YWdg+Ip1Jr38WWt8q4wYk4w2uYw= + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/fb-watchman/download/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha1-/IT7OdJwnPP/bXQ3BhV7tXCKioU= + dependencies: + bser "2.1.1" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.nlark.com/figures/download/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha1-IRst2WWcsDlLBz5zI6w8kz1SICc= + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.nlark.com/fill-range/download/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= + dependencies: + to-regex-range "^5.0.1" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/find-up/download/find-up-2.1.0.tgz?cache=0&sync_timestamp=1633618879668&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffind-up%2Fdownload%2Ffind-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1633618879668&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk= + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/find-up/download/find-up-5.0.0.tgz?cache=0&sync_timestamp=1633618879668&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffind-up%2Fdownload%2Ffind-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw= + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/find-versions/download/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha1-PFflc7+XdpuMuN8Wk0tieRXaSWU= + dependencies: + semver-regex "^3.1.2" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npm.taobao.org/flat-cache/download/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha1-YbAzgwKy/p+Vfcwy/CqH8cMEixE= + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.2" + resolved "https://registry.nlark.com/flatted/download/flatted-3.2.2.tgz?cache=0&sync_timestamp=1627541754031&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fflatted%2Fdownload%2Fflatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha1-ZL/tXLaP48p4s+shStl7Y77c5WE= + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.npm.taobao.org/form-data/download/form-data-3.0.1.tgz?cache=0&sync_timestamp=1613411017277&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fform-data%2Fdownload%2Fform-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha1-69U3kbeDVqma+aMA1CgsTV65dV8= + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.nlark.com/fs-extra/download/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha1-WVRGDHZKjaIJS6NVS/g55rmnyG0= + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.nlark.com/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0= + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.nlark.com/gensync/download/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA= + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34= + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/get-intrinsic/download/get-intrinsic-1.1.1.tgz?cache=0&sync_timestamp=1612364745563&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-intrinsic%2Fdownload%2Fget-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y= + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.npmmirror.com/get-own-enumerable-property-symbols/download/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha1-tf3nfyLL4185C04ImSLFC85u9mQ= + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npm.taobao.org/get-package-type/download/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha1-jeLYA8/0TfO8bEVuZmizbDkm4Ro= + +get-stdin@8.0.0, get-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.npm.taobao.org/get-stdin/download/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + integrity sha1-y61qc/63X27rIrqeAfiaooqpelM= + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.nlark.com/get-stream/download/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha1-omLY7vZ6ztV8KFKtYWdSakPL97c= + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/get-symbol-description/download/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha1-f9uByQAQH71WTdXxowr1qtweWNY= + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +git-raw-commits@^2.0.0: + version "2.0.10" + resolved "https://registry.npm.taobao.org/git-raw-commits/download/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" + integrity sha1-4iVe2VY7HJw+pr0FgGQQKQKXu8E= + dependencies: + dargs "^7.0.0" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/download/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ= + dependencies: + is-glob "^4.0.1" + +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.0" + resolved "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz?cache=0&sync_timestamp=1632354712536&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fglob%2Fdownload%2Fglob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha1-0VU1r3cy4C6Uj0xBYovZECk/YCM= + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/global-dirs/download/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/global-modules/download/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha1-mXYFrSNF8n9RU5vqJldEISFcd4A= + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/global-prefix/download/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha1-/IX3MGTfafUEIfR/iD/luRO6m5c= + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.nlark.com/globals/download/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4= + +globals@^13.6.0, globals@^13.9.0: + version "13.11.0" + resolved "https://registry.nlark.com/globals/download/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" + integrity sha1-QO9njaEX/nvS4o8fqySVG9AlW+c= + dependencies: + type-fest "^0.20.2" + +globby@^11.0.2, globby@^11.0.3: + version "11.0.4" + resolved "https://registry.nlark.com/globby/download/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha1-LLr/d8Lypi5x6bKBOme5ejowAaU= + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.npm.taobao.org/globjoin/download/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" + integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= + +gonzales-pe@^4.3.0: + version "4.3.0" + resolved "https://registry.nlark.com/gonzales-pe/download/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha1-/p3sXzxVfurQn/hoxlgmvlTQZ7M= + dependencies: + minimist "^1.2.5" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.8" + resolved "https://registry.nlark.com/graceful-fs/download/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha1-5BK40z9eAGWTy9PO5t+fLOu+gCo= + +gray-matter@^4.0.3: + version "4.0.3" + resolved "https://registry.npmmirror.com/gray-matter/download/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha1-6JPAZIJd5z6h9ffYjHqfcnQoh5g= + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/hard-rejection/download/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha1-HG7aXBaFxjlCdm15u0Cudzzs2IM= + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/has-bigints/download/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha1-ZP5qywIGc+O3jbA1pa9pqp0HsRM= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/has-symbols/download/has-symbols-1.0.2.tgz?cache=0&sync_timestamp=1631809058290&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-symbols%2Fdownload%2Fhas-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM= + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/has-tostringtag/download/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha1-fhM4GKfTlHNPlB5zw9P5KR5liyU= + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.nlark.com/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y= + dependencies: + function-bind "^1.1.1" + +hash-sum@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/hash-sum/download/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" + integrity sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo= + +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.nlark.com/highlight.js/download/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha1-aXJy45kTVuQMPKxWanTu9oF1ZTE= + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.nlark.com/hosted-git-info/download/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k= + +hosted-git-info@^4.0.1: + version "4.0.2" + resolved "https://registry.nlark.com/hosted-git-info/download/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" + integrity sha1-XkJVB+7eT+qEa3Ji8IOEVsQgmWE= + dependencies: + lru-cache "^6.0.0" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.nlark.com/html-encoding-sniffer/download/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha1-QqbcT9M/ACgRduiyN1nKTk+hhfM= + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npm.taobao.org/html-escaper/download/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha1-39YAJ9o2o238viNiYsAKWCJoFFM= + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/html-tags/download/html-tags-3.1.0.tgz?cache=0&sync_timestamp=1612455116888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-tags%2Fdownload%2Fhtml-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha1-e15vfmZen7QfMAB+2eDUHpf7IUA= + +htmlparser2@^3.10.0: + version "3.10.1" + resolved "https://registry.nlark.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1631386311915&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha1-vWedw/WYl7ajS7EHSchVu1OpOS8= + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.nlark.com/htmlparser2/download/htmlparser2-6.1.0.tgz?cache=0&sync_timestamp=1631386311915&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha1-xNditsM3GgXb5l6UrkOp+EX7j7c= + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/http-proxy-agent/download/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha1-ioyO9/WTLM+VPClsqCkblap0qjo= + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/https-proxy-agent/download/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha1-4qkFQqu2inYuCghQ9sntrf2FBrI= + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.nlark.com/human-signals/download/human-signals-2.1.0.tgz?cache=0&sync_timestamp=1624364612113&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhuman-signals%2Fdownload%2Fhuman-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA= + +husky@^4.3.7: + version "4.3.8" + resolved "https://registry.nlark.com/husky/download/husky-4.3.8.tgz?cache=0&sync_timestamp=1629855107759&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhusky%2Fdownload%2Fhusky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha1-MRRAYL6WP9aFDlzI8Bmh3+GUKW0= + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^7.0.0" + find-versions "^4.0.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^5.0.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs= + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.nlark.com/ieee754/download/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I= + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw= + +ignore@^5.1.4, ignore@^5.1.8: + version "5.1.8" + resolved "https://registry.npm.taobao.org/ignore/download/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha1-8VCotQo0KJsz4i9YiavU2AFvDlc= + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha1-NxYsJfy566oublPVtNiM4X2eDCs= + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/import-lazy/download/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha1-6OtidIOgpD2jwD8+NVSL5csMwVM= + +import-local@^3.0.2: + version "3.0.3" + resolved "https://registry.npmmirror.com/import-local/download/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha1-TVHCxJXKk5PaJZ7Ga2LgIpICEeA= + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/indent-string/download/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.nlark.com/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= + +ini@^1.3.4, ini@^1.3.5: + version "1.3.8" + resolved "https://registry.npm.taobao.org/ini/download/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw= + +inquirer@^8.1.2: + version "8.2.0" + resolved "https://registry.npmmirror.com/inquirer/download/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha1-9E8AjdNEu/xLMAMfRdmE4DSjrDo= + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/internal-slot/download/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha1-c0fjB97uovqsKsYgXUvH00ln9Zw= + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.nlark.com/interpret/download/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha1-Zlq4vE2iendKQFhOgS4+D6RbGh4= + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.npm.taobao.org/is-alphabetical/download/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha1-nn1rlJFr4iFTdF0YTCmMv5hqaG0= + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.npm.taobao.org/is-alphanumerical/download/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha1-frmiQx+FX2se8aeOMm31FWlsTb8= + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.nlark.com/is-arrayish/download/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.nlark.com/is-bigint/download/is-bigint-1.0.4.tgz?cache=0&sync_timestamp=1628747605326&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-bigint%2Fdownload%2Fis-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha1-CBR6GHW8KzIAXUHM2Ckd/8ZpHfM= + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.nlark.com/is-boolean-object/download/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha1-XG3CACRt2TIa5LiFoRS7H3X2Nxk= + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.npm.taobao.org/is-buffer/download/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha1-68JS5ADSL/jXf6CYiIIaJKZYwZE= + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.nlark.com/is-callable/download/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha1-RzAdWN0CWUB4ZVR4U99tYf5HGUU= + +is-ci@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/is-ci/download/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" + integrity sha1-x+e+PJ2O730PoUQ5C9HkuI3EyZQ= + dependencies: + ci-info "^3.1.1" + +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.7.0: + version "2.8.0" + resolved "https://registry.npmmirror.com/is-core-module/download/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha1-AyEzbD0JJeSX/Zf12VyxFKXM1Ug= + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.nlark.com/is-date-object/download/is-date-object-1.0.5.tgz?cache=0&sync_timestamp=1628200237261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-date-object%2Fdownload%2Fis-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha1-CEHVU25yTCVZe/bqYuG9OCmN8x8= + dependencies: + has-tostringtag "^1.0.0" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.nlark.com/is-decimal/download/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha1-ZaOllYocW2OnBuGzM9fNn2MNP6U= + +is-expression@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/is-expression/download/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" + integrity sha1-wzFVliq/IdCv0lUlFNZ9LsFv0qs= + dependencies: + acorn "^7.1.1" + object-assign "^4.1.1" + +is-extendable@^0.1.0: + version "0.1.1" + resolved "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.nlark.com/is-generator-fn/download/is-generator-fn-2.1.0.tgz?cache=0&sync_timestamp=1628689179107&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-generator-fn%2Fdownload%2Fis-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha1-fRQK3DiarzARqPKipM+m+q3/sRg= + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/download/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ= + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.npm.taobao.org/is-hexadecimal/download/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha1-zDXJdYjaS9Saju3WvECC1E3LI6c= + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/is-interactive/download/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha1-zqbmrlyHCnsKAAQHC3tYfgJSkS4= + +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/is-interactive/download/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha1-QMV2FFk4JtoRAK3mBZd41ZfxbpA= + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha1-PedGwY3aIxkkGlNnWQjY92bxHCQ= + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.nlark.com/is-number-object/download/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha1-anqvg4x/BoalC0VT9+VKlklOifA= + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/is-obj/download/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/is-obj/download/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI= + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.nlark.com/is-plain-obj/download/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.nlark.com/is-plain-obj/download/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha1-ReQuN/zPH0Dajl927iFRWEDAkoc= + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/is-potential-custom-element-name/download/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha1-Fx7W8Z46xVQ5Tt94yqBXhKRb67U= + +is-promise@^2.0.0: + version "2.2.2" + resolved "https://registry.npm.taobao.org/is-promise/download/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha1-OauVnMv5p3TPB597QMeib3YxNfE= + +is-regex@^1.0.3, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.nlark.com/is-regex/download/is-regex-1.1.4.tgz?cache=0&sync_timestamp=1628222322170&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-regex%2Fdownload%2Fis-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha1-7vVmPNWfpMCuM5UFMj32hUuxWVg= + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-regexp/download/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-regexp@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/is-regexp/download/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" + integrity sha1-zXNKVoZOI7lWv058ZsOWpMCyLC0= + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/is-shared-array-buffer/download/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha1-l7DIX72stZycRG/mU7gs8rW3z+Y= + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.nlark.com/is-stream/download/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha1-+sHj1TuXrVqdCunO8jifWBClwHc= + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.nlark.com/is-string/download/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha1-DdEr8gBvJVu1j2lREO/3SR7rwP0= + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.nlark.com/is-symbol/download/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha1-ptrJO2NbBjymhyI23oiRClevE5w= + dependencies: + has-symbols "^1.0.2" + +is-text-path@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/is-text-path/download/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" + integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= + dependencies: + text-extensions "^1.0.0" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/is-typedarray/download/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/download/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc= + +is-unicode-supported@^1.0.0, is-unicode-supported@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/download/is-unicode-supported-1.1.0.tgz#9127b71f9fa82f52ca5c20e982e7bec0ee31ee1e" + integrity sha1-kSe3H5+oL1LKXCDpgue+wO4x7h4= + +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/is-weakref/download/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha1-hC26TsF/qayYUN8tbvvBc3J08qI= + dependencies: + call-bind "^1.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +istanbul-lib-coverage@^3.0.0: + version "3.0.2" + resolved "https://registry.npmmirror.com/istanbul-lib-coverage/download/istanbul-lib-coverage-3.0.2.tgz#36786d4d82aad2ea5911007e255e2da6b5f80d86" + integrity sha1-NnhtTYKq0upZEQB+JV4tprX4DYY= + +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.npmmirror.com/istanbul-lib-instrument/download/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha1-hzxv/4l0UBGCIndGlqPyiQLXfB0= + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/istanbul-lib-report/download/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha1-dRj+UupE3jcvRgp2tezan/tz2KY= + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/istanbul-lib-source-maps/download/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha1-iV86cJ/PujTG3lpCk5Ai8+Q1hVE= + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.0.5" + resolved "https://registry.npmmirror.com/istanbul-reports/download/istanbul-reports-3.0.5.tgz#a2580107e71279ea6d661ddede929ffc6d693384" + integrity sha1-olgBB+cSeeptZh3e3pKf/G1pM4Q= + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-changed-files/download/jest-changed-files-27.2.5.tgz?cache=0&sync_timestamp=1633701209542&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-changed-files%2Fdownload%2Fjest-changed-files-27.2.5.tgz#9dfd550d158260bcb6fa80aff491f5647f7daeca" + integrity sha1-nf1VDRWCYLy2+oCv9JH1ZH99rso= + dependencies: + "@jest/types" "^27.2.5" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-circus/download/jest-circus-27.2.5.tgz#573256a6fb6e447ac2fc7e0ade9375013309037f" + integrity sha1-VzJWpvtuRHrC/H4K3pN1ATMJA38= + dependencies: + "@jest/environment" "^27.2.5" + "@jest/test-result" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.2.5" + is-generator-fn "^2.0.0" + jest-each "^27.2.5" + jest-matcher-utils "^27.2.5" + jest-message-util "^27.2.5" + jest-runtime "^27.2.5" + jest-snapshot "^27.2.5" + jest-util "^27.2.5" + pretty-format "^27.2.5" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-cli/download/jest-cli-27.2.5.tgz#88718c8f05f1c0f209152952ecd61afe4c3311bb" + integrity sha1-iHGMjwXxwPIJFSlS7NYa/kwzEbs= + dependencies: + "@jest/core" "^27.2.5" + "@jest/test-result" "^27.2.5" + "@jest/types" "^27.2.5" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.2.5" + jest-util "^27.2.5" + jest-validate "^27.2.5" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-config/download/jest-config-27.2.5.tgz#c2e4ec6ea2bf4ffd2cae3d927999fe6159cba207" + integrity sha1-wuTsbqK/T/0srj2SeZn+YVnLogc= + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^27.2.5" + "@jest/types" "^27.2.5" + babel-jest "^27.2.5" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + is-ci "^3.0.0" + jest-circus "^27.2.5" + jest-environment-jsdom "^27.2.5" + jest-environment-node "^27.2.5" + jest-get-type "^27.0.6" + jest-jasmine2 "^27.2.5" + jest-regex-util "^27.0.6" + jest-resolve "^27.2.5" + jest-runner "^27.2.5" + jest-util "^27.2.5" + jest-validate "^27.2.5" + micromatch "^4.0.4" + pretty-format "^27.2.5" + +jest-diff@^26.0.0: + version "26.6.2" + resolved "https://registry.npmmirror.com/jest-diff/download/jest-diff-26.6.2.tgz?cache=0&sync_timestamp=1633701200270&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-diff%2Fdownload%2Fjest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha1-GqdGi1LDpo19XF/c381eSb0WQ5Q= + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-diff@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-diff/download/jest-diff-27.2.5.tgz?cache=0&sync_timestamp=1633701200270&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-diff%2Fdownload%2Fjest-diff-27.2.5.tgz#908f7a6aca5653824516ad30e0a9fd9767e53623" + integrity sha1-kI96aspWU4JFFq0w4Kn9l2flNiM= + dependencies: + chalk "^4.0.0" + diff-sequences "^27.0.6" + jest-get-type "^27.0.6" + pretty-format "^27.2.5" + +jest-docblock@^27.0.6: + version "27.0.6" + resolved "https://registry.nlark.com/jest-docblock/download/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" + integrity sha1-zHgmas9/5pPKRiy72g6k5jnk5fM= + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-each/download/jest-each-27.2.5.tgz?cache=0&sync_timestamp=1633701212234&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-each%2Fdownload%2Fjest-each-27.2.5.tgz#378118d516db730b92096a9607b8711165946353" + integrity sha1-N4EY1RbbcwuSCWqWB7hxEWWUY1M= + dependencies: + "@jest/types" "^27.2.5" + chalk "^4.0.0" + jest-get-type "^27.0.6" + jest-util "^27.2.5" + pretty-format "^27.2.5" + +jest-environment-jsdom@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-environment-jsdom/download/jest-environment-jsdom-27.2.5.tgz?cache=0&sync_timestamp=1633701196279&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-environment-jsdom%2Fdownload%2Fjest-environment-jsdom-27.2.5.tgz#21de3ad0e89441d961b592ba7561b16241279208" + integrity sha1-Id460OiUQdlhtZK6dWGxYkEnkgg= + dependencies: + "@jest/environment" "^27.2.5" + "@jest/fake-timers" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.2.5" + jest-util "^27.2.5" + jsdom "^16.6.0" + +jest-environment-node@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-environment-node/download/jest-environment-node-27.2.5.tgz?cache=0&sync_timestamp=1633701217316&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-environment-node%2Fdownload%2Fjest-environment-node-27.2.5.tgz#ffa1afb3604c640ec841f044d526c65912e02cef" + integrity sha1-/6Gvs2BMZA7IQfBE1SbGWRLgLO8= + dependencies: + "@jest/environment" "^27.2.5" + "@jest/fake-timers" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.2.5" + jest-util "^27.2.5" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.nlark.com/jest-get-type/download/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha1-6X3Dw/U8K0Bsp6+u1Ek7HQmRmeA= + +jest-get-type@^27.0.6: + version "27.0.6" + resolved "https://registry.nlark.com/jest-get-type/download/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" + integrity sha1-DrXH91WFQnnOm2ip8aQSL2kEfP4= + +jest-haste-map@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-haste-map/download/jest-haste-map-27.2.5.tgz?cache=0&sync_timestamp=1633701211231&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-haste-map%2Fdownload%2Fjest-haste-map-27.2.5.tgz#0247b7299250643472bbcf5b4ad85c72d5178e2e" + integrity sha1-Ake3KZJQZDRyu89bSthcctUXji4= + dependencies: + "@jest/types" "^27.2.5" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.0.6" + jest-serializer "^27.0.6" + jest-util "^27.2.5" + jest-worker "^27.2.5" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-jasmine2/download/jest-jasmine2-27.2.5.tgz?cache=0&sync_timestamp=1633701222042&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-jasmine2%2Fdownload%2Fjest-jasmine2-27.2.5.tgz#baaf96c69913c52bce0100000cf0721027c0fd66" + integrity sha1-uq+WxpkTxSvOAQAADPByECfA/WY= + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^27.2.5" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.2.5" + is-generator-fn "^2.0.0" + jest-each "^27.2.5" + jest-matcher-utils "^27.2.5" + jest-message-util "^27.2.5" + jest-runtime "^27.2.5" + jest-snapshot "^27.2.5" + jest-util "^27.2.5" + pretty-format "^27.2.5" + throat "^6.0.1" + +jest-leak-detector@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-leak-detector/download/jest-leak-detector-27.2.5.tgz?cache=0&sync_timestamp=1633701213914&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-leak-detector%2Fdownload%2Fjest-leak-detector-27.2.5.tgz#e2edc3b37d38e8d9a527e10e456b403c3151b206" + integrity sha1-4u3Ds3046NmlJ+EORWtAPDFRsgY= + dependencies: + jest-get-type "^27.0.6" + pretty-format "^27.2.5" + +jest-matcher-utils@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-matcher-utils/download/jest-matcher-utils-27.2.5.tgz?cache=0&sync_timestamp=1633701215360&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-matcher-utils%2Fdownload%2Fjest-matcher-utils-27.2.5.tgz#4684faaa8eb32bf15e6edaead6834031897e2980" + integrity sha1-RoT6qo6zK/Febtrq1oNAMYl+KYA= + dependencies: + chalk "^4.0.0" + jest-diff "^27.2.5" + jest-get-type "^27.0.6" + pretty-format "^27.2.5" + +jest-message-util@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-message-util/download/jest-message-util-27.2.5.tgz?cache=0&sync_timestamp=1633701213604&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-message-util%2Fdownload%2Fjest-message-util-27.2.5.tgz#ed8b7b0965247bb875a49c1f9b9ab2d1d0820028" + integrity sha1-7Yt7CWUke7h1pJwfm5qy0dCCACg= + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.2.5" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.2.5" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-mock/download/jest-mock-27.2.5.tgz?cache=0&sync_timestamp=1633701210867&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-mock%2Fdownload%2Fjest-mock-27.2.5.tgz#0ec38d5ff1e49c4802e7a4a8179e8d7a2fd84de0" + integrity sha1-DsONX/HknEgC56SoF56Nei/YTeA= + dependencies: + "@jest/types" "^27.2.5" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.nlark.com/jest-pnp-resolver/download/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha1-twSsCuAoqJEIpNBAs/kZ393I4zw= + +jest-regex-util@^27.0.6: + version "27.0.6" + resolved "https://registry.nlark.com/jest-regex-util/download/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" + integrity sha1-AuESCCk1rpSc5dE7JnXbPYyH2cU= + +jest-resolve-dependencies@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-resolve-dependencies/download/jest-resolve-dependencies-27.2.5.tgz#fcd8eca005b3d11ba32da443045c028164b83be1" + integrity sha1-/NjsoAWz0RujLaRDBFwCgWS4O+E= + dependencies: + "@jest/types" "^27.2.5" + jest-regex-util "^27.0.6" + jest-snapshot "^27.2.5" + +jest-resolve@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-resolve/download/jest-resolve-27.2.5.tgz?cache=0&sync_timestamp=1633701214299&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-resolve%2Fdownload%2Fjest-resolve-27.2.5.tgz#04dadbfc1312a2541f5c199c5011945e9cfe5cef" + integrity sha1-BNrb/BMSolQfXBmcUBGUXpz+XO8= + dependencies: + "@jest/types" "^27.2.5" + chalk "^4.0.0" + escalade "^3.1.1" + graceful-fs "^4.2.4" + jest-haste-map "^27.2.5" + jest-pnp-resolver "^1.2.2" + jest-util "^27.2.5" + jest-validate "^27.2.5" + resolve "^1.20.0" + slash "^3.0.0" + +jest-runner@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-runner/download/jest-runner-27.2.5.tgz?cache=0&sync_timestamp=1633701201558&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-runner%2Fdownload%2Fjest-runner-27.2.5.tgz#3d9d0626f351480bb2cffcfbbfac240c0097ebd4" + integrity sha1-PZ0GJvNRSAuyz/z7v6wkDACX69Q= + dependencies: + "@jest/console" "^27.2.5" + "@jest/environment" "^27.2.5" + "@jest/test-result" "^27.2.5" + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.0.6" + jest-environment-jsdom "^27.2.5" + jest-environment-node "^27.2.5" + jest-haste-map "^27.2.5" + jest-leak-detector "^27.2.5" + jest-message-util "^27.2.5" + jest-resolve "^27.2.5" + jest-runtime "^27.2.5" + jest-util "^27.2.5" + jest-worker "^27.2.5" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-runtime/download/jest-runtime-27.2.5.tgz#d144c3f6889b927aae1e695b63a41a3323b7016b" + integrity sha1-0UTD9oibknquHmlbY6QaMyO3AWs= + dependencies: + "@jest/console" "^27.2.5" + "@jest/environment" "^27.2.5" + "@jest/fake-timers" "^27.2.5" + "@jest/globals" "^27.2.5" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.2.5" + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.2.5" + jest-message-util "^27.2.5" + jest-mock "^27.2.5" + jest-regex-util "^27.0.6" + jest-resolve "^27.2.5" + jest-snapshot "^27.2.5" + jest-util "^27.2.5" + jest-validate "^27.2.5" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^16.2.0" + +jest-serializer@^27.0.6: + version "27.0.6" + resolved "https://registry.nlark.com/jest-serializer/download/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1" + integrity sha1-k6bHTgEyuBotVGIyUcRsSYu1vsE= + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-snapshot/download/jest-snapshot-27.2.5.tgz?cache=0&sync_timestamp=1633701195172&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-snapshot%2Fdownload%2Fjest-snapshot-27.2.5.tgz#8a612fe31e2967f58ad364542198dff61f92ef32" + integrity sha1-imEv4x4pZ/WK02RUIZjf9h+S7zI= + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/parser" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.2.5" + graceful-fs "^4.2.4" + jest-diff "^27.2.5" + jest-get-type "^27.0.6" + jest-haste-map "^27.2.5" + jest-matcher-utils "^27.2.5" + jest-message-util "^27.2.5" + jest-resolve "^27.2.5" + jest-util "^27.2.5" + natural-compare "^1.4.0" + pretty-format "^27.2.5" + semver "^7.3.2" + +jest-util@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-util/download/jest-util-27.2.5.tgz?cache=0&sync_timestamp=1633701210171&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-util%2Fdownload%2Fjest-util-27.2.5.tgz#88740c4024d223634a82ce7c2263e8bc6df3b3ba" + integrity sha1-iHQMQCTSI2NKgs58ImPovG3zs7o= + dependencies: + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^3.0.0" + picomatch "^2.2.3" + +jest-validate@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-validate/download/jest-validate-27.2.5.tgz?cache=0&sync_timestamp=1633701213277&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-validate%2Fdownload%2Fjest-validate-27.2.5.tgz#2d59bf1627d180f395ba58f24599b0ee0efcfbdf" + integrity sha1-LVm/FifRgPOVuljyRZmw7g78+98= + dependencies: + "@jest/types" "^27.2.5" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.0.6" + leven "^3.1.0" + pretty-format "^27.2.5" + +jest-watcher@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-watcher/download/jest-watcher-27.2.5.tgz?cache=0&sync_timestamp=1633701214616&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-watcher%2Fdownload%2Fjest-watcher-27.2.5.tgz#41cd3e64dc5bea8a4327083d71ba7667be400567" + integrity sha1-Qc0+ZNxb6opDJwg9cbp2Z75ABWc= + dependencies: + "@jest/test-result" "^27.2.5" + "@jest/types" "^27.2.5" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.2.5" + string-length "^4.0.1" + +jest-worker@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest-worker/download/jest-worker-27.2.5.tgz?cache=0&sync_timestamp=1633701196934&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest-worker%2Fdownload%2Fjest-worker-27.2.5.tgz#ed42865661959488aa020e8a325df010597c36d4" + integrity sha1-7UKGVmGVlIiqAg6KMl3wEFl8NtQ= + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.0.4: + version "27.2.5" + resolved "https://registry.npmmirror.com/jest/download/jest-27.2.5.tgz?cache=0&sync_timestamp=1633701085699&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjest%2Fdownload%2Fjest-27.2.5.tgz#7d8a5c8781a160f693beeb7c68e46c16ef948148" + integrity sha1-fYpch4GhYPaTvut8aORsFu+UgUg= + dependencies: + "@jest/core" "^27.2.5" + import-local "^3.0.2" + jest-cli "^27.2.5" + +js-stringify@^1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/js-stringify/download/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" + integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk= + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.nlark.com/js-yaml/download/js-yaml-3.14.1.tgz?cache=0&sync_timestamp=1618847614705&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-yaml%2Fdownload%2Fjs-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc= + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.npmmirror.com/jsdom/download/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha1-kYrnGWVCSxl8gZ+Bg6dU4Yl3txA= + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.nlark.com/jsesc/download/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q= + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.nlark.com/jsesc/download/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.nlark.com/json-parse-even-better-errors/download/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.nlark.com/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA= + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/json-schema-traverse/download/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha1-rnvLNlard6c7pcSb9lTzjmtoYOI= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/json5/download/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4= + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.1.3: + version "2.2.0" + resolved "https://registry.nlark.com/json5/download/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha1-Lf7+cgxrpSXZ69kJlQ8FFTFsiaM= + dependencies: + minimist "^1.2.5" + +jsonc-parser@^2.3.0: + version "2.3.1" + resolved "https://registry.npm.taobao.org/jsonc-parser/download/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" + integrity sha1-WVSRULEz8u+sykj+nOHsBlmvI0I= + +jsonc-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/jsonc-parser/download/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" + integrity sha1-q914VwHH5+rKip7IzwcMpRp0WiI= + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.nlark.com/jsonfile/download/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4= + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.npm.taobao.org/jsonparse/download/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jstransformer@1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/jstransformer/download/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" + integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= + dependencies: + is-promise "^2.0.0" + promise "^7.0.1" + +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.nlark.com/kind-of/download/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0= + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npm.taobao.org/kleur/download/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha1-p5yezIbuHOP6YgbRIWxQHxR/wH4= + +known-css-properties@^0.21.0: + version "0.21.0" + resolved "https://registry.nlark.com/known-css-properties/download/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d" + integrity sha1-FfvQu7g0R/POCdivJH7UfGjt6A0= + +kolorist@^1.5.0: + version "1.5.0" + resolved "https://registry.nlark.com/kolorist/download/kolorist-1.5.0.tgz#a06f7dd11d1b5fdb743d79c8acd4e1ecbcbd89b3" + integrity sha1-oG990R0bX9t0PXnIrNTh7Ly9ibM= + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/leven/download/leven-3.1.0.tgz?cache=0&sync_timestamp=1628597922950&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fleven%2Fdownload%2Fleven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha1-d4kd6DQGTMy6gq54QrtrFKE+1/I= + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npm.taobao.org/levn/download/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha1-rkViwAdHO5MqYgDUAyaN0v/8at4= + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.nlark.com/lines-and-columns/download/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +linkify-it@^3.0.1: + version "3.0.3" + resolved "https://registry.npmmirror.com/linkify-it/download/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha1-qYuvRM5FpVDvtNScdp0HUkzC+i4= + dependencies: + uc.micro "^1.0.1" + +lint-staged@^11.0.0: + version "11.2.3" + resolved "https://registry.npmmirror.com/lint-staged/download/lint-staged-11.2.3.tgz#fc3f4569cc4f46553309dfc1447b8aef69f744fb" + integrity sha1-/D9FacxPRlUzCd/BRHuK72n3RPs= + dependencies: + cli-truncate "2.1.0" + colorette "^1.4.0" + commander "^8.2.0" + cosmiconfig "^7.0.1" + debug "^4.3.2" + enquirer "^2.3.6" + execa "^5.1.1" + listr2 "^3.12.2" + micromatch "^4.0.4" + normalize-path "^3.0.0" + please-upgrade-node "^3.2.0" + string-argv "0.3.1" + stringify-object "3.3.0" + supports-color "8.1.1" + +listr2@^3.12.2: + version "3.12.2" + resolved "https://registry.npmmirror.com/listr2/download/listr2-3.12.2.tgz#2d55cc627111603ad4768a9e87c9c7bb9b49997e" + integrity sha1-LVXMYnERYDrUdoqeh8nHu5tJmX4= + dependencies: + cli-truncate "^2.1.0" + colorette "^1.4.0" + log-update "^4.0.0" + p-map "^4.0.0" + rxjs "^6.6.7" + through "^2.3.8" + wrap-ansi "^7.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/locate-path/download/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/locate-path/download/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha1-Gvujlq/WdqbUJQTQpno6frn2KqA= + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.nlark.com/locate-path/download/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha1-VTIeswn+u8WcSAHZMackUqaB0oY= + dependencies: + p-locate "^5.0.0" + +lodash-es@^4.17.20: + version "4.17.21" + resolved "https://registry.npm.taobao.org/lodash-es/download/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4= + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.npm.taobao.org/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.nlark.com/lodash.debounce/download/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npm.taobao.org/lodash.merge/download/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo= + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npm.taobao.org/lodash.truncate/download/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1618847558302&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flodash%2Fdownload%2Flodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw= + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/log-symbols/download/log-symbols-4.1.0.tgz?cache=0&sync_timestamp=1618723443432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flog-symbols%2Fdownload%2Flog-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha1-P727lbRoOsn8eFER55LlWNSr1QM= + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-symbols@^5.0.0: + version "5.0.0" + resolved "https://registry.npm.taobao.org/log-symbols/download/log-symbols-5.0.0.tgz?cache=0&sync_timestamp=1618723443432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flog-symbols%2Fdownload%2Flog-symbols-5.0.0.tgz#7720d3c6a56c365e1f658916069ba18d941092ca" + integrity sha1-dyDTxqVsNl4fZYkWBpuhjZQQkso= + dependencies: + chalk "^4.1.0" + is-unicode-supported "^1.0.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/log-update/download/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha1-WJ7NNSRx8qHAxXAodUOmTf0g4KE= + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +longest-streak@^2.0.0: + version "2.0.4" + resolved "https://registry.npm.taobao.org/longest-streak/download/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" + integrity sha1-uFmZV9pbXatk3uP+MW+ndFl9kOQ= + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.nlark.com/lru-cache/download/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ= + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.7: + version "0.25.7" + resolved "https://registry.nlark.com/magic-string/download/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE= + dependencies: + sourcemap-codec "^1.4.4" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8= + dependencies: + semver "^6.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.npm.taobao.org/makeerror/download/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.nlark.com/map-obj/download/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-obj@^4.0.0: + version "4.3.0" + resolved "https://registry.nlark.com/map-obj/download/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha1-kwT5Buk/qucIgNoQKp8d8OqLsFo= + +markdown-it-anchor@^7.1.0: + version "7.1.0" + resolved "https://registry.npmmirror.com/markdown-it-anchor/download/markdown-it-anchor-7.1.0.tgz#30fb21497bf59e83ff4d1ddc052d821962e2489e" + integrity sha1-MPshSXv1noP/TR3cBS2CGWLiSJ4= + +markdown-it-container@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/markdown-it-container/download/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b" + integrity sha1-HRmwYECgIPmoJ1d7t9v2eqXemls= + +markdown-it-emoji@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/markdown-it-emoji/download/markdown-it-emoji-2.0.0.tgz#3164ad4c009efd946e98274f7562ad611089a231" + integrity sha1-MWStTACe/ZRumCdPdWKtYRCJojE= + +markdown-it-table-of-contents@^0.5.2: + version "0.5.2" + resolved "https://registry.npm.taobao.org/markdown-it-table-of-contents/download/markdown-it-table-of-contents-0.5.2.tgz#2f941d386c277887910f2c7a8a16f5a17acb829c" + integrity sha1-L5QdOGwneIeRDyx6ihb1oXrLgpw= + +markdown-it@^12.0.4, markdown-it@^12.0.6: + version "12.2.0" + resolved "https://registry.nlark.com/markdown-it/download/markdown-it-12.2.0.tgz#091f720fd5db206f80de7a8d1f1a7035fd0d38db" + integrity sha1-CR9yD9XbIG+A3nqNHxpwNf0NONs= + dependencies: + argparse "^2.0.1" + entities "~2.1.0" + linkify-it "^3.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +matchit@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/matchit/download/matchit-1.1.0.tgz#c4ccf17d9c824cc1301edbcffde9b75a61d10a7c" + integrity sha1-xMzxfZyCTMEwHtvP/em3WmHRCnw= + dependencies: + "@arr/every" "^1.0.0" + +mathml-tag-names@^2.1.3: + version "2.1.3" + resolved "https://registry.npm.taobao.org/mathml-tag-names/download/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" + integrity sha1-TdrdZzCOeAzxakdoWHjuJ7c2oKM= + +mdast-util-from-markdown@^0.8.0: + version "0.8.5" + resolved "https://registry.npmmirror.com/mdast-util-from-markdown/download/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" + integrity sha1-0e8spCvDd+ywRjqYeRDa6JvZoow= + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-string "^2.0.0" + micromark "~2.11.0" + parse-entities "^2.0.0" + unist-util-stringify-position "^2.0.0" + +mdast-util-to-markdown@^0.6.0: + version "0.6.5" + resolved "https://registry.nlark.com/mdast-util-to-markdown/download/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" + integrity sha1-sz9nyoINaebMUnqT1AOSSbUEvr4= + dependencies: + "@types/unist" "^2.0.0" + longest-streak "^2.0.0" + mdast-util-to-string "^2.0.0" + parse-entities "^2.0.0" + repeat-string "^1.0.0" + zwitch "^1.0.0" + +mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/mdast-util-to-string/download/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha1-uM/mpxPhCRy1tyj8SIhaR2f4uXs= + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.nlark.com/mdn-data/download/mdn-data-2.0.14.tgz?cache=0&sync_timestamp=1631838436876&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA= + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.nlark.com/mdurl/download/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +meow@^8.0.0: + version "8.1.2" + resolved "https://registry.nlark.com/meow/download/meow-8.1.2.tgz?cache=0&sync_timestamp=1627561056191&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmeow%2Fdownload%2Fmeow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" + integrity sha1-vL5FvaDuFynTUMA8/8g5WjbE6Jc= + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.18.0" + yargs-parser "^20.2.3" + +meow@^9.0.0: + version "9.0.0" + resolved "https://registry.nlark.com/meow/download/meow-9.0.0.tgz?cache=0&sync_timestamp=1627561056191&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmeow%2Fdownload%2Fmeow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" + integrity sha1-zZUQvFysne59A8c+4fmtlZ9Oo2Q= + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize "^1.2.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.18.0" + yargs-parser "^20.2.3" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/merge-stream/download/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A= + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.nlark.com/merge2/download/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4= + +micromark@~2.11.0: + version "2.11.4" + resolved "https://registry.npmmirror.com/micromark/download/micromark-2.11.4.tgz?cache=0&sync_timestamp=1633766302628&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmicromark%2Fdownload%2Fmicromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" + integrity sha1-0TQ2E47qgmOD6CJEnJpcUO5EZlo= + dependencies: + debug "^4.0.0" + parse-entities "^2.0.0" + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.nlark.com/micromatch/download/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k= + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.50.0, "mime-db@>= 1.43.0 < 2": + version "1.50.0" + resolved "https://registry.nlark.com/mime-db/download/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha1-q9SslOmNPA4YUBbGerRdX95AwR8= + +mime-types@^2.1.12, mime-types@~2.1.24: + version "2.1.33" + resolved "https://registry.npmmirror.com/mime-types/download/mime-types-2.1.33.tgz?cache=0&sync_timestamp=1633108539902&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmime-types%2Fdownload%2Fmime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha1-H6EqkERy+v0GjkjZ6EAfdNP3Dts= + dependencies: + mime-db "1.50.0" + +mime@^2.3.1: + version "2.5.2" + resolved "https://registry.nlark.com/mime/download/mime-2.5.2.tgz?cache=0&sync_timestamp=1618846922439&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmime%2Fdownload%2Fmime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha1-bj3GzCuVEGQ4MOXxnVy3U9pe6r4= + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/mimic-fn/download/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs= + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/min-indent/download/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha1-pj9oFnOzBXH76LwlaGrnRu76mGk= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= + dependencies: + brace-expansion "^1.1.7" + +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/minimist-options/download/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha1-wGVXE8U6ii69d/+iR9NCxA8BBhk= + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1632788836446&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fms%2Fdownload%2Fms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1632788836446&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fms%2Fdownload%2Fms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/download/ms-2.1.3.tgz?cache=0&sync_timestamp=1632788836446&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fms%2Fdownload%2Fms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha1-V0yBOM4dK1hh8LRFedut1gxmFbI= + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha1-FjDEKyJR/4HiooPelqVJfqkuXg0= + +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.nlark.com/mz/download/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI= + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanocolors@^0.1.12: + version "0.1.12" + resolved "https://registry.npmmirror.com/nanocolors/download/nanocolors-0.1.12.tgz#8577482c58cbd7b5bb1681db4cf48f11a87fd5f6" + integrity sha1-hXdILFjL17W7FoHbTPSPEah/1fY= + +nanoid@^3.1.28: + version "3.1.30" + resolved "https://registry.npmmirror.com/nanoid/download/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha1-Y/k8xUjSoRPcXfvGO/oJ4rm2Q2I= + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.nlark.com/natural-compare/download/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs= + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/node-int64/download/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/node-modules-regexp/download/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/node-releases/download/node-releases-2.0.0.tgz#67dc74903100a7deb044037b8a2e5f453bb05400" + integrity sha1-Z9x0kDEAp96wRAN7ii5fRTuwVAA= + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.nlark.com/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&sync_timestamp=1629301911873&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg= + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^3.0.0: + version "3.0.3" + resolved "https://registry.nlark.com/normalize-package-data/download/normalize-package-data-3.0.3.tgz?cache=0&sync_timestamp=1629301911873&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha1-28w+LaWVCaCYNCKITNFy7v36Ul4= + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/normalize-range/download/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-selector@^0.2.0: + version "0.2.0" + resolved "https://registry.npm.taobao.org/normalize-selector/download/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" + integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/npm-run-path/download/npm-run-path-4.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fnpm-run-path%2Fdownload%2Fnpm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= + dependencies: + path-key "^3.0.0" + +nth-check@^2.0.0: + version "2.0.1" + resolved "https://registry.nlark.com/nth-check/download/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha1-Lv4WL1w9oGoolZ+9PbddvuqfD8I= + dependencies: + boolbase "^1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.nlark.com/num2fraction/download/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.npm.taobao.org/nwsapi/download/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha1-IEh5qePQaP8qVROcLHcngGgaOLc= + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.nlark.com/object-inspect/download/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha1-nc6xRs7dQUig2eUauI00z1CZIrE= + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/object-keys/download/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha1-HEfyct8nfzsdrwYWd9nILiMixg4= + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.npm.taobao.org/object.assign/download/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha1-DtVKNC7Os3s4/3brgxoOeIy2OUA= + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.npmmirror.com/object.values/download/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha1-lZ9j486e8QhyAzMIITHkpFm3Fqw= + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/on-headers/download/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.nlark.com/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz?cache=0&sync_timestamp=1617889842663&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fonetime%2Fdownload%2Fonetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= + dependencies: + mimic-fn "^2.1.0" + +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.npm.taobao.org/opencollective-postinstall/download/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha1-eg//l49tv6TQBiOPusmO1BmMMlk= + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.nlark.com/optionator/download/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.nlark.com/optionator/download/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha1-TyNqY3Pa4FZqbUPhMmZ09QwpFJk= + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ora@*: + version "6.0.1" + resolved "https://registry.nlark.com/ora/download/ora-6.0.1.tgz#68caa9fd6c485a40d6f46c50a3940fa3df99c7f3" + integrity sha1-aMqp/WxIWkDW9GxQo5QPo9+Zx/M= + dependencies: + bl "^5.0.0" + chalk "^4.1.2" + cli-cursor "^4.0.0" + cli-spinners "^2.6.0" + is-interactive "^2.0.0" + is-unicode-supported "^1.1.0" + log-symbols "^5.0.0" + strip-ansi "^7.0.1" + wcwidth "^1.0.1" + +ora@^5.4.0, ora@^5.4.1: + version "5.4.1" + resolved "https://registry.nlark.com/ora/download/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha1-GyZ4Qmr0rEpQkAjl5KyemVnbnhg= + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.nlark.com/os-tmpdir/download/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.nlark.com/p-limit/download/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg= + dependencies: + p-try "^1.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.nlark.com/p-limit/download/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE= + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.nlark.com/p-limit/download/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs= + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/p-locate/download/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.nlark.com/p-locate/download/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha1-o0KLtwiLOmApL2aRkni3wpetTwc= + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/p-locate/download/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ= + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/p-map/download/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha1-uy+Vpe2i7BaOySdOBqdHw+KQTSs= + dependencies: + aggregate-error "^3.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/p-try/download/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/p-try/download/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha1-yyhoVA4xPWHeWPr741zpAE1VQOY= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/parent-module/download/parent-module-1.0.1.tgz?cache=0&sync_timestamp=1633338208560&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fparent-module%2Fdownload%2Fparent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI= + dependencies: + callsites "^3.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/parse-entities/download/parse-entities-2.0.0.tgz?cache=0&sync_timestamp=1632273629559&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fparse-entities%2Fdownload%2Fparse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha1-U8brW5MUofTsmfoP33zgHs2gy+g= + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/parse-json/download/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80= + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha1-LN+a2CMyEUA3DU2/XT6Sx8jdxuY= + dependencies: + parse5 "^6.0.1" + +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.npm.taobao.org/parse5/download/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha1-4aHAhcVps9wIMhGE8Zo5zCf3wws= + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.npm.taobao.org/parse5/download/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg= + +patch-vue-directive-ssr@^0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/patch-vue-directive-ssr/download/patch-vue-directive-ssr-0.0.1.tgz#2eac731f59cdb766d4d613bc24e522ded6ff1bb8" + integrity sha1-LqxzH1nNt2bU1hO8JOUi3tb/G7g= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz?cache=0&sync_timestamp=1628765299359&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpath-exists%2Fdownload%2Fpath-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/path-exists/download/path-exists-4.0.0.tgz?cache=0&sync_timestamp=1628765299359&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpath-exists%2Fdownload%2Fpath-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.nlark.com/path-key/download/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.nlark.com/path-parse/download/path-parse-1.0.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpath-parse%2Fdownload%2Fpath-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU= + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/path-type/download/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs= + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/picocolors/download/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha1-VwZw95NkaFHRuhNZlpYqutWHhZ8= + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/picocolors/download/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw= + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpicomatch%2Fdownload%2Fpicomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI= + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.nlark.com/pirates/download/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha1-ZDqSyviUVm+RsrmG0sZpUKji+4c= + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/pkg-dir/download/pkg-dir-2.0.0.tgz?cache=0&sync_timestamp=1633498874247&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpkg-dir%2Fdownload%2Fpkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/pkg-dir/download/pkg-dir-4.2.0.tgz?cache=0&sync_timestamp=1633498874247&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpkg-dir%2Fdownload%2Fpkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM= + dependencies: + find-up "^4.0.0" + +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/pkg-dir/download/pkg-dir-5.0.0.tgz?cache=0&sync_timestamp=1633498874247&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpkg-dir%2Fdownload%2Fpkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha1-oC1q6+a6EzqSj3Suwguv3+a452A= + dependencies: + find-up "^5.0.0" + +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.npm.taobao.org/please-upgrade-node/download/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha1-rt3T+ZTJM+StmLmdmlVu+g4v6UI= + dependencies: + semver-compare "^1.0.0" + +polka@^0.5.2: + version "0.5.2" + resolved "https://registry.npmmirror.com/polka/download/polka-0.5.2.tgz#588bee0c5806dbc6c64958de3a1251860e9f2e26" + integrity sha1-WIvuDFgG28bGSVjeOhJRhg6fLiY= + dependencies: + "@polka/url" "^0.5.0" + trouter "^2.0.1" + +postcss-html@^0.36.0: + version "0.36.0" + resolved "https://registry.nlark.com/postcss-html/download/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" + integrity sha1-tAkT+U6qzCRT/TChMnrW7h+IsgQ= + dependencies: + htmlparser2 "^3.10.0" + +postcss-less@^3.1.4: + version "3.1.4" + resolved "https://registry.nlark.com/postcss-less/download/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" + integrity sha1-Np9YZCtZKO+Jj/vBpuk8lYMExa0= + dependencies: + postcss "^7.0.14" + +postcss-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.npm.taobao.org/postcss-media-query-parser/download/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= + +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/postcss-resolve-nested-selector/download/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" + integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= + +postcss-safe-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.nlark.com/postcss-safe-parser/download/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" + integrity sha1-ptTkjw832ffBGypYG/APi6SHC5Y= + dependencies: + postcss "^7.0.26" + +postcss-sass@^0.4.4: + version "0.4.4" + resolved "https://registry.npmmirror.com/postcss-sass/download/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3" + integrity sha1-kfDzRHtFzjcyJ6mLYfjY8HhShaM= + dependencies: + gonzales-pe "^4.3.0" + postcss "^7.0.21" + +postcss-scss@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/postcss-scss/download/postcss-scss-2.1.1.tgz?cache=0&sync_timestamp=1632913757115&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpostcss-scss%2Fdownload%2Fpostcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" + integrity sha1-7Dp1+imlXgFrkL8yaQJsU8HSs4M= + dependencies: + postcss "^7.0.6" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.5: + version "6.0.6" + resolved "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-6.0.6.tgz?cache=0&sync_timestamp=1620752990832&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha1-LFu6gXSsL2mBq2MaQqsO5UrzMuo= + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-syntax@^0.36.2: + version "0.36.2" + resolved "https://registry.npm.taobao.org/postcss-syntax/download/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" + integrity sha1-8IV4x9lYNFdOVZOoLfv6ivrjtRw= + +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha1-RD9qIM7WSBor2k+oUypuVdeJoss= + +postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.npmmirror.com/postcss/download/postcss-7.0.39.tgz?cache=0&sync_timestamp=1633379061167&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpostcss%2Fdownload%2Fpostcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha1-liQ3XZZWMOLh8sAqk1yCpZy0gwk= + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.1.10, postcss@^8.3.8: + version "8.3.9" + resolved "https://registry.npmmirror.com/postcss/download/postcss-8.3.9.tgz?cache=0&sync_timestamp=1633379061167&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpostcss%2Fdownload%2Fpostcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" + integrity sha1-mHVMqgbE7p61nMSL0HO7a9NDfDE= + dependencies: + nanoid "^3.1.28" + picocolors "^0.2.1" + source-map-js "^0.6.2" + +preact@^10.0.0: + version "10.5.15" + resolved "https://registry.npmmirror.com/preact/download/preact-10.5.15.tgz#6df94d8afecf3f9e10a742fd8c362ddab464225f" + integrity sha1-bflNiv7PP54Qp0L9jDYt2rRkIl8= + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.nlark.com/prelude-ls/download/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha1-3rxkidem5rDnYRiIzsiAM30xY5Y= + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.nlark.com/prelude-ls/download/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prettier@^2.2.1: + version "2.4.1" + resolved "https://registry.nlark.com/prettier/download/prettier-2.4.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fprettier%2Fdownload%2Fprettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" + integrity sha1-Zx4RyJwUpM/Ids5WQQbEpnJsn1w= + +pretty-format@^26.0.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.npmmirror.com/pretty-format/download/pretty-format-26.6.2.tgz?cache=0&sync_timestamp=1633701203131&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpretty-format%2Fdownload%2Fpretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha1-41wnBfFMt/4v6U+geDRbREEg/JM= + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +pretty-format@^27.2.5: + version "27.2.5" + resolved "https://registry.npmmirror.com/pretty-format/download/pretty-format-27.2.5.tgz?cache=0&sync_timestamp=1633701203131&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpretty-format%2Fdownload%2Fpretty-format-27.2.5.tgz#7cfe2a8e8f01a5b5b29296a0b70f4140df0830c5" + integrity sha1-fP4qjo8BpbWykpagtw9BQN8IMMU= + dependencies: + "@jest/types" "^27.2.5" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +prismjs@^1.23.0: + version "1.25.0" + resolved "https://registry.nlark.com/prismjs/download/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha1-b4It8b2tllc0sxCzFaIzFc+Zl1Y= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha1-foz42PW48jnBvGi+tOt4Vn1XLvg= + +promise@^7.0.1: + version "7.3.1" + resolved "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078= + dependencies: + asap "~2.0.3" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmmirror.com/prompts/download/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha1-e1fnOzpIAprRDr1E90sBcipMsGk= + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ= + +pug-attrs@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/pug-attrs/download/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" + integrity sha1-sQRR4DSBZeMfrRzCPr3dncc0fEE= + dependencies: + constantinople "^4.0.1" + js-stringify "^1.0.2" + pug-runtime "^3.0.0" + +pug-code-gen@^3.0.2: + version "3.0.2" + resolved "https://registry.nlark.com/pug-code-gen/download/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce" + integrity sha1-rRkPSUMTO/GGtguA3kgxAOEy4s4= + dependencies: + constantinople "^4.0.1" + doctypes "^1.1.0" + js-stringify "^1.0.2" + pug-attrs "^3.0.0" + pug-error "^2.0.0" + pug-runtime "^3.0.0" + void-elements "^3.1.0" + with "^7.0.0" + +pug-error@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/pug-error/download/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" + integrity sha1-XGIXPLCcNN4qLOBPF7it/sdNjKU= + +pug-filters@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/pug-filters/download/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" + integrity sha1-0+Sa9bqEcum3pm2YDnB86dLMm14= + dependencies: + constantinople "^4.0.1" + jstransformer "1.0.0" + pug-error "^2.0.0" + pug-walk "^2.0.0" + resolve "^1.15.1" + +pug-lexer@^5.0.1: + version "5.0.1" + resolved "https://registry.npm.taobao.org/pug-lexer/download/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" + integrity sha1-rkRijFvvmxkLZlaDsojKkCS4sNU= + dependencies: + character-parser "^2.2.0" + is-expression "^4.0.0" + pug-error "^2.0.0" + +pug-linker@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/pug-linker/download/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" + integrity sha1-EsvAWU/Fo+Brn8Web5PBRpYqdwg= + dependencies: + pug-error "^2.0.0" + pug-walk "^2.0.0" + +pug-load@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/pug-load/download/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" + integrity sha1-n9nNpSICsIrbEdJWgfufNL1BtmI= + dependencies: + object-assign "^4.1.1" + pug-walk "^2.0.0" + +pug-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.npm.taobao.org/pug-parser/download/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" + integrity sha1-qP3ANYY6lbLB3F6/Ts+AtOdqEmA= + dependencies: + pug-error "^2.0.0" + token-stream "1.0.0" + +pug-runtime@^3.0.0, pug-runtime@^3.0.1: + version "3.0.1" + resolved "https://registry.npm.taobao.org/pug-runtime/download/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" + integrity sha1-9jaXYgRyPzWoxfb61qzaKhkbg9c= + +pug-strip-comments@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/pug-strip-comments/download/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" + integrity sha1-+UsH/WtJVSMzD0kKf1VLT/h2MD4= + dependencies: + pug-error "^2.0.0" + +pug-walk@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/pug-walk/download/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" + integrity sha1-QXqrwpIyu0SZtbUGmistKiTV9f4= + +pug@^3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/pug/download/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" + integrity sha1-81xxBzQ0VOQ7wnrg/3bHMbeOpTU= + dependencies: + pug-code-gen "^3.0.2" + pug-filters "^4.0.0" + pug-lexer "^5.0.1" + pug-linker "^4.0.0" + pug-load "^3.0.0" + pug-parser "^6.0.0" + pug-runtime "^3.0.1" + pug-strip-comments "^2.0.0" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.nlark.com/punycode/download/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha1-tYsBCsQMIsVldhbI0sLALHv0eew= + +q@^1.5.1: + version "1.5.1" + resolved "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.nlark.com/queue-microtask/download/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha1-SSkii7xyTfrEPg77BYyve2z7YkM= + +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.nlark.com/quick-lru/download/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha1-W4h48ROlgheEjGSCAmxz4bpXcn8= + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.nlark.com/quick-lru/download/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha1-NmST5rPkKjpoheLpnRj4D7eoyTI= + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.npmmirror.com/react-is/download/react-is-17.0.2.tgz?cache=0&sync_timestamp=1634230899200&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Freact-is%2Fdownload%2Freact-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha1-5pHUqOnHiTZWVVOas3J2Kw77VPA= + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/read-pkg-up/download/read-pkg-up-7.0.1.tgz?cache=0&sync_timestamp=1634148714272&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fread-pkg-up%2Fdownload%2Fread-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha1-86YTV1hFlzOuK5VjgFbhhU5+9Qc= + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.nlark.com/read-pkg/download/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w= + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.nlark.com/readable-stream/download/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.nlark.com/readdirp/download/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc= + dependencies: + picomatch "^2.2.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.nlark.com/rechoir/download/rechoir-0.6.2.tgz?cache=0&sync_timestamp=1627102454602&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frechoir%2Fdownload%2Frechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/redent/download/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha1-5Ve3mYMWu1PJ8fVvpiY1LGljBZ8= + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.nlark.com/regenerate-unicode-properties/download/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha1-VNCccRXh9T3CMUqXSzLBw0Tv4yY= + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.npm.taobao.org/regenerate/download/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha1-uTRtiCfo9aMve6KWN9OYtpAUhIo= + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.nlark.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I= + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.nlark.com/regenerator-transform/download/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha1-yY2hVGg2ccnE3LFuznNlF+G3/rQ= + dependencies: + "@babel/runtime" "^7.8.4" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.nlark.com/regexpp/download/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha1-BCWido2PI7rXDKS5BGH6LxIT4bI= + +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.nlark.com/regexpu-core/download/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha1-5WBbo2G2excYR4UBMnUC9EeamPA= + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.npmmirror.com/regjsgen/download/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha1-kv8pX7He7L9uzaslQ9IH6RqjNzM= + +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.nlark.com/regjsparser/download/regjsparser-0.7.0.tgz?cache=0&sync_timestamp=1630946857014&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fregjsparser%2Fdownload%2Fregjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha1-prZntUyIXhi1JVTLSWDvcRh+mWg= + dependencies: + jsesc "~0.5.0" + +remark-parse@^9.0.0: + version "9.0.0" + resolved "https://registry.nlark.com/remark-parse/download/remark-parse-9.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fremark-parse%2Fdownload%2Fremark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" + integrity sha1-TSCimWZYgOT0r12Qt8e4qTWFNkA= + dependencies: + mdast-util-from-markdown "^0.8.0" + +remark-stringify@^9.0.0: + version "9.0.1" + resolved "https://registry.npmmirror.com/remark-stringify/download/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" + integrity sha1-V20G6RBUiwpxkacfJ7M/EhiGKJQ= + dependencies: + mdast-util-to-markdown "^0.6.0" + +remark@^13.0.0: + version "13.0.0" + resolved "https://registry.nlark.com/remark/download/remark-13.0.0.tgz?cache=0&sync_timestamp=1628001703248&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fremark%2Fdownload%2Fremark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" + integrity sha1-0V2b9xpAL0Aofr42Bntm1Uho5CU= + dependencies: + remark-parse "^9.0.0" + remark-stringify "^9.0.0" + unified "^9.1.0" + +repeat-string@^1.0.0: + version "1.6.1" + resolved "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request-light@^0.5.4: + version "0.5.4" + resolved "https://registry.nlark.com/request-light/download/request-light-0.5.4.tgz#497a98c6d8ae49536417a5e2d7f383b934f3e38c" + integrity sha1-SXqYxtiuSVNkF6Xi1/ODuTTz44w= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.nlark.com/require-from-string/download/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/require-main-filename/download/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs= + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha1-DwB18bslRHZs9zumpuKt/ryxPy0= + dependencies: + resolve-from "^5.0.0" + +resolve-from@5.0.0, resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/resolve-from/download/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha1-w1IlhD3493bfIcV1V7wIfp39/Gk= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/resolve-from/download/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY= + +resolve-global@1.0.0, resolve-global@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/resolve-global/download/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" + integrity sha1-oqed9K8so/Sb93753azTItrRklU= + dependencies: + global-dirs "^0.1.1" + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.nlark.com/resolve/download/resolve-1.20.0.tgz?cache=0&sync_timestamp=1618846903792&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fresolve%2Fdownload%2Fresolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU= + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/restore-cursor/download/restore-cursor-3.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frestore-cursor%2Fdownload%2Frestore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha1-OfZ8VLOnpYzqUjbZXPADQjljH34= + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/restore-cursor/download/restore-cursor-4.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frestore-cursor%2Fdownload%2Frestore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha1-UZVgpDGJdQlt725gnUQQDtqkzLk= + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npm.taobao.org/reusify/download/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY= + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.nlark.com/rimraf/download/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho= + dependencies: + glob "^7.1.3" + +rollup@^2.57.0: + version "2.58.0" + resolved "https://registry.npmmirror.com/rollup/download/rollup-2.58.0.tgz#a643983365e7bf7f5b7c62a8331b983b7c4c67fb" + integrity sha1-pkOYM2Xnv39bfGKoMxuYO3xMZ/s= + optionalDependencies: + fsevents "~2.3.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU= + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npm.taobao.org/run-parallel/download/run-parallel-1.2.0.tgz?cache=0&sync_timestamp=1612926584650&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frun-parallel%2Fdownload%2Frun-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4= + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.6.7: + version "6.6.7" + resolved "https://registry.npmmirror.com/rxjs/download/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha1-kKwBisq/SRv2UEQjXVhjxNq4BMk= + dependencies: + tslib "^1.9.0" + +rxjs@^7.2.0: + version "7.4.0" + resolved "https://registry.npmmirror.com/rxjs/download/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha1-oSpE1+6/AW9f8kQbh/KMmlHOvGg= + dependencies: + tslib "~2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo= + +sass@^1.32.2: + version "1.43.2" + resolved "https://registry.npmmirror.com/sass/download/sass-1.43.2.tgz#c02501520c624ad6622529a8b3724eb08da82d65" + integrity sha1-wCUBUgxiStZiJSmos3JOsI2oLWU= + dependencies: + chokidar ">=3.0.0 <4.0.0" + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.npm.taobao.org/saxes/download/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha1-7rq5U/o7dgjb6U5drbFciI+maW0= + dependencies: + xmlchars "^2.2.0" + +section-matter@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/section-matter/download/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha1-6QQZU1BngOwB1Z8pKhnHuFC4QWc= + dependencies: + extend-shallow "^2.0.1" + kind-of "^6.0.0" + +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/semver-compare/download/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + +semver-regex@^3.1.2: + version "3.1.3" + resolved "https://registry.npmmirror.com/semver-regex/download/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" + integrity sha1-srzG+X9jJp8oaZTil+IptiRdDcM= + +"semver@2 || 3 || 4 || 5": + version "5.7.1" + resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1616464367341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.npm.taobao.org/semver/download/semver-7.0.0.tgz?cache=0&sync_timestamp=1616464367341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha1-XzyjV2HkfgWyBsba/yz4FPAxa44= + +semver@7.3.2: + version "7.3.2" + resolved "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz?cache=0&sync_timestamp=1616464367341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg= + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1616464367341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0= + +semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.npm.taobao.org/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1616464367341&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc= + dependencies: + lru-cache "^6.0.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo= + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/shebang-regex/download/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= + +shelljs@^0.8.4: + version "0.8.4" + resolved "https://registry.npm.taobao.org/shelljs/download/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + integrity sha1-3naE/ut2f4cWsyYHiooAh1iQ48I= + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npm.taobao.org/side-channel/download/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha1-785cj9wQTudRslxY1CkAEfpeos8= + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.5" + resolved "https://registry.npmmirror.com/signal-exit/download/signal-exit-3.0.5.tgz?cache=0&sync_timestamp=1632948898808&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsignal-exit%2Fdownload%2Fsignal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + integrity sha1-nj6MwMdamUcrRDIQM6dwLnc4JS8= + +sirv@^1.0.12: + version "1.0.17" + resolved "https://registry.nlark.com/sirv/download/sirv-1.0.17.tgz#86e2c63c612da5a1dace1c16c46f524aaa26ac45" + integrity sha1-huLGPGEtpaHazhwWxG9SSqomrEU= + dependencies: + "@polka/url" "^1.0.0-next.20" + mime "^2.3.1" + totalist "^1.0.0" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npm.taobao.org/sisteransi/download/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha1-E01oEpd1ZDfMBcoBNw06elcQde0= + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/slash/download/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ= + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/slice-ansi/download/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha1-Md3BCTCht+C2ewjJbC9Jt3p4l4c= + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/slice-ansi/download/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha1-UA6N0P1VsFgVCGJVsxla3ypF/ms= + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.nlark.com/source-map-js/download/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha1-C7XeYxtBz72mz7qL0FqA79/SOF4= + +source-map-support@^0.5.6: + version "0.5.20" + resolved "https://registry.nlark.com/source-map-support/download/source-map-support-0.5.20.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha1-EhZgifj15ejFaSazd2Mzkt0stsk= + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha1-UwL4FpAxc1ImVECS5kmB91F1A4M= + +sourcemap-codec@^1.4.4: + version "1.4.8" + resolved "https://registry.nlark.com/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ= + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.nlark.com/spdx-correct/download/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha1-3s6BrJweZxPl99G28X1Gj6U9iak= + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0= + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.nlark.com/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha1-z3D1BILu/cmOPOCmgz5KU87rpnk= + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.10" + resolved "https://registry.nlark.com/spdx-license-ids/download/spdx-license-ids-3.0.10.tgz?cache=0&sync_timestamp=1628484477982&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fspdx-license-ids%2Fdownload%2Fspdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" + integrity sha1-DZvszN5wA9bGWNSH3UijLwvzAUs= + +specificity@^0.4.1: + version "0.4.1" + resolved "https://registry.nlark.com/specificity/download/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" + integrity sha1-qrXmRQEtsIuhguFRFlc40AiHsBk= + +split2@^3.0.0: + version "3.2.2" + resolved "https://registry.npmmirror.com/split2/download/split2-3.2.2.tgz?cache=0&sync_timestamp=1634234142741&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsplit2%2Fdownload%2Fsplit2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha1-vyzyo32DgxLCSciSBv16F90SNl8= + dependencies: + readable-stream "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.nlark.com/sprintf-js/download/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.npm.taobao.org/stable/download/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88= + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.nlark.com/stack-utils/download/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha1-0lJl/KmVFUZZ27+6O0klR3jS/dU= + dependencies: + escape-string-regexp "^2.0.0" + +string-argv@0.3.1: + version "0.3.1" + resolved "https://registry.npm.taobao.org/string-argv/download/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha1-leL77AQnrhkYSTX4FtdKqkxcGdo= + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.nlark.com/string-length/download/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha1-qKjce9XBqCubPIuH4SX2aHG25Xo= + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/download/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA= + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.nlark.com/string.prototype.trimend/download/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha1-51rpDClCxjUEaGwYsoe0oLGkX4A= + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.nlark.com/string.prototype.trimstart/download/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha1-s2OZr0qymZtMnGSL16P7K7Jv7u0= + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.nlark.com/string_decoder/download/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= + dependencies: + safe-buffer "~5.2.0" + +stringify-object@3.3.0: + version "3.3.0" + resolved "https://registry.nlark.com/stringify-object/download/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha1-cDBlrvyhkwDTzoivT1s5VtdVZik= + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk= + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha1-YXQKCM42th5Q5lZT8HBg0ACXX7I= + dependencies: + ansi-regex "^6.0.1" + +strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/strip-bom-string/download/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/strip-bom/download/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/strip-bom/download/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha1-nDUFwdtFvO3KPZz3oW9cWqOQGHg= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/strip-final-newline/download/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0= + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/strip-indent/download/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha1-wy4c7pQLazQyx3G8LFS8znPNMAE= + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.nlark.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1629398084712&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY= + +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.nlark.com/style-search/download/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" + integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= + +stylelint-config-recommended-scss@^4.3.0: + version "4.3.0" + resolved "https://registry.nlark.com/stylelint-config-recommended-scss/download/stylelint-config-recommended-scss-4.3.0.tgz#717dc253b4cab246da654cee208e499c5c797ae4" + integrity sha1-cX3CU7TKskbaZUzuII5JnFx5euQ= + dependencies: + stylelint-config-recommended "^5.0.0" + +stylelint-config-recommended@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/stylelint-config-recommended/download/stylelint-config-recommended-5.0.0.tgz#fb5653f495a60b4938f2ad3e77712d9e1039ae78" + integrity sha1-+1ZT9JWmC0k48q0+d3EtnhA5rng= + +stylelint-config-standard@^22.0.0: + version "22.0.0" + resolved "https://registry.nlark.com/stylelint-config-standard/download/stylelint-config-standard-22.0.0.tgz#c860be9a13ebbc1b084456fa10527bf13a44addf" + integrity sha1-yGC+mhPrvBsIRFb6EFJ78TpErd8= + dependencies: + stylelint-config-recommended "^5.0.0" + +stylelint-scss@^3.20.1: + version "3.21.0" + resolved "https://registry.nlark.com/stylelint-scss/download/stylelint-scss-3.21.0.tgz#9f50898691b16b1c1ca3945837381d98c5b22331" + integrity sha1-n1CJhpGxaxwco5RYNzgdmMWyIzE= + dependencies: + lodash "^4.17.15" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +stylelint@^13.13.1: + version "13.13.1" + resolved "https://registry.nlark.com/stylelint/download/stylelint-13.13.1.tgz?cache=0&sync_timestamp=1619887420035&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fstylelint%2Fdownload%2Fstylelint-13.13.1.tgz#fca9c9f5de7990ab26a00f167b8978f083a18f3c" + integrity sha1-/KnJ9d55kKsmoA8We4l48IOhjzw= + dependencies: + "@stylelint/postcss-css-in-js" "^0.37.2" + "@stylelint/postcss-markdown" "^0.36.2" + autoprefixer "^9.8.6" + balanced-match "^2.0.0" + chalk "^4.1.1" + cosmiconfig "^7.0.0" + debug "^4.3.1" + execall "^2.0.0" + fast-glob "^3.2.5" + fastest-levenshtein "^1.0.12" + file-entry-cache "^6.0.1" + get-stdin "^8.0.0" + global-modules "^2.0.0" + globby "^11.0.3" + globjoin "^0.1.4" + html-tags "^3.1.0" + ignore "^5.1.8" + import-lazy "^4.0.0" + imurmurhash "^0.1.4" + known-css-properties "^0.21.0" + lodash "^4.17.21" + log-symbols "^4.1.0" + mathml-tag-names "^2.1.3" + meow "^9.0.0" + micromatch "^4.0.4" + normalize-selector "^0.2.0" + postcss "^7.0.35" + postcss-html "^0.36.0" + postcss-less "^3.1.4" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^4.0.2" + postcss-sass "^0.4.4" + postcss-scss "^2.1.1" + postcss-selector-parser "^6.0.5" + postcss-syntax "^0.36.2" + postcss-value-parser "^4.1.0" + resolve-from "^5.0.0" + slash "^3.0.0" + specificity "^0.4.1" + string-width "^4.2.2" + strip-ansi "^6.0.0" + style-search "^0.1.0" + sugarss "^2.0.0" + svg-tags "^1.0.0" + table "^6.6.0" + v8-compile-cache "^2.3.0" + write-file-atomic "^3.0.3" + +sugarss@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/sugarss/download/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" + integrity sha1-3dduASSyl9QL88yjHIsi7LQ7xh0= + dependencies: + postcss "^7.0.2" + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.nlark.com/supports-color/download/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw= + dependencies: + has-flag "^4.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.nlark.com/supports-color/download/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.npm.taobao.org/supports-hyperlinks/download/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha1-T3e0JIh2WJF3S3DHm6vYf5vVlLs= + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.nlark.com/svg-tags/download/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + +svgo@^2.3.0: + version "2.7.0" + resolved "https://registry.npmmirror.com/svgo/download/svgo-2.7.0.tgz#e164cded22f4408fe4978f082be80159caea1e2d" + integrity sha1-4WTN7SL0QI/kl48IK+gBWcrqHi0= + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + nanocolors "^0.1.12" + stable "^0.1.8" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I= + +table@^6.0.9, table@^6.6.0: + version "6.7.2" + resolved "https://registry.npmmirror.com/table/download/table-6.7.2.tgz#a8d39b9f5966693ca8b0feba270a78722cbaf3b0" + integrity sha1-qNObn1lmaTyosP66Jwp4ciy687A= + dependencies: + ajv "^8.0.1" + lodash.clonedeep "^4.5.0" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.npm.taobao.org/terminal-link/download/terminal-link-2.1.1.tgz?cache=0&sync_timestamp=1618725119507&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterminal-link%2Fdownload%2Fterminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha1-FKZKJ6s8Dfkz6lRvulXy0HjtyZQ= + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npm.taobao.org/test-exclude/download/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha1-BKhphmHYBepvopO2y55jrARO8V4= + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-extensions@^1.0.0: + version "1.9.0" + resolved "https://registry.npm.taobao.org/text-extensions/download/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + integrity sha1-GFPkX+45yUXOb2w2stZZtaq8KiY= + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.nlark.com/thenify-all/download/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.nlark.com/thenify/download/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8= + dependencies: + any-promise "^1.0.0" + +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.npm.taobao.org/throat/download/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha1-1RT+2tlXQMEsLX/HDqhj61Gt43U= + +through2@^4.0.0: + version "4.0.2" + resolved "https://registry.npm.taobao.org/through2/download/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha1-p846wqeosLlmyA58SfBITDsjl2Q= + dependencies: + readable-stream "3" + +"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8: + version "2.3.8" + resolved "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.nlark.com/tmp/download/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha1-bTQzWIl2jSGyvNoKonfO07G/rfk= + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.5" + resolved "https://registry.nlark.com/tmpl/download/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha1-hoPguQK7nCDE9ybjwLafNlGMB8w= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/to-fast-properties/download/to-fast-properties-2.0.0.tgz?cache=0&sync_timestamp=1628418893613&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.nlark.com/to-regex-range/download/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= + dependencies: + is-number "^7.0.0" + +token-stream@1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/token-stream/download/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" + integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= + +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.nlark.com/totalist/download/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha1-pNZaPlRlF3AePlw3pHpwrJf+Vt8= + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha1-2CIjTuyogvmR8PkIgkrSYi3b7OQ= + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/tr46/download/tr46-2.1.0.tgz?cache=0&sync_timestamp=1633302260375&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftr46%2Fdownload%2Ftr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha1-+oeqgcpdWUHajL8fm3SdyWmk4kA= + dependencies: + punycode "^2.1.1" + +trim-newlines@^3.0.0: + version "3.0.1" + resolved "https://registry.nlark.com/trim-newlines/download/trim-newlines-3.0.1.tgz?cache=0&sync_timestamp=1623342300678&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftrim-newlines%2Fdownload%2Ftrim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha1-Jgpdli2LdSQlsy86fbDcrNF2wUQ= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.nlark.com/trough/download/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha1-uLY5zvrX0LsqvTfUM/+Ck++l9AY= + +trouter@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/trouter/download/trouter-2.0.1.tgz#2726a5f8558e090d24c3a393f09eaab1df232df6" + integrity sha1-Jyal+FWOCQ0kw6OT8J6qsd8jLfY= + dependencies: + matchit "^1.0.0" + +tsconfig-paths@^3.11.0: + version "3.11.0" + resolved "https://registry.nlark.com/tsconfig-paths/download/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" + integrity sha1-lUwf6XPaYznHjgawPOLkiBC2XzY= + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.nlark.com/tslib/download/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha1-zy04vcNKE0vK8QkcQfZhni9nLQA= + +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.nlark.com/tslib/download/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha1-2mCGDxwuyqVwOrfTm8Bba/mIuXo= + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.nlark.com/tsutils/download/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha1-tIcX05TOpsHglpg+7Vjp1hcVtiM= + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.nlark.com/type-check/download/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE= + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.nlark.com/type-check/download/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npm.taobao.org/type-detect/download/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw= + +type-fest@^0.18.0: + version "0.18.1" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.18.1.tgz?cache=0&sync_timestamp=1634020516053&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" + integrity sha1-20vBUaSiz07r+a3V23VQjbbMhB8= + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.20.2.tgz?cache=0&sync_timestamp=1634020516053&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ= + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.21.3.tgz?cache=0&sync_timestamp=1634020516053&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc= + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.6.0.tgz?cache=0&sync_timestamp=1634020516053&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha1-jSojcNPfiG61yQraHFv2GIrPg4s= + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.8.1.tgz?cache=0&sync_timestamp=1634020516053&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha1-CeJJ696FHTseSNJ8EFREZn8XuD0= + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.npm.taobao.org/typedarray-to-buffer/download/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha1-qX7nqf9CaRufeD/xvFES/j/KkIA= + dependencies: + is-typedarray "^1.0.0" + +typescript@^4.0.3, typescript@^4.3.2: + version "4.4.4" + resolved "https://registry.npmmirror.com/typescript/download/typescript-4.4.4.tgz?cache=0&sync_timestamp=1634282467870&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftypescript%2Fdownload%2Ftypescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha1-LNAaGh8WBwTTEB/VpY/w+fy4Aww= + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha1-nEEagCpAmpH8bPdAgbq6NLJEmaw= + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/unbox-primitive/download/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha1-CF4hViXsMWJXTciFmr7nilmxRHE= + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/download/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha1-MBrNxSVjFnDTn2FG4Od/9rvevdw= + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/unicode-match-property-ecmascript/download/unicode-match-property-ecmascript-2.0.0.tgz?cache=0&sync_timestamp=1631619258031&other_urls=https%3A%2F%2Fregistry.nlark.com%2Funicode-match-property-ecmascript%2Fdownload%2Funicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha1-VP0W4OyxZ88Ezx91a9zJLrp5dsM= + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/unicode-match-property-value-ecmascript/download/unicode-match-property-value-ecmascript-2.0.0.tgz?cache=0&sync_timestamp=1631619016740&other_urls=https%3A%2F%2Fregistry.nlark.com%2Funicode-match-property-value-ecmascript%2Fdownload%2Funicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha1-GgGqVyR8FMVouJd1pUk4eIGJpxQ= + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/unicode-property-aliases-ecmascript/download/unicode-property-aliases-ecmascript-2.0.0.tgz?cache=0&sync_timestamp=1631609512166&other_urls=https%3A%2F%2Fregistry.nlark.com%2Funicode-property-aliases-ecmascript%2Fdownload%2Funicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha1-CjbLmlhcT2q9Ua0d7dsoXBZSl8g= + +unified@^9.1.0: + version "9.2.2" + resolved "https://registry.nlark.com/unified/download/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" + integrity sha1-Z2SaGr/Dq4XSlpUCkCd16wMUaXU= + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +unist-util-find-all-after@^3.0.2: + version "3.0.2" + resolved "https://registry.nlark.com/unist-util-find-all-after/download/unist-util-find-all-after-3.0.2.tgz#fdfecd14c5b7aea5e9ef38d5e0d5f774eeb561f6" + integrity sha1-/f7NFMW3rqXp7zjV4NX3dO61YfY= + dependencies: + unist-util-is "^4.0.0" + +unist-util-is@^4.0.0: + version "4.1.0" + resolved "https://registry.nlark.com/unist-util-is/download/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" + integrity sha1-l25fRip6Xec9lLcGusG5BnG1d5c= + +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.npm.taobao.org/unist-util-stringify-position/download/unist-util-stringify-position-2.0.3.tgz?cache=0&sync_timestamp=1618328325446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funist-util-stringify-position%2Fdownload%2Funist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha1-zOO/oc34W6c3XR1bF73Eytqb2do= + dependencies: + "@types/unist" "^2.0.2" + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.nlark.com/universalify/download/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY= + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/universalify/download/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= + +upath@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/upath/download/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" + integrity sha1-UMc96mjW9rmQ9R0nnOYIFmXWGos= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.nlark.com/uri-js/download/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34= + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: + version "2.3.0" + resolved "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4= + +v8-to-istanbul@^8.1.0: + version "8.1.0" + resolved "https://registry.npmmirror.com/v8-to-istanbul/download/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + integrity sha1-Cut2OJTxoKFnat+Ki3YSo4kCRGw= + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha1-/JH2uce6FchX9MssXe/uw51PQQo= + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.nlark.com/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.nlark.com/vfile-message/download/vfile-message-2.0.4.tgz?cache=0&sync_timestamp=1628782750676&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvfile-message%2Fdownload%2Fvfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha1-W0O4gXHUCerlhHfRPyPdQdUsNxo= + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile@^4.0.0: + version "4.2.1" + resolved "https://registry.npmmirror.com/vfile/download/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" + integrity sha1-A/Hc4o/GJcYlvGUUNQ+9sA+p5iQ= + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + +vite-plugin-md@^0.6.0: + version "0.6.7" + resolved "https://registry.nlark.com/vite-plugin-md/download/vite-plugin-md-0.6.7.tgz#6318b059a6d968030c908c81f066a8e81ed0c0bc" + integrity sha1-YxiwWabZaAMMkIyB8Gao6B7QwLw= + dependencies: + gray-matter "^4.0.3" + markdown-it "^12.0.6" + +vite-svg-loader@^2.2.0: + version "2.2.0" + resolved "https://registry.nlark.com/vite-svg-loader/download/vite-svg-loader-2.2.0.tgz#b5d6ca948b03e45320cb4f96c44bf88f5bef0a2c" + integrity sha1-tdbKlIsD5FMgy0+WxEv4j1vvCiw= + dependencies: + "@vue/compiler-sfc" "^3.0.11" + svgo "^2.3.0" + +vite@^2.3.7, vite@^2.4.4: + version "2.6.7" + resolved "https://registry.npmmirror.com/vite/download/vite-2.6.7.tgz#e15c1d8327950720b5d7c4ec3fb36a5a58ccf7cb" + integrity sha1-4VwdgyeVByC118TsP7NqWljM98s= + dependencies: + esbuild "^0.13.2" + postcss "^8.3.8" + resolve "^1.20.0" + rollup "^2.57.0" + optionalDependencies: + fsevents "~2.3.2" + +vitepress-theme-demoblock@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/vitepress-theme-demoblock/download/vitepress-theme-demoblock-1.2.2.tgz#0b582dc5d1cc0b4cccc33b245f43518232ea6d55" + integrity sha1-C1gtxdHMC0zMwzskX0NRgjLqbVU= + dependencies: + camelcase "^6.2.0" + globby "^11.0.2" + kolorist "^1.5.0" + markdown-it "^12.0.4" + minimist "^1.2.5" + prettier "^2.2.1" + vitepress "^0.16.1" + yaml "^2.0.0-6" + +vitepress@^0.15.6: + version "0.15.6" + resolved "https://registry.npmmirror.com/vitepress/download/vitepress-0.15.6.tgz#b3d2487384f60deb5e0be7da1f1896c1db75025e" + integrity sha1-s9JIc4T2DeteC+faHxiWwdt1Al4= + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@docsearch/js" "^1.0.0-alpha.28" + "@types/markdown-it" "^12.0.1" + "@vitejs/plugin-vue" "^1.2.3" + "@vue/compiler-sfc" "^3.1.1" + "@vue/server-renderer" "^3.1.1" + chalk "^4.1.1" + compression "^1.7.4" + debug "^4.3.2" + diacritics "^1.3.0" + escape-html "^1.0.3" + fs-extra "^10.0.0" + globby "^11.0.3" + gray-matter "^4.0.3" + lru-cache "^6.0.0" + markdown-it "^12.0.6" + markdown-it-anchor "^7.1.0" + markdown-it-container "^3.0.0" + markdown-it-emoji "^2.0.0" + markdown-it-table-of-contents "^0.5.2" + minimist "^1.2.5" + ora "^5.4.0" + polka "^0.5.2" + prismjs "^1.23.0" + sirv "^1.0.12" + vite "^2.3.7" + vue "^3.1.1" + +vitepress@^0.16.1: + version "0.16.1" + resolved "https://registry.npmmirror.com/vitepress/download/vitepress-0.16.1.tgz#70ba4326a4bdc7152f264868c0775615c0bc16d5" + integrity sha1-cLpDJqS9xxUvJkhowHdWFcC8FtU= + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@docsearch/js" "^1.0.0-alpha.28" + "@types/markdown-it" "^12.0.1" + "@vitejs/plugin-vue" "^1.4.0" + "@vue/compiler-sfc" "^3.2.1" + "@vue/server-renderer" "^3.2.1" + chalk "^4.1.1" + compression "^1.7.4" + debug "^4.3.2" + diacritics "^1.3.0" + escape-html "^1.0.3" + fs-extra "^10.0.0" + globby "^11.0.3" + gray-matter "^4.0.3" + lru-cache "^6.0.0" + markdown-it "^12.0.6" + markdown-it-anchor "^7.1.0" + markdown-it-container "^3.0.0" + markdown-it-emoji "^2.0.0" + markdown-it-table-of-contents "^0.5.2" + minimist "^1.2.5" + ora "^5.4.0" + polka "^0.5.2" + prismjs "^1.23.0" + sirv "^1.0.12" + vite "^2.4.4" + vue "^3.2.1" + +void-elements@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/void-elements/download/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + +vscode-css-languageservice@^5.1.4: + version "5.1.7" + resolved "https://registry.npmmirror.com/vscode-css-languageservice/download/vscode-css-languageservice-5.1.7.tgz#ebbf803b03fde539bd683588cd2da6c4a61b90e2" + integrity sha1-67+AOwP95Tm9aDWIzS2mxKYbkOI= + dependencies: + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-html-languageservice@^4.0.7: + version "4.1.0" + resolved "https://registry.npmmirror.com/vscode-html-languageservice/download/vscode-html-languageservice-4.1.0.tgz#e1662f1ff3b623b910c54d3f4a2aad8f397e53d7" + integrity sha1-4WYvH/O2I7kQxU0/Siqtjzl+U9c= + dependencies: + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-json-languageservice@^4.1.7: + version "4.1.8" + resolved "https://registry.npmmirror.com/vscode-json-languageservice/download/vscode-json-languageservice-4.1.8.tgz#397a39238d496e3e08a544a8b93df2cd13347d0c" + integrity sha1-OXo5I41Jbj4IpUSouT3yzRM0fQw= + dependencies: + jsonc-parser "^3.0.0" + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-jsonrpc@8.0.0-next.3, vscode-jsonrpc@^8.0.0-next.2: + version "8.0.0-next.3" + resolved "https://registry.npmmirror.com/vscode-jsonrpc/download/vscode-jsonrpc-8.0.0-next.3.tgz#b55edff0e550b03f3804aade44aca2699af27255" + integrity sha1-tV7f8OVQsD84BKreRKyiaZryclU= + +vscode-languageserver-protocol@3.17.0-next.9: + version "3.17.0-next.9" + resolved "https://registry.npmmirror.com/vscode-languageserver-protocol/download/vscode-languageserver-protocol-3.17.0-next.9.tgz#0fd4ad43611c96acd83d8d998dbe76668f60e604" + integrity sha1-D9StQ2EclqzYPY2Zjb52Zo9g5gQ= + dependencies: + vscode-jsonrpc "8.0.0-next.3" + vscode-languageserver-types "3.17.0-next.4" + +vscode-languageserver-textdocument@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/vscode-languageserver-textdocument/download/vscode-languageserver-textdocument-1.0.2.tgz#2f9f6bd5b5eb3d8e21424c0c367009216f016236" + integrity sha1-L59r1bXrPY4hQkwMNnAJIW8BYjY= + +vscode-languageserver-types@3.17.0-next.4: + version "3.17.0-next.4" + resolved "https://registry.npmmirror.com/vscode-languageserver-types/download/vscode-languageserver-types-3.17.0-next.4.tgz#f6788b375ec163da8b381f2f3e3f547cbc7fbeec" + integrity sha1-9niLN17BY9qLOB8vPj9UfLx/vuw= + +vscode-languageserver-types@^3.15.1, vscode-languageserver-types@^3.16.0: + version "3.16.0" + resolved "https://registry.npmmirror.com/vscode-languageserver-types/download/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha1-7POT/BIexpdLLaPvsxVWRMUU4kc= + +vscode-languageserver@^8.0.0-next.2: + version "8.0.0-next.3" + resolved "https://registry.npmmirror.com/vscode-languageserver/download/vscode-languageserver-8.0.0-next.3.tgz#36c701a6844ec269505539e3b84a37693760a52f" + integrity sha1-NscBpoROwmlQVTnjuEo3aTdgpS8= + dependencies: + vscode-languageserver-protocol "3.17.0-next.9" + +vscode-nls@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/vscode-nls/download/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" + integrity sha1-mfDaC9nqfNpE5WWnTFSx8rwleEA= + +vscode-pug-languageservice@^0.27.24: + version "0.27.24" + resolved "https://registry.npmmirror.com/vscode-pug-languageservice/download/vscode-pug-languageservice-0.27.24.tgz#fa805c4d3e33dee3681e660a0767136738e68370" + integrity sha1-+oBcTT4z3uNoHmYKB2cTZzjmg3A= + dependencies: + "@volar/code-gen" "^0.27.24" + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + "@volar/transforms" "^0.27.24" + pug-lexer "^5.0.1" + pug-parser "^6.0.0" + vscode-languageserver "^8.0.0-next.2" + +vscode-typescript-languageservice@^0.27.25: + version "0.27.25" + resolved "https://registry.npmmirror.com/vscode-typescript-languageservice/download/vscode-typescript-languageservice-0.27.25.tgz#acd211723b600108c25515388b75d55ce15bb056" + integrity sha1-rNIRcjtgAQjCVRU4i3XVXOFbsFY= + dependencies: + "@volar/shared" "^0.27.24" + semver "^7.3.5" + upath "^2.0.1" + vscode-languageserver "^8.0.0-next.2" + vscode-languageserver-textdocument "^1.0.1" + +vscode-uri@^2.1.2: + version "2.1.2" + resolved "https://registry.npm.taobao.org/vscode-uri/download/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" + integrity sha1-yNQN6T61evMfPHFd1lDiyiwJbxw= + +vscode-uri@^3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/vscode-uri/download/vscode-uri-3.0.2.tgz#ecfd1d066cb8ef4c3a208decdbab9a8c23d055d0" + integrity sha1-7P0dBmy470w6II3s26uajCPQVdA= + +vscode-vue-languageservice@^0.27.0: + version "0.27.30" + resolved "https://registry.npmmirror.com/vscode-vue-languageservice/download/vscode-vue-languageservice-0.27.30.tgz#1f32b0203dd233582f74a457428519a6318f039e" + integrity sha1-HzKwID3SM1gvdKRXQoUZpjGPA54= + dependencies: + "@volar/code-gen" "^0.27.24" + "@volar/html2pug" "^0.27.13" + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + "@volar/transforms" "^0.27.24" + "@vscode/emmet-helper" "^2.7.0" + "@vue/compiler-dom" "^3.2.19" + "@vue/reactivity" "^3.2.19" + "@vue/shared" "^3.2.19" + request-light "^0.5.4" + upath "^2.0.1" + vscode-css-languageservice "^5.1.4" + vscode-html-languageservice "^4.0.7" + vscode-json-languageservice "^4.1.7" + vscode-languageserver "^8.0.0-next.2" + vscode-languageserver-textdocument "^1.0.1" + vscode-pug-languageservice "^0.27.24" + vscode-typescript-languageservice "^0.27.25" + +vscode-web-custom-data@^0.3.2: + version "0.3.6" + resolved "https://registry.npmmirror.com/vscode-web-custom-data/download/vscode-web-custom-data-0.3.6.tgz#7ff374bd39ee4a7c05c77c997d9410520e1d02bc" + integrity sha1-f/N0vTnuSnwFx3yZfZQQUg4dArw= + +vue-eslint-parser@^7.10.0: + version "7.11.0" + resolved "https://registry.nlark.com/vue-eslint-parser/download/vue-eslint-parser-7.11.0.tgz#214b5dea961007fcffb2ee65b8912307628d0daf" + integrity sha1-IUtd6pYQB/z/su5luJEjB2KNDa8= + dependencies: + debug "^4.1.1" + eslint-scope "^5.1.1" + eslint-visitor-keys "^1.1.0" + espree "^6.2.1" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^6.3.0" + +vue-router@^4.0.3: + version "4.0.12" + resolved "https://registry.npmmirror.com/vue-router/download/vue-router-4.0.12.tgz#8dc792cddf5bb1abcc3908f9064136de7e13c460" + integrity sha1-jceSzd9bsavMOQj5BkE23n4TxGA= + dependencies: + "@vue/devtools-api" "^6.0.0-beta.18" + +vue-tsc@^0.2.2: + version "0.2.3" + resolved "https://registry.npmmirror.com/vue-tsc/download/vue-tsc-0.2.3.tgz#12bf48e3c9b1e553d31aad0c641722d5d15841d8" + integrity sha1-Er9I48mx5VPTGq0MZBci1dFYQdg= + dependencies: + vscode-vue-languageservice "^0.27.0" + +vue@^3.1.1, vue@^3.2.1: + version "3.2.20" + resolved "https://registry.npmmirror.com/vue/download/vue-3.2.20.tgz#940f8aa8bf3e3be78243ca582bad41fcd45ae3e6" + integrity sha1-lA+KqL8+O+eCQ8pYK61B/NRa4+Y= + dependencies: + "@vue/compiler-dom" "3.2.20" + "@vue/compiler-sfc" "3.2.20" + "@vue/runtime-dom" "3.2.20" + "@vue/server-renderer" "3.2.20" + "@vue/shared" "3.2.20" + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/w3c-hr-time/download/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha1-ConN9cwVgi35w2BUNnaWPgzDCM0= + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/w3c-xmlserializer/download/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha1-PnEEoFt1FGzGD1ZDgLf2g6zxAgo= + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.7" + resolved "https://registry.nlark.com/walker/download/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/wcwidth/download/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.nlark.com/webidl-conversions/download/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha1-rlnIoAsSFUOirMZcBDT1ew/BGv8= + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.nlark.com/webidl-conversions/download/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha1-kRG01+qArNQPUnDWZmIa+ni2lRQ= + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.nlark.com/whatwg-encoding/download/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha1-WrrPd3wyFmpR0IXWtPPn0nET3bA= + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.nlark.com/whatwg-mimetype/download/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha1-PUseAxLSB5h5+Cav8Y2+7KWWD78= + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.npmmirror.com/whatwg-url/download/whatwg-url-8.7.0.tgz?cache=0&sync_timestamp=1633542687912&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fwhatwg-url%2Fdownload%2Fwhatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha1-ZWp45RD/jzk3vAvL6fXArDWUG3c= + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/which-boxed-primitive/download/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha1-E3V7yJsgmwSf5dhkMOIc9AqJqOY= + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.nlark.com/which-module/download/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/which-pm-runs/download/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + +which@^1.3.1: + version "1.3.1" + resolved "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo= + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE= + dependencies: + isexe "^2.0.0" + +with@^7.0.0: + version "7.0.2" + resolved "https://registry.nlark.com/with/download/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" + integrity sha1-zO461ULSVTinp6gKrSErmChJW6w= + dependencies: + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + assert-never "^1.2.1" + babel-walk "3.0.0-canary-5" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha1-YQY29rH3A4kb00dxzLF/uTtHB5w= + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.nlark.com/wrap-ansi/download/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha1-6Tk7oHEC5skaOyIUePAlfNKFblM= + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.nlark.com/wrap-ansi/download/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM= + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: + version "3.0.3" + resolved "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug= + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.5" + resolved "https://registry.npmmirror.com/ws/download/ws-7.5.5.tgz?cache=0&sync_timestamp=1633200307778&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fws%2Fdownload%2Fws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha1-i0vEr1GM+r0Ec65PmRRCh7M+uIE= + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/xml-name-validator/download/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha1-auc+Bt5NjG5H+fsYH3jWSK1FfGo= + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.nlark.com/xmlchars/download/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha1-Bg/hvLf5x2/ioX24apvDq4lCEMs= + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.nlark.com/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8= + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.nlark.com/y18n/download/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU= + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.nlark.com/yallist/download/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI= + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.nlark.com/yaml/download/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha1-IwHF/78StGfejaIzOkWeKeeSDks= + +yaml@^2.0.0-6: + version "2.0.0-8" + resolved "https://registry.nlark.com/yaml/download/yaml-2.0.0-8.tgz#226365f0d804ba7fb8cc2b527a00a7a4a3d8ea5f" + integrity sha1-ImNl8NgEun+4zCtSegCnpKPY6l8= + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.nlark.com/yargs-parser/download/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A= + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2, yargs-parser@^20.2.3: + version "20.2.9" + resolved "https://registry.nlark.com/yargs-parser/download/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha1-LrfcOwKJcY/ClfNidThFxBoMlO4= + +yargs@^15.1.0: + version "15.4.1" + resolved "https://registry.npmmirror.com/yargs/download/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg= + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^16.0.0, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.npmmirror.com/yargs/download/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha1-HIK/D2tqZur85+8w43b0mhJHf2Y= + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yarn@^1.22.11: + version "1.22.15" + resolved "https://registry.npmmirror.com/yarn/download/yarn-1.22.15.tgz#3431d5f134d3c752a57a9dd7f5e1167627ca3cc3" + integrity sha1-NDHV8TTTx1Klep3X9eEWdifKPMM= + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.nlark.com/yocto-queue/download/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha1-ApTrPe4FAo0x7hpfosVWpqrxChs= + +zwitch@^1.0.0: + version "1.0.5" + resolved "https://registry.nlark.com/zwitch/download/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" + integrity sha1-0R1zgf/tFrdC9q97PyI9XNn+mSA= diff --git a/scripts/add-api.js b/scripts/add-api.js deleted file mode 100644 index 5ffdbf8d9e8552bde1fb74ac10c220b0c0a73bd9..0000000000000000000000000000000000000000 --- a/scripts/add-api.js +++ /dev/null @@ -1,65 +0,0 @@ -const fs = require('fs') -const path = require('path') -const shelljs = require('shelljs') -const program = require('commander') -const { COMPONENTS } = require('./const') - -const DEFAULT_SOURCE_PATH = path.resolve(__dirname, '../../../code/ng-devui/devui') -const DEFAULT_TARGET_PATH = path.resolve(__dirname, '../devui') - -// 从命令行参数中取源文件和目标文件路径 -program - .option('-s, --source <type>', 'Original file path', DEFAULT_SOURCE_PATH) - .option('-t, --target <type>', 'Target file path', DEFAULT_TARGET_PATH) -program.parse(process.argv); - -const { source, target } = program.opts(); - -const sourcePath = source; -const targetPath = target; - -function addApi(sourcePath, targetPath) { - fs.readdir(sourcePath, function(sourcePathError, sourceComponentFolder) { - if (sourcePathError) { - console.error(sourcePathError) - return - } - - sourceComponentFolder - .filter(doc => COMPONENTS.includes(doc)) - .forEach((componentName) => { - const targetDocPath = path.resolve(targetPath, componentName, 'doc') - - // 在组件目录下创建 doc 目录 - if (!fs.existsSync(targetDocPath)) { - fs.mkdirSync(targetDocPath) - } - - // 拷贝中英文 API 文档 - const sourceDocPath = path.resolve(sourcePath, componentName, 'doc') - fs.readdir(sourceDocPath, (sourceDocPathError, sourceDocs) => { - if (sourceDocPathError) { - console.error(sourceDocPathError) - return - } - - sourceDocs.forEach(sourceDoc => { - shelljs.cp(path.resolve(sourceDocPath, sourceDoc), targetDocPath) - }) - }) - - // 修改路由 - const componentRoutePath = path.resolve(targetPath, componentName, 'demo', componentName + '.route.ts') - shelljs.sed('-i', /'..\/doc\/api-cn.md'/, 'ApiCn', componentRoutePath) - shelljs.sed('-i', /'..\/doc\/api-en.md'/, 'ApiEn', componentRoutePath) - shelljs.sed( - '-i', - /const routes = \[/, - 'import ApiCn from \'../doc/api-cn.md\'\nimport ApiEn from \'../doc/api-en.md\'\nconst routes = [', - componentRoutePath - ) - }) - }) -} - -addApi(sourcePath, targetPath) diff --git a/scripts/const.js b/scripts/const.js deleted file mode 100644 index 68506a03980985b78ad5def96bea1a972c4870e4..0000000000000000000000000000000000000000 --- a/scripts/const.js +++ /dev/null @@ -1,69 +0,0 @@ -const COMPONENTS = [ - 'accordion', - 'alert', - 'anchor', - 'auto-complete', - 'avatar', - 'back-top', - 'badge', - 'breadcrumb', - 'button', - 'card', - - 'carousel', - 'cascader', - 'checkbox', - 'data-table', - 'datepicker', - 'dragdrop', - 'drawer', - 'dropdown', - 'editable-select', - 'form', - - - 'fullscreen', - 'gantt', - 'image-preview', - 'input-number', - 'layout', - 'loading', - 'modal', - 'multi-auto-complete', - 'pagination', - 'panel', - - 'popover', - 'progress', - 'quadrant-diagram', - 'radio', - 'rate', - 'read-tip', - 'search', - 'select', - 'slider', - 'splitter', - - 'status', - 'steps-guide', - 'sticky', - 'tabs', - 'tags', - 'tags-input', - 'text-input', - 'textarea', - 'time-axis', - 'time-picker', - - 'toast', - 'toggle', - 'tooltip', - 'transfer', - 'tree', - 'tree-select', - 'upload', -] - -module.exports = { - COMPONENTS -} diff --git a/scripts/convert-component-route.js b/scripts/convert-component-route.js deleted file mode 100644 index eb459e2396ec2f1e5719d5c3e2111433f99a29cc..0000000000000000000000000000000000000000 --- a/scripts/convert-component-route.js +++ /dev/null @@ -1,72 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const shelljs = require('shelljs'); -const program = require('commander'); - -const DEFAULT_SOURCE_PATH = path.resolve(__dirname, '../docs/component.route.ts'); -const DEFAULT_TARGET_PATH = path.resolve(__dirname, '../src/components'); - -// 从命令行参数中取源文件和目标文件路径 -program - .option('-s, --source <type>', 'Original file path', DEFAULT_SOURCE_PATH) - .option('-t, --target <type>', 'Target file path', DEFAULT_TARGET_PATH) -program.parse(process.argv); - -const { source, target } = program.opts(); - -/** - * 将 ng-devui 的组件路由文件转换成 vue-devui 的路由文件 - * - * 主要转换规则: - * 1. loadChildren 整行移除,loadChildren 分多行的,需要将多行都移除 - * 2. data 改成 meta - * 3. import 的组件都从 app-demo-cell 导入 - * - * 例如: - * import { ExamplePanelComponent } from './example-panel.component'; -> import ExamplePanelComponent from './app-demo-cell.vue'; - * import { GetStartedComponent } from './get-started.component'; -> import GetStartedComponent from './app-demo-cell.vue'; - * import { ColorComponent } from './color/color.component'; -> import ColorComponent from './app-demo-cell.vue'; - * import { ThemeGuideComponent } from './theme-guide.component'; -> import ThemeGuideComponent from './app-demo-cell.vue'; - * - * { - * path: 'accordion', - * component: ExamplePanelComponent, - * loadChildren: () => import('../../../devui/accordion/demo/accordion-demo.moudule').then((m) => m.AccordionDemoModule), - * data: { - * type: '导航', - * enType: 'Navigation', - * name: 'Accordion', - * cnName: '手风琴', - * }, - * }, - * -> - * { - * path: 'accordion', - * component: ExamplePanelComponent, - * meta: { - * type: '导航', - * enType: 'Navigation', - * name: 'Accordion', - * cnName: '手风琴', - * }, - * }, - */ -function convertComponentRoute(source, target) { - shelljs.sed('-i', /import { ExamplePanelComponent } from '.\/example-panel.component'/, 'import ExamplePanelComponent from \'.\/app-demo-cell.vue\'', source); - shelljs.sed('-i', /import { GetStartedComponent } from '.\/get-started.component'/, 'import GetStartedComponent from \'.\/app-demo-cell.vue\'', source); - shelljs.sed('-i', /import { ColorComponent } from '.\/color\/color.component'/, 'import ColorComponent from \'.\/app-demo-cell.vue\'', source); - shelljs.sed('-i', /import { ThemeGuideComponent } from '.\/theme-guide.component'/, 'import ThemeGuideComponent from \'.\/app-demo-cell.vue\'', source); - - shelljs.sed('-i', /redirectTo: 'get-start'/, 'redirect: \'/components/button\'', source); - - shelljs.sed('-i', /^.*loadChildren.*$/, '', source); - shelljs.sed('-i', /^.*import\(.*$/, '', source); - - shelljs.sed('-i', /data: {/, 'meta: {', source); - - shelljs.sed('-i', /];/, '];\n\nexport default routesConfig;', source); - - shelljs.cp(source, target); -} - -convertComponentRoute(source, target); diff --git a/scripts/delete-old-api.js b/scripts/delete-old-api.js deleted file mode 100644 index b4517dffa7f8aab48c7b8372371a6010c250aad1..0000000000000000000000000000000000000000 --- a/scripts/delete-old-api.js +++ /dev/null @@ -1,28 +0,0 @@ -const fs = require('fs') -const path = require('path') -const shelljs = require('shelljs') -const { COMPONENTS } = require('./const') - -const targetPath = path.resolve(__dirname, '../devui') - -function deleteOldApi(targetPath) { - fs.readdir(targetPath, function(targetPathError, targetComponentFolder) { - if (targetPathError) { - console.error(targetPathError) - return - } - - targetComponentFolder - .filter(doc => COMPONENTS.includes(doc)) - .forEach((componentName) => { - const targetApiPath = path.resolve(targetPath, componentName, 'api') - - // 在组件目录下创建 doc 目录 - if (fs.existsSync(targetApiPath)) { - shelljs.rm('-rf', targetApiPath); - } - }) - }) -} - -deleteOldApi(targetPath) diff --git a/src/app.route.ts b/src/app.route.ts deleted file mode 100644 index 0eb527c6fb524137a5b0072e3ef3ed9b6fc14146..0000000000000000000000000000000000000000 --- a/src/app.route.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createRouter, createWebHistory } from 'vue-router' -import AppContentRoutes from './components/component.route' -import AppContent from './components/app-content.vue' - -const routerHistory = createWebHistory() - -const router = createRouter({ - history: routerHistory, - routes: [ - { - path: '/', - redirect: '/components' - }, - { - path: '/components', - component: AppContent, - children: AppContentRoutes - } - ] -}) - -export default router diff --git a/src/app.vue b/src/app.vue deleted file mode 100644 index 6d85dc1b701e4ed630b4b3426b2d2c681eeaeb92..0000000000000000000000000000000000000000 --- a/src/app.vue +++ /dev/null @@ -1,689 +0,0 @@ -<template> - <div class="app-container"> - <div class="app-bar"> - <header> - <h1 class="title"> - <a target="_self" href="/home"> - <span class="logo"> - <svg - width="26px" - height="26px" - viewBox="0 0 26 26" - version="1.1" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - > - <defs> - <linearGradient x1="89.5364583%" y1="21.60078%" x2="7.57349918%" y2="65.7395747%" id="linearGradient-1"> - <stop stop-color="#2954C8" offset="0%"></stop> - <stop stop-color="#5170FF" offset="100%"></stop> - </linearGradient> - <linearGradient x1="89.5364583%" y1="21.4573588%" x2="7.57349918%" y2="65.8190624%" id="linearGradient-2"> - <stop stop-color="#2954C8" offset="0%"></stop> - <stop stop-color="#5170FF" offset="100%"></stop> - </linearGradient> - <linearGradient x1="-11.5260417%" y1="24.3907324%" x2="87.1145833%" y2="74.8850926%" id="linearGradient-3"> - <stop stop-color="#89D2FF" offset="0%"></stop> - <stop stop-color="#5170FF" offset="100%"></stop> - </linearGradient> - <linearGradient x1="0%" y1="18.4813953%" x2="75.9513522%" y2="81.5186047%" id="linearGradient-4"> - <stop stop-color="#89D2FF" offset="0%"></stop> - <stop stop-color="#5170FF" offset="100%"></stop> - </linearGradient> - </defs> - <g id="Devui-Logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> - <g id="Group-2" transform="translate(3.000000, 0.000000)"> - <g> - <path - d="M4.28576801,9.22873192 L9.32098286,6.02205882 L13.1143389,8.49673203 L0.010890596,17.0193525 L0.010890596,17.0193525 C0.010890596,13.8625823 1.62310848,10.9244448 4.28576801,9.22873192 Z" - id="Path-39-Copy-3" - fill="url(#linearGradient-1)" - ></path> - <path - d="M8.76945593,17.4828869 L14.1939212,14.0196078 L18.2867527,16.6963836 L4.14882163,25.9150327 L4.14882163,25.9150327 C4.14882163,22.4998846 5.89095741,19.3206798 8.76945593,17.4828869 Z" - id="Path-39-Copy-2" - fill="url(#linearGradient-2)" - transform="translate(11.217787, 19.967320) scale(-1, 1) translate(-11.217787, -19.967320) " - ></path> - <path - d="M0.183304389,2.48689958e-13 L13.1143389,8.49673203 L9.42310099,10.9017055 L9.42310099,10.9017055 C4.36778167,11.0371959 0.159798979,7.04888649 0.0243085926,1.99356717 C0.00937841938,1.43650334 0.0453320846,0.879239543 0.13172203,0.32871271 L0.183304389,2.48689958e-13 Z" - id="Path-38-Copy-3" - fill="url(#linearGradient-3)" - ></path> - <path - d="M4.54131151,6.55708742 L19.8945577,16.6535948 L16.2033199,19.0585682 L11.1830136,17.9470593 C6.34348625,16.8755752 3.2888836,12.0837536 4.36036765,7.24422626 C4.41158805,7.01288123 4.47194996,6.78365535 4.54131151,6.55708742 L4.54131151,6.55708742 Z" - id="Path-38-Copy-2" - fill="url(#linearGradient-4)" - transform="translate(12.021690, 12.807828) scale(-1, 1) translate(-12.021690, -12.807828) " - ></path> - </g> - </g> - </g> - </svg> - </span> - <span class="text">DevUI</span> - </a> - </h1> - <div class="main-nav"> - <a class="main-nav-item" target="_self" href="/design-cn"> - <span>设计体系</span> - </a> - <a class="main-nav-item" routerLink="components"> - <span>组件</span> - </a> - <a class="main-nav-item" target="_self" href="/icon"> - <span>图标库</span> - </a> - <a - class="main-nav-item" - target="_blank" - rel="noopener noreferrer" - href="https://github.com/DevCloudFE/ng-devui/releases" - > - <span>版本历程</span> - </a> - <span class="main-nav-item"> - <!-- TODO: 版本下拉框 d-select --> - </span> - <span class="main-nav-item"> - <!-- TODO: 主题选择器 d-dropdown --> - </span> - </div> - <div id="headerMenu" class="header-menu"><span></span></div> - </header> - </div> - <!-- <app-content></app-content> --> - <router-view></router-view> - </div> -</template> - -<script lang="ts"> -import { defineComponent } from 'vue' -import AppContent from './components/app-content.vue' - -export default defineComponent({ - name: 'App', - components: { - AppContent, - }, - methods: { - } -}) -</script> - -<style lang="scss"> -@import './assets/styles.scss'; -@import '../devui/style/devui'; -@import '../devui/style/theme/color'; -@import '../devui/style/core/font'; - -body { - background: $devui-base-bg; -} - -@mixin menu() { - position: fixed; - display: block; - font-size: $devui-font-size; - z-index: 5; - width: 4em; - height: 4em; - padding: 1em; - transition: all 0.2s ease-out; - - span { - position: relative; - display: block; - margin-top: 0.9em; - - &::before, - &::after { - position: absolute; - top: -0.55em; - content: ' '; - } - - &::after { - top: 0.55em; - } - - &, - &::before, - &::after { - background-color: $devui-text; - width: 100%; - height: 0.2em; - transition: all 0.4s; - } - } - - &.active span { - background: transparent; - - &::before { - transform: rotate(45deg) translate(0.5em, 0.4em); - } - - &::after { - transform: rotate(-45deg) translate(0.4em, -0.3em); - } - } -} - -.app-container { - display: flex; - flex-direction: column; - transform: none; - - .app-bar { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 10; - } - - a.main-nav-item { - cursor: pointer; - } - - header { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - height: 50px; - background: $devui-base-bg; - box-shadow: 0 2px 4px 0 $devui-shadow; - - a { - line-height: $line-height-base; - color: $devui-text; - text-decoration: none; - } - - a:hover, - a:focus { - color: $devui-text; - text-decoration: none; - } - } - - h1.title { - font-size: $devui-font-size-page-title; - margin: 0; - font-weight: $font-title-weight; - padding: 9px 20px; - box-sizing: border-box; - - .logo, - .text { - display: inline-block; - vertical-align: top; - } - - .ui { - font-weight: normal; - } - - a:hover { - text-decoration: none; - } - - .internal { - font-size: small; - background-color: #5e7ce0; - color: white; - margin-left: 5px; - font-weight: normal; - line-height: 10px; - display: inline-block; - padding: 3px 4px 0; - } - } - - .main-nav { - display: flex; - justify-content: flex-end; - margin-right: 20px; - } - - .header-menu { - right: 5px; - @include menu(); - - display: none; - - span { - &, - &::before, - &::after { - background: $devui-text; - } - } - } - - .main-nav-item { - display: flex; - align-items: center; - padding: 5px 0; - margin: 0 12px; - color: $devui-text; - cursor: pointer; - - & > span { - font-size: $devui-font-size-page-title; - line-height: $line-height-base; - } - - &.version-label { - cursor: default; - - &:hover, - &:focus { - color: inherit; - } - } - - &.language { - cursor: pointer; - min-width: 50px; - text-align: center; - - &:hover { - color: inherit; - background: $devui-list-item-hover-bg; - } - } - } - - a.main-nav-item { - &:hover { - text-decoration: none; - color: $devui-list-item-hover-text; - } - - &:active, - &:focus { - color: $devui-brand; - } - } - - .wrapper { - position: absolute; - top: 50px; - left: 0; - right: 0; - bottom: 0; - - .sidebar { - box-sizing: border-box; - position: fixed; - top: 120px; - bottom: 0; - left: 0; - width: 240px; - margin-left: -240px; - border-right: 1px solid $devui-dividing-line; - height: 100%; - overflow-y: hidden; - z-index: 2; - background: $devui-base-bg; - transition: all 0.2s ease-out; - - &:hover { - overflow-y: auto; - } - } - - .menu-link { - left: 0; - background: rgba(#000000, 0.7); - @include menu(); - } - - .doc-viewer-container { - width: 100%; - margin-left: 0; - transition: all 0.2s ease-out; - - .main { - width: 100%; - padding: 0 20px; - } - } - - &.active { - .sidebar { - overflow-y: auto; - left: 240px; - } - - .devui-components-search { - margin-left: 0; - } - - .doc-viewer-container { - margin-left: 240px; - } - - .menu-link { - left: 240px; - } - } - } - - .tabNav { - text-decoration: none; - width: 100%; - height: 100%; - display: block; - } - - .side-nav { - background: $devui-base-bg; - padding-bottom: 144px; - - ul { - margin: 0; - } - - .panel-body { - padding: 0; - background-color: $devui-base-bg; - } - - .panel-title { - font-size: $devui-font-size; - font-weight: normal; - color: $devui-placeholder; - margin: 0; - position: relative; - height: 40px; - display: flex; - align-items: center; - - span { - @include font-content(); - } - } - - .panel > .panel-heading, - .panel.panel-default > .panel-heading { - background: $devui-base-bg; - padding-left: 20px; - } - - .panel { - box-shadow: none; - } - - [class*='panel-'] > .panel-heading { - cursor: pointer; - - &:hover { - color: $devui-list-item-hover-text; - } - } - - .panel-group .panel-heading + .panel-collapse > .panel-body { - border: none; - } - } -} - -.devui-menu { - outline: none; - margin-bottom: 0; - padding-left: 0; - list-style: none; - z-index: 1050; - background: $devui-base-bg; -} - -.devui-menu-item { - text-overflow: ellipsis; - overflow: hidden; - padding-left: 20px; - height: 40px; - display: flex; - align-items: center; - - &:not(.devui-menu-item-selected):hover { - background-color: $devui-list-item-hover-bg; - } -} - -.devui-menu-item > a { - @include font-content(); - - display: block; - color: $devui-text; - text-decoration: none; -} - -.devui-menu-item-selected { - color: $devui-brand; - background-color: $devui-list-item-selected-bg; - border-right: 2px solid $devui-brand; - - a { - color: inherit; - } -} - -.main { - .docs-header { - & > h1 { - @include font-title(); - - margin: 1em 0; - } - - h3 { - @include font-title($devui-font-size-card-title); - } - } -} - -.demo-container { - position: relative; - padding-bottom: 30px; - margin-top: 20px; -} - -.demo-content { - margin-right: 200px; -} - -.demo-example { - margin-bottom: 20px; -} - -.demo-nav { - position: absolute; - height: 100%; - top: 0; - right: 0; - width: 150px; - line-height: 24px; -} - -.demo-nav .items { - margin-top: 10px; - cursor: pointer; -} - -.demo-nav .items > li:hover { - color: $devui-brand; -} - -.demo-nav-active { - color: $devui-brand; -} - -.demo-title { - @include font-title($devui-font-size-card-title); - - color: $devui-text; - margin-bottom: 10px; - height: 24px; - display: flex; - align-items: center; -} - -.demo-text { - @include font-content(); - - color: $devui-text; -} - -.readme { - .hljs { - background: transparent; - } - - pre { - background-color: $devui-base-bg; - border: none; - - code { - border: 1px solid $devui-dividing-line; - overflow-x: auto; - } - } - - p { - margin: 1em 0; - } -} - -@media (max-width: 1024px) { - .app-container { - .header-menu { - display: block; - } - - header { - flex-direction: column; - justify-items: center; - - .main-nav { - display: none; - } - - &.active { - height: 100%; - - .main-nav { - display: flex; - flex-direction: column; - width: 100%; - margin-left: 20px; - } - } - } - } -} - -@media (min-width: 1024px) { - .app-container .wrapper { - .sidebar { - left: 240px; - } - - .devui-components-search { - margin-left: 0; - } - - .doc-viewer-container { - margin-left: 240px; - width: calc(100% - 240px); - - .main { - padding: 0 60px; - } - } - - .menu-link { - display: none; - } - } -} - -@media (min-width: 1280px) { - .app-container .wrapper { - .doc-viewer-container { - .main { - padding: 0 20%; - } - } - } -} - -.main-nav-item .show-themable { - display: none; - display: var(--iehack, flex); - align-items: center; - - d-select, - d-toggle { - margin-right: 5px; - } -} - -.demo-example.active.anchor-active-by-anchor-link, -.demo-example.active.anchor-active-by-fragment { - animation: hightlight-and-disapear 1 3s linear; - outline-offset: 8px; -} - -@keyframes hightlight-and-disapear { - 0% { - outline: invert none medium; - } - - 2% { - outline: 0 none rgba(255, 255, 255, 0); - } - - 10% { - outline: 1px dashed $devui-brand; - } - - 50% { - outline: 1px dashed $devui-brand; - } - - 90% { - outline: 1px dashed rgba(255, 255, 255, 0); - } - - 99% { - outline: 0 none rgba(255, 255, 255, 0); - } - - 100% { - outline: invert none medium; - } -} - -.side-nav d-accordion d-accordion-list d-accordion-menu .devui-accordion-open-icon { - display: none !important; -} - -.side-nav d-accordion d-accordion-list { - box-shadow: none !important; -} - -.devui-components-search { - padding: 24px 0 24px 16px; - position: fixed; - margin-left: -240px; - transition: margin-left 0.2s; - - d-search { - width: 215px; - } -} -</style> \ No newline at end of file diff --git a/src/assets/styles.scss b/src/assets/styles.scss deleted file mode 100755 index bf47d33d9ea8876d687f390c334fd62abcb48afd..0000000000000000000000000000000000000000 --- a/src/assets/styles.scss +++ /dev/null @@ -1,182 +0,0 @@ -@import '../devui/style/devui'; -// @import '~@devui-design/icons/icomoon/devui-icon.css'; -@import '../devui/style/theme/_font'; - -.markdown { - color: $devui-text; - font-size: $devui-font-size-page-title; - line-height: 1.8; - - a { - color: $devui-link; - - &:hover { - color: $devui-link-active; - text-decoration: underline; - cursor: pointer; - } - } -} - -.highlight { - line-height: 1.5; - position: relative; -} - -code[class*='language-'], -pre[class*='language-'], -pre code { - white-space: pre; - font-family: Lucida Console, Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace; -} - -pre { - display: block; - margin: 0 0 10px; - line-height: 1.42857143; - color: $devui-text; - word-break: break-all; - word-wrap: break-word; - border: 1px solid $devui-dividing-line; - border-radius: 1px; -} - -.hljs { - background: $devui-area; - color: $devui-text; - font-size: $devui-font-size; -} - -pre code { - display: block; - color: $devui-text; - background: $devui-base-bg; - line-height: 1.5; - padding: 10px 15px; - border-radius: 4px; - overflow-x: auto; -} - -code, -kbd, -pre, -samp { - font-family: Consolas, Menlo, Courier, monospace; -} - -section { - margin-bottom: 0 !important; -} - -.markdown { - width: 100%; - display: block; - overflow-x: auto; - - table { - font-size: $devui-font-size; - } - - p { - margin: 1em 0; - } - - a code { - text-decoration: underline; - } - - pre code { - font-size: $devui-font-size; - padding: 0.5em; - background-color: $devui-area; - } -} - -.markdown table { - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - border: 1px solid $devui-line; - width: 100%; - margin: 8px 0 16px; - - th, - td { - border: 1px solid $devui-dividing-line; - padding: 8px 16px; - text-align: left; - } - - th { - background: $devui-area; - white-space: nowrap; - color: $devui-text; - font-weight: 600; - } -} - -.markdown h2 { - font-size: 22px; -} - -.markdown h3 { - font-size: 18px; -} - -.markdown h2, -.markdown h3, -.markdown h4, -.markdown h5, -.markdown h6 { - color: $devui-text; - margin: 1.6em 0 0.6em; - font-weight: 500; - clear: both; -} - -code { - padding: 2px 4px; - // font-size: 90%; - color: #c7254e; - background-color: $devui-area; - border-radius: 1px; -} - -.readme { - h1 { - // font-size: 30px; - @include font-title(); - - padding: 20px 0; - } - - h2 { - // font-size: 24px; - @include font-title($devui-font-size-card-title); - - padding: 40px 0 15px; - } - - h3 { - // font-size: 18px; - @include font-title($devui-font-size-card-title); - - padding: 30px 0 10px; - } - - h1, - h2, - h3 { - // font-weight: 300; - margin: 0; - } - - pre code { - padding: 0.5em; - } -} - -[dTextInput]::-ms-clear, -[dTextInput]::-ms-reveal { - display: none; -} diff --git a/src/components/app-content.vue b/src/components/app-content.vue deleted file mode 100644 index f23b2777956d129523cc465ec7b486f78ce670a5..0000000000000000000000000000000000000000 --- a/src/components/app-content.vue +++ /dev/null @@ -1,110 +0,0 @@ -<template> - <div class="wrapper"> - <div id="menuLink" class="menu-link"> - <span></span> - </div> - <div class="devui-components-search"> - <!-- TODO: 搜索框 --> - </div> - <div class="sidebar"> - <ul class="devui-menu" style="margin-bottom: 0"> - <li class="devui-menu-item"> - <a href="/get-start">快速开始</a> - </li> - <li class="devui-menu-item"> - <a href="/color" style="position: relative" - >颜色变量 - <sup class="devui-beta-label">Beta</sup> - </a> - </li> - <li class="devui-menu-item"> - <a href="/theme-guide" style="position: relative">主题化使用指南 </a> - </li> - </ul> - <nav class="side-nav"> - <!-- TODO: 左侧组件导航 d-accordion --> - <d-accordion :data="componentsData" :linkType="'routerLink'"></d-accordion> - </nav> - </div> - <div class="doc-viewer-container"> - <!-- TODO: 文档主体内容 --> - <!-- <app-demo-cell></app-demo-cell> --> - <router-view :key="key"></router-view> - </div> - </div> -</template> - -<script lang="ts"> -import { groupBy, map } from 'lodash-es' -import { routesConfig } from './component.route' -import AppDemoCell from './app-demo-cell.vue' -import Accordion from '../../devui/accordion/accordion' - -export default { - name: 'app-content', - components: { - AppDemoCell, - 'd-accordion': Accordion - }, - data(): any { - return { - componentsData: [] - } - }, - computed: { - key() { - return this.$route.fullPath - } - }, - created() { - this.generateComponentData(); - }, - methods: { - generateComponentData() { - // TODO: 补充类型 - const routesWithData = map(routesConfig, (route: any) => { - if (!route.meta) { - route.meta = {}; - } - return route; - }); - const groupedRoutesObj = groupBy(routesWithData, - (route: any) => { - return (route as any).meta.type || '通用'; - }); - for (const key in groupedRoutesObj) { - if (key) { - const group = groupedRoutesObj[key].map((item: any) => { - if (item.meta.name) { - return { - title: item.meta.name + ' ' + item.meta.cnName, - link: '/components/' + item.path + '/demo', - }; - } else { - return {}; - } - } - ).filter((item: any) => Object.keys(item).length !== 0) - .sort(function (s1: any, s2: any) { - const prev = (s1.title).toUpperCase(); - const next = (s2.title).toUpperCase(); - if (prev < next) { - return -1; - } - if (prev > next) { - return 1; - } - return 0; - }); - const componentItem: any = { title: key, children: group, open: true }; - this.componentsData.push(componentItem); - } - } - } - }, -} -</script> - -<style lang="scss"> - -</style> \ No newline at end of file diff --git a/src/components/app-demo-cell.vue b/src/components/app-demo-cell.vue deleted file mode 100644 index 38093348d6c898e6f2195088a8b5ee34f190ad49..0000000000000000000000000000000000000000 --- a/src/components/app-demo-cell.vue +++ /dev/null @@ -1,57 +0,0 @@ -<template> - <div class="main"> - <div class="docs-header"> - <h1>{{ data.name }} {{ data.cnName }}</h1> - <div style="margin-bottom: 40px">{{ data.description }}</div> - <div v-if="data.tmw"> - <h3>何时使用</h3> - <div style="margin-bottom: 20px" v-html="data.tmw"></div> - </div> - <!-- TODO: d-tabs --> - <d-tabs - v-model="activeTab" - :showContent="false" - @activeTabChange="activeTabChange($event)" - > - <d-tab id="demo" title="demo" tabId="demo"> </d-tab> - <d-tab id="api" title="API" tabId="api"> </d-tab> - </d-tabs> - </div> - <div class="examples-viewer"> - <div class="examples-viewer-wrapper"> - <!-- TODO: Demo列表 --> - <router-view></router-view> - </div> - </div> - </div> -</template> - -<script> -import ButtonDemo from '../../devui/button/demo/button-demo'; -import Tabs from '../../devui/tabs/tabs'; -import Tab from '../../devui/tabs/tab'; - -export default { - name: 'app-demo-cell', - components: { - 'd-button-demo': ButtonDemo, - 'd-tabs': Tabs, - 'd-tab': Tab, - }, - data() { - return { - data: {}, - activeTab: 'demo', - }; - }, - methods: { - activeTabChange(a) { - this.$router.push(a); - }, - }, - mounted() { - this.data = this.$route.meta; - this.activeTab = /\/demo$/.test(this.$route.path) ? 'demo' : 'api'; - }, -}; -</script> diff --git a/src/components/component.route.ts b/src/components/component.route.ts deleted file mode 100755 index 4b10142a5928de4c4f9d4a014eee7a9210b6b7cc..0000000000000000000000000000000000000000 --- a/src/components/component.route.ts +++ /dev/null @@ -1,728 +0,0 @@ -import ExamplePanelComponent from './app-demo-cell.vue'; -import GetStartedComponent from './app-demo-cell.vue'; -import ColorComponent from './app-demo-cell.vue'; -import ThemeGuideComponent from './app-demo-cell.vue'; - -import accordionRoutes from '../../devui/accordion/demo/accordion.route' -import alertRoutes from '../../devui/alert/demo/alert.route' -import anchorRoutes from '../../devui/anchor/demo/anchor.route' -import autoCompleteRoutes from '../../devui/auto-complete/demo/auto-complete.route' -import avatarRoutes from '../../devui/avatar/demo/avatar.route' -import backTopRoutes from '../../devui/back-top/demo/back-top.route' -import badgeRoutes from '../../devui/badge/demo/badge.route' -import breadcrumbRoutes from '../../devui/breadcrumb/demo/breadcrumb.route' -import buttonRoutes from '../../devui/button/demo/button.route' -import cardRoutes from '../../devui/card/demo/card.route' - -import carouselRoutes from '../../devui/carousel/demo/carousel.route' -import cascaderRoutes from '../../devui/cascader/demo/cascader.route' -import checkboxRoutes from '../../devui/checkbox/demo/checkbox.route' -import dataTableRoutes from '../../devui/data-table/demo/data-table.route' -import datepickerRoutes from '../../devui/datepicker/demo/datepicker.route' -import dragdropRoutes from '../../devui/dragdrop/demo/dragdrop.route' -import drawerRoutes from '../../devui/drawer/demo/drawer.route' -import dropdownRoutes from '../../devui/dropdown/demo/dropdown.route' -import editableSelectRoutes from '../../devui/editable-select/demo/editable-select.route' -import formRoutes from '../../devui/form/demo/form.route' - -import fullscreenRoutes from '../../devui/fullscreen/demo/fullscreen.route' -import ganttRoutes from '../../devui/gantt/demo/gantt.route' -import imagePreviewRoutes from '../../devui/image-preview/demo/image-preview.route' -import inputNumberRoutes from '../../devui/input-number/demo/input-number.route' -import layoutRoutes from '../../devui/layout/demo/layout.route' -import loadingRoutes from '../../devui/loading/demo/loading.route' -import modalRoutes from '../../devui/modal/demo/modal.route' -import multiAutoCompleteRoutes from '../../devui/multi-auto-complete/demo/multi-auto-complete.route' -import paginationRoutes from '../../devui/pagination/demo/pagination.route' -import panelRoutes from '../../devui/panel/demo/panel.route' - -import popoverRoutes from '../../devui/popover/demo/popover.route' -import progressRoutes from '../../devui/progress/demo/progress.route' -import quadrantDiagramRoutes from '../../devui/quadrant-diagram/demo/quadrant-diagram.route' -import radioRoutes from '../../devui/radio/demo/radio.route' -import rateRoutes from '../../devui/rate/demo/rate.route' -import readTipRoutes from '../../devui/read-tip/demo/read-tip.route' -import searchRoutes from '../../devui/search/demo/search.route' -import selectRoutes from '../../devui/select/demo/select.route' -import sliderRoutes from '../../devui/slider/demo/slider.route' -import splitterRoutes from '../../devui/splitter/demo/splitter.route' - -import statusRoutes from '../../devui/status/demo/status.route' -import stepsGuideRoutes from '../../devui/steps-guide/demo/steps-guide.route' -import stickyRoutes from '../../devui/sticky/demo/sticky.route' -import tabsRoutes from '../../devui/tabs/demo/tabs.route' -import tagsRoutes from '../../devui/tags/demo/tags.route' -import tagsInputRoutes from '../../devui/tags-input/demo/tags-input.route' -import textInputRoutes from '../../devui/text-input/demo/text-input.route' -import textareaRoutes from '../../devui/textarea/demo/textarea.route' -import timeAxisRoutes from '../../devui/time-axis/demo/time-axis.route' -import timePickerRoutes from '../../devui/time-picker/demo/time-picker.route' - -import toastRoutes from '../../devui/toast/demo/toast.route' -import toggleRoutes from '../../devui/toggle/demo/toggle.route' -import tooltipRoutes from '../../devui/tooltip/demo/tooltip.route' -import transferRoutes from '../../devui/transfer/demo/transfer.route' -import treeRoutes from '../../devui/tree/demo/tree.route' -import treeSelectRoutes from '../../devui/tree-select/demo/tree-select.route' -import uploadRoutes from '../../devui/upload/demo/upload.route' - -export const routesConfig = [ - { - path: '', - redirect: '/components/button/demo', - pathMatch: 'full', - meta: {}, - }, - { - path: 'get-start', - component: GetStartedComponent, - meta: { nodisplay: true }, - }, - { - path: 'color', - component: ColorComponent, - meta: {nodisplay: true} - }, - { - path: 'theme-guide', - component: ThemeGuideComponent, - meta: { nodisplay: true }, - }, - { - path: 'accordion', - component: ExamplePanelComponent, - children: accordionRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'Accordion', - cnName: '手风琴', - }, - }, - { - path: 'alert', - component: ExamplePanelComponent, - children: alertRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Alert', - cnName: '警告', - }, - }, - { - path: 'anchor', - component: ExamplePanelComponent, - children: anchorRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'Anchor', - cnName: '锚点', - }, - }, - { - path: 'auto-complete', - component: ExamplePanelComponent, - children: autoCompleteRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'AutoComplete', - cnName: '自动补全', - }, - }, - { - path: 'avatar', - component: ExamplePanelComponent, - children: avatarRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Avatar', - cnName: '头像', - }, - }, - { - path: 'ImagePreview', - component: ExamplePanelComponent, - children: imagePreviewRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'ImagePreview', - cnName: '图片预览', - }, - }, - { - path: 'breadcrumb', - component: ExamplePanelComponent, - children: breadcrumbRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'Breadcrumb', - cnName: '面包屑', - }, - }, - { - path: 'back-top', - component: ExamplePanelComponent, - children: backTopRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'BackTop', - cnName: '回到顶部', - }, - }, - { - path: 'button', - component: ExamplePanelComponent, - children: buttonRoutes, - meta: { - name: 'Button', - cnName: '按钮', - }, - }, - { - path: 'badge', - component: ExamplePanelComponent, - children: badgeRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Badge', - cnName: '徽标', - }, - }, - { - path: 'card', - component: ExamplePanelComponent, - children: cardRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Card', - cnName: '卡片', - }, - }, - { - path: 'carousel', - component: ExamplePanelComponent, - children: carouselRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Carousel', - cnName: '走马灯', - }, - }, - { - path: 'checkbox', - component: ExamplePanelComponent, - children: checkboxRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'CheckBox', - cnName: '复选框', - }, - }, - { - path: 'common', - component: ExamplePanelComponent, - children: accordionRoutes, - meta: { - name: 'Common', - cnName: '公共方法', - }, - }, - { - path: 'datatable', - component: ExamplePanelComponent, - children: dataTableRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'DataTable', - cnName: '表格', - }, - }, - { - path: 'datepicker', - component: ExamplePanelComponent, - children: datepickerRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'DatePicker', - cnName: '日期选择器', - }, - }, - { - path: 'multi-auto-complete', - component: ExamplePanelComponent, - children: multiAutoCompleteRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'MultiAutoComplete', - cnName: '多项自动补全', - }, - }, - { - path: 'form', - component: ExamplePanelComponent, - children: formRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Form', - cnName: '表单', - }, - }, - { - path: 'fullscreen', - component: ExamplePanelComponent, - children: fullscreenRoutes, - meta: { - name: 'Fullscreen', - cnName: '全屏', - }, - }, - { - path: 'transfer', - component: ExamplePanelComponent, - children: transferRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Transfer', - cnName: '穿梭框', - }, - }, - { - path: 'dragdrop', - component: ExamplePanelComponent, - children: dragdropRoutes, - meta: { - name: 'DragDrop', - cnName: '拖拽', - }, - }, - { - path: 'drawer', - component: ExamplePanelComponent, - children: drawerRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Drawer', - cnName: '抽屉板', - }, - }, - { - path: 'dropdown', - component: ExamplePanelComponent, - children: dropdownRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'DropDown', - cnName: '下拉菜单', - }, - }, - { - path: 'editable-select', - component: ExamplePanelComponent, - children: editableSelectRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'EditableSelect', - cnName: '可输入下拉选择框', - }, - }, - { - path: 'loading', - component: ExamplePanelComponent, - children: loadingRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Loading', - cnName: '加载提示', - }, - }, - { - path: 'modal', - component: ExamplePanelComponent, - children: modalRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Modal', - cnName: '模态弹窗', - }, - }, - { - path: 'pagination', - component: ExamplePanelComponent, - children: paginationRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'Pagination', - cnName: '分页', - }, - }, - { - path: 'panel', - component: ExamplePanelComponent, - children: panelRoutes, - meta: { - name: 'Panel', - cnName: '面板', - }, - }, - { - path: 'popover', - component: ExamplePanelComponent, - children: popoverRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Popover', - cnName: '悬浮提示', - }, - }, - { - path: 'progress', - component: ExamplePanelComponent, - children: progressRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Progress', - cnName: '进度条', - }, - }, - { - path: 'quadrant-diagram', - component: ExamplePanelComponent, - children: quadrantDiagramRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Quadrant Diagram', - cnName: '象限图', - }, - }, - { - path: 'radio', - component: ExamplePanelComponent, - children: radioRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Radio', - cnName: '单选框', - }, - }, - { - path: 'rate', - component: ExamplePanelComponent, - children: rateRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Rate', - cnName: '等级评估', - }, - }, - { - path: 'search', - component: ExamplePanelComponent, - children: searchRoutes, - meta: { - name: 'Search', - cnName: '搜索框', - }, - }, - { - path: 'select', - component: ExamplePanelComponent, - children: selectRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Select', - cnName: '下拉选择框', - }, - }, - { - path: 'cascader', - component: ExamplePanelComponent, - children: cascaderRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Cascader', - cnName: '级联菜单', - }, - }, - { - path: 'status', - component: ExamplePanelComponent, - children: statusRoutes, - meta: { - name: 'Status', - cnName: '状态', - }, - }, - { - path: 'sticky', - component: ExamplePanelComponent, - children: stickyRoutes, - meta: { - name: 'Sticky', - cnName: '便贴', - }, - }, - { - path: 'tabs', - component: ExamplePanelComponent, - children: tabsRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'Tabs', - cnName: '选项卡切换', - }, - }, - { - path: 'tags', - component: ExamplePanelComponent, - children: tagsRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Tags', - cnName: '标签', - }, - }, - { - path: 'tags-input', - component: ExamplePanelComponent, - children: tagsInputRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'TagsInput', - cnName: '标签输入', - }, - }, - { - path: 'time-axis', - component: ExamplePanelComponent, - children: timeAxisRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'TimeAxis', - cnName: '时间轴', - }, - }, - { - path: 'toast', - component: ExamplePanelComponent, - children: toastRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Toast', - cnName: '全局通知', - }, - }, - { - path: 'tooltip', - component: ExamplePanelComponent, - children: tooltipRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'Tooltip', - cnName: '提示', - }, - }, - { - path: 'read-tip', - component: ExamplePanelComponent, - children: readTipRoutes, - meta: { - type: '反馈', - enType: 'Feedback', - name: 'ReadTip', - cnName: '阅读提示', - description: '阅读提示组件。', - tmw: `当html文档中需要对特定内容进行提示时使用。`, - }, - }, - { - path: 'toggle', - component: ExamplePanelComponent, - children: toggleRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Toggle', - cnName: '开关', - }, - }, - { - path: 'tree', - component: ExamplePanelComponent, - children: treeRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Tree', - cnName: '树', - }, - }, - { - path: 'upload', - component: ExamplePanelComponent, - children: uploadRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Upload', - cnName: '上传', - }, - }, - { - path: 'input-number', - component: ExamplePanelComponent, - children: inputNumberRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'InputNumber', - cnName: '数字输入框', - }, - }, - { - path: 'tree-select', - component: ExamplePanelComponent, - children: treeSelectRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'TreeSelect', - cnName: '树形选择框', - }, - }, - { - path: 'slider', - component: ExamplePanelComponent, - children: sliderRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Slider', - cnName: '滑动输入条', - }, - }, - { - path: 'splitter', - component: ExamplePanelComponent, - children: splitterRoutes, - meta: { - type: '布局', - enType: 'Layout', - name: 'Splitter', - cnName: '分割器', - }, - }, - { - path: 'layout', - component: ExamplePanelComponent, - children: layoutRoutes, - meta: { - type: '布局', - enType: 'Layout', - name: 'Layout', - cnName: '布局', - }, - }, - { - path: 'gantt', - component: ExamplePanelComponent, - children: ganttRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'Gantt', - cnName: '甘特图', - }, - }, - { - path: 'text-input', - component: ExamplePanelComponent, - children: textInputRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'TextInput', - cnName: '文本框', - }, - }, - { - path: 'textarea', - component: ExamplePanelComponent, - children: textareaRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'Textarea', - cnName: '多行文本框', - }, - }, - { - path: 'steps-guide', - component: ExamplePanelComponent, - children: stepsGuideRoutes, - meta: { - type: '导航', - enType: 'Navigation', - name: 'StepsGuide', - cnName: '操作指引', - }, - }, - { - path: 'time-picker', - component: ExamplePanelComponent, - children: timePickerRoutes, - meta: { - type: '数据录入', - enType: 'Data Entry', - name: 'TimePicker', - cnName: '时间选择器', - }, - }, - { - path: 'relative-time', - component: ExamplePanelComponent, - children: accordionRoutes, - meta: { - type: '数据展示', - enType: 'Data Display', - name: 'RelativeTime', - cnName: '人性化时间转换', - }, - }, -]; - -export default routesConfig; diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index b59e0a2b93ff4deb9a783f684338ac1e7ae05b6c..0000000000000000000000000000000000000000 --- a/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createApp } from 'vue' -// TypeScript error? Run VSCode command -// TypeScript: Select TypeScript version - > Use Workspace Version -import App from './app.vue' -import appRoutes from './app.route' - -const app = createApp(App) - -app.use(appRoutes) - -app.mount('#app') diff --git a/yarn.lock b/yarn.lock index e5bcfc2a6ccc7a195b912c27cdd697e072c4511b..713eb7e3560a057905dd6e2e1f341a9efeee19de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,32 +2,148 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.12.13.tgz?cache=0&sync_timestamp=1612315810167&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha1-3PyCa+72XnXFDiHTg319lXmN1lg= - dependencies: - "@babel/highlight" "^7.12.13" +"@algolia/cache-browser-local-storage@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.11.0.tgz#1c168add00b398a860db6c86039e33b2843a9425" + integrity sha512-4sr9vHIG1fVA9dONagdzhsI/6M5mjs/qOe2xUP0yBmwsTsuwiZq3+Xu6D3dsxsuFetcJgC6ydQoCW8b7fDJHYQ== + dependencies: + "@algolia/cache-common" "4.11.0" + +"@algolia/cache-common@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.11.0.tgz#066fe6d58b18e4b028dbef9bb8de07c5e22a3594" + integrity sha512-lODcJRuPXqf+6mp0h6bOxPMlbNoyn3VfjBVcQh70EDP0/xExZbkpecgHyyZK4kWg+evu+mmgvTK3GVHnet/xKw== + +"@algolia/cache-in-memory@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.11.0.tgz#763c8cb655e6fd2261588e04214fca0959ac07c1" + integrity sha512-aBz+stMSTBOBaBEQ43zJXz2DnwS7fL6dR0e2myehAgtfAWlWwLDHruc/98VOy1ZAcBk1blE2LCU02bT5HekGxQ== + dependencies: + "@algolia/cache-common" "4.11.0" + +"@algolia/client-account@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.11.0.tgz#67fadd3b0802b013ebaaa4b47bb7babae892374e" + integrity sha512-jwmFBoUSzoMwMqgD3PmzFJV/d19p1RJXB6C1ADz4ju4mU7rkaQLtqyZroQpheLoU5s5Tilmn/T8/0U2XLoJCRQ== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-analytics@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.11.0.tgz#cbdc8128205e2da749cafc79e54708d14c413974" + integrity sha512-v5U9585aeEdYml7JqggHAj3E5CQ+jPwGVztPVhakBk8H/cmLyPS2g8wvmIbaEZCHmWn4TqFj3EBHVYxAl36fSA== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-common@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.11.0.tgz#9a2d1f6f8eaad25ba5d6d4ce307ba5bd84e6f999" + integrity sha512-Qy+F+TZq12kc7tgfC+FM3RvYH/Ati7sUiUv/LkvlxFwNwNPwWGoZO81AzVSareXT/ksDDrabD4mHbdTbBPTRmQ== + dependencies: + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-personalization@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.11.0.tgz#d3bf0e760f85df876b4baf5b81996f0aa3a59940" + integrity sha512-mI+X5IKiijHAzf9fy8VSl/GTT67dzFDnJ0QAM8D9cMPevnfX4U72HRln3Mjd0xEaYUOGve8TK/fMg7d3Z5yG6g== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-search@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.11.0.tgz#c1105d715a2a04ba27231eca86f5d6620f68f4ae" + integrity sha512-iovPLc5YgiXBdw2qMhU65sINgo9umWbHFzInxoNErWnYoTQWfXsW6P54/NlKx5uscoLVjSf+5RUWwFu5BX+lpw== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/logger-common@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.11.0.tgz#bac1c2d59d29dee378b57412c8edd435b97de663" + integrity sha512-pRMJFeOY8hoWKIxWuGHIrqnEKN/kqKh7UilDffG/+PeEGxBuku+Wq5CfdTFG0C9ewUvn8mAJn5BhYA5k8y0Jqg== + +"@algolia/logger-console@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.11.0.tgz#ced19e3abb22eb782ed5268d51efb5aa9ef109ef" + integrity sha512-wXztMk0a3VbNmYP8Kpc+F7ekuvaqZmozM2eTLok0XIshpAeZ/NJDHDffXK2Pw+NF0wmHqurptLYwKoikjBYvhQ== + dependencies: + "@algolia/logger-common" "4.11.0" + +"@algolia/requester-browser-xhr@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.11.0.tgz#f9e1ad56f185432aa8dde8cad53ae271fd5d6181" + integrity sha512-Fp3SfDihAAFR8bllg8P5ouWi3+qpEVN5e7hrtVIYldKBOuI/qFv80Zv/3/AMKNJQRYglS4zWyPuqrXm58nz6KA== + dependencies: + "@algolia/requester-common" "4.11.0" + +"@algolia/requester-common@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.11.0.tgz#d16de98d3ff72434bac39e4d915eab08035946a9" + integrity sha512-+cZGe/9fuYgGuxjaBC+xTGBkK7OIYdfapxhfvEf03dviLMPmhmVYFJtJlzAjQ2YmGDJpHrGgAYj3i/fbs8yhiA== + +"@algolia/requester-node-http@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.11.0.tgz#beb2b6b68d5f4ce15aec80ede623f0ac96991368" + integrity sha512-qJIk9SHRFkKDi6dMT9hba8X1J1z92T5AZIgl+tsApjTGIRQXJLTIm+0q4yOefokfu4CoxYwRZ9QAq+ouGwfeOg== + dependencies: + "@algolia/requester-common" "4.11.0" + +"@algolia/transporter@4.11.0": + version "4.11.0" + resolved "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.11.0.tgz#a8de3c173093ceceb02b26b577395ce3b3d4b96f" + integrity sha512-k4dyxiaEfYpw4UqybK9q7lrFzehygo6KV3OCYJMMdX0IMWV0m4DXdU27c1zYRYtthaFYaBzGF4Kjcl8p8vxCKw== + dependencies: + "@algolia/cache-common" "4.11.0" + "@algolia/logger-common" "4.11.0" + "@algolia/requester-common" "4.11.0" -"@babel/compat-data@^7.13.12": - version "7.13.15" - resolved "https://registry.npm.taobao.org/@babel/compat-data/download/@babel/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" - integrity sha1-fo7qQtC2T9orN1si0GxgUiLoSPQ= +"@arr/every@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz#22fe1f8e6355beca6c7c7bde965eb15cf994387b" + integrity sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg== -"@babel/core@^7.12.10": - version "7.13.15" - resolved "https://registry.npm.taobao.org/@babel/core/download/@babel/core-7.13.15.tgz#a6d40917df027487b54312202a06812c4f7792d0" - integrity sha1-ptQJF98CdIe1QxIgKgaBLE93ktA= - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-compilation-targets" "^7.13.13" - "@babel/helper-module-transforms" "^7.13.14" - "@babel/helpers" "^7.13.10" - "@babel/parser" "^7.13.15" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.14" +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz#ea269d7f78deb3a7826c39a4048eecda541ebdaa" + integrity sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew== + +"@babel/core@>=7.9.0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.15.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -35,204 +151,879 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.12.1", "@babel/generator@^7.13.9": - version "7.13.9" - resolved "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" - integrity sha1-Onqpb577jivkLTjYDizrTGTY3jk= +"@babel/generator@^7.12.1", "@babel/generator@^7.16.0", "@babel/generator@^7.7.2": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.16.0" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-compilation-targets@^7.13.13": - version "7.13.13" - resolved "https://registry.npm.taobao.org/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.13.13.tgz?cache=0&sync_timestamp=1616807461253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-compilation-targets%2Fdownload%2F%40babel%2Fhelper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5" - integrity sha1-KylyoJJkdIU/QeStvGkzj1IGAOU= +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" + integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== dependencies: - "@babel/compat-data" "^7.13.12" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" + "@babel/helper-explode-assignable-expression" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz#01d615762e796c17952c29e3ede9d6de07d235a8" + integrity sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.13.0": - version "7.13.11" - resolved "https://registry.npm.taobao.org/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.13.11.tgz#30d30a005bca2c953f5653fc25091a492177f4f6" - integrity sha1-MNMKAFvKLJU/VlP8JQkaSSF39PY= +"@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + +"@babel/helper-create-regexp-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" + integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.4": + version "0.2.4" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz#8867aed79d3ea6cade40f801efb7ac5c66916b10" + integrity sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" + integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== + dependencies: + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-remap-async-to-generator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.0.tgz#d5aa3b086e13a5fe05238ff40c3a5a0c2dab3ead" + integrity sha512-MLM1IOMe9aQBqMWxcRw8dcb9jlM86NIw7KA0Wri91Xkfied+dE0QuBFSBjMNvqzmS0OSIDsMNC24dBEkPUi7ew== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helper-wrap-function@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" + integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helpers@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.0.tgz#875519c979c232f41adfbd43a3b0398c2e388183" + integrity sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ== + dependencies: + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@7.12.3": + version "7.12.3" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" + integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw== + +"@babel/parser@^7.1.0", "@babel/parser@^7.12.1", "@babel/parser@^7.12.3", "@babel/parser@^7.14.7", "@babel/parser@^7.15.0", "@babel/parser@^7.15.5", "@babel/parser@^7.16.0", "@babel/parser@^7.6.0", "@babel/parser@^7.7.2", "@babel/parser@^7.9.6": + version "7.16.2" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz#3723cd5c8d8773eef96ce57ea1d9b7faaccd12ac" + integrity sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.0": + version "7.16.2" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz#2977fca9b212db153c195674e57cfab807733183" + integrity sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" + integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + +"@babel/plugin-proposal-async-generator-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.0.tgz#11425d47a60364352f668ad5fbc1d6596b2c5caf" + integrity sha512-nyYmIo7ZqKsY6P4lnVmBlxp9B3a96CscbLotlsNuktMHahkDwoPYEjXrZHU0Tj844Z9f1IthVxQln57mhkcExw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" + integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" + integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" + integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" + integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" + integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" + integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" + integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" + integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" + integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" + integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" + integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" + integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" + integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.0", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" + integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-member-expression-to-functions" "^7.13.0" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-replace-supers" "^7.13.0" - "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.12.13": +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.12.13.tgz?cache=0&sync_timestamp=1612316135661&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a" - integrity sha1-k61lbbPDwiMlWf17LD29y+DrN3o= + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha1-vGNFHUA6OzCCuX4diz/lvUCR5YM= +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== dependencies: - "@babel/types" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.13.12.tgz?cache=0&sync_timestamp=1616428522303&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-member-expression-to-functions%2Fdownload%2F%40babel%2Fhelper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha1-3+No8m1CagcpnY1lE4IXaCFubXI= +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: - "@babel/types" "^7.13.12" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.13.12.tgz?cache=0&sync_timestamp=1616428522999&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha1-xqNppvNiHLJdoBQHhoTakZa2GXc= +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== dependencies: - "@babel/types" "^7.13.12" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/helper-module-transforms@^7.13.14": - version "7.13.14" - resolved "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.13.14.tgz?cache=0&sync_timestamp=1617027606597&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef" - integrity sha1-5gBlK6SMyxZBd1QTyzLPpOi0le8= +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.12.11" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.13" - "@babel/types" "^7.13.14" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha1-XALRcbTIYVsecWP4iMHIHDCiquo= +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: - "@babel/types" "^7.12.13" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0": - version "7.13.0" - resolved "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" - integrity sha1-gGUmzhJa7QM3O8QWqCgyHjpqM68= +"@babel/plugin-syntax-jsx@^7.0.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1" + integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12": - version "7.13.12" - resolved "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.13.12.tgz?cache=0&sync_timestamp=1616428524187&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-replace-supers%2Fdownload%2F%40babel%2Fhelper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804" - integrity sha1-ZEL0wa2RJQJIGlZKc4beDHf/OAQ= +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.12" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.13.12.tgz?cache=0&sync_timestamp=1616428523367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha1-3WxTivthgZ0gWgEsMXkqOcel6vY= +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: - "@babel/types" "^7.13.12" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.12.13.tgz?cache=0&sync_timestamp=1612316065439&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha1-6UML4AuvPoiw4T5vnU6vITY3KwU= +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: - "@babel/types" "^7.12.13" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.12.11.tgz?cache=0&sync_timestamp=1608076959746&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha1-yaHwIZF9y1zPDU5FPjmQIpgfye0= +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.npm.taobao.org/@babel/helper-validator-option/download/@babel/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha1-0fvwEuGnm37rv9xtJwuq+NnrmDE= +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helpers@^7.13.10": - version "7.13.10" - resolved "https://registry.npm.taobao.org/@babel/helpers/download/@babel/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8" - integrity sha1-/Y4rp0iFM83qxFzBWOnryl48ffg= +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/highlight@^7.12.13": - version "7.13.10" - resolved "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" - integrity sha1-qLKmYUj1sn1maxXYF3Q0enMdUtE= +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - chalk "^2.0.0" - js-tokens "^4.0.0" + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/parser@7.12.3": - version "7.12.3" - resolved "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" - integrity sha1-owVBXr56bHAjtAtRIqBmLZKDNM0= +"@babel/plugin-syntax-typescript@^7.16.0", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb" + integrity sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/parser@^7.12.0", "@babel/parser@^7.12.1", "@babel/parser@^7.12.13", "@babel/parser@^7.12.3", "@babel/parser@^7.13.15", "@babel/parser@^7.13.9": - version "7.13.15" - resolved "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8" - integrity sha1-jmZ3X7UjWZrLaiieEpKfpasJVNg= +"@babel/plugin-transform-arrow-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" + integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-import-meta@^7.10.4": - version "7.10.4" - resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-import-meta/download/@babel/plugin-syntax-import-meta-7.10.4.tgz?cache=0&sync_timestamp=1593525045347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-import-meta%2Fdownload%2F%40babel%2Fplugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha1-7mATSMNw+jNNIge+FYd3SWUh/VE= +"@babel/plugin-transform-async-to-generator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" + integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" -"@babel/plugin-syntax-jsx@^7.0.0": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.12.13.tgz?cache=0&sync_timestamp=1612315688632&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-jsx%2Fdownload%2F%40babel%2Fplugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15" - integrity sha1-BE+4HrrWaY/mLEeIdVdby7m3DxU= +"@babel/plugin-transform-block-scoped-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" + integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.12.13": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/plugin-syntax-typescript/download/@babel/plugin-syntax-typescript-7.12.13.tgz#9dff111ca64154cef0f4dc52cf843d9f12ce4474" - integrity sha1-nf8RHKZBVM7w9NxSz4Q9nxLORHQ= +"@babel/plugin-transform-block-scoping@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" + integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typescript@^7.12.1": - version "7.13.0" - resolved "https://registry.npm.taobao.org/@babel/plugin-transform-typescript/download/@babel/plugin-transform-typescript-7.13.0.tgz#4a498e1f3600342d2a9e61f60131018f55774853" - integrity sha1-SkmOHzYANC0qnmH2ATEBj1V3SFM= +"@babel/plugin-transform-classes@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" + integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-typescript" "^7.12.13" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" + integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" + integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.16.0", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" + integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-duplicate-keys@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" + integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" + integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-for-of@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" + integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" + integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" + integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" + integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" + integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" + integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.16.0" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" + integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== + dependencies: + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" + integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" + integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + +"@babel/plugin-transform-new-target@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" + integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" + integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + +"@babel/plugin-transform-parameters@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.0.tgz#1b50765fc421c229819dc4c7cdb8911660b3c2d7" + integrity sha512-XgnQEm1CevKROPx+udOi/8f8TiGhrUWiHiaUCIp47tE0tpFDjzXNTZc9E5CmCwxNjXTWEVqvRfWZYOTFvMa/ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" + integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" + integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" + integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-shorthand-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" + integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" + integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" + integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" + integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" + integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typescript@^7.15.4", "@babel/plugin-transform-typescript@^7.16.0": + version "7.16.1" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409" + integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.16.0" + +"@babel/plugin-transform-unicode-escapes@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" + integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" + integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@^7.14.5": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.0.tgz#97228393d217560d6a1c6c56f0adb9d12bca67f5" + integrity sha512-cdTu/W0IrviamtnZiTfixPfIncr2M1VqRrkjzZWlr1B4TVYimCFK5jkyOdP4qw2MrlKHi+b3ORj6x8GoCew8Dg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.0" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-async-generator-functions" "^7.16.0" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-class-static-block" "^7.16.0" + "@babel/plugin-proposal-dynamic-import" "^7.16.0" + "@babel/plugin-proposal-export-namespace-from" "^7.16.0" + "@babel/plugin-proposal-json-strings" "^7.16.0" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" + "@babel/plugin-proposal-numeric-separator" "^7.16.0" + "@babel/plugin-proposal-object-rest-spread" "^7.16.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-private-methods" "^7.16.0" + "@babel/plugin-proposal-private-property-in-object" "^7.16.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.0" + "@babel/plugin-transform-async-to-generator" "^7.16.0" + "@babel/plugin-transform-block-scoped-functions" "^7.16.0" + "@babel/plugin-transform-block-scoping" "^7.16.0" + "@babel/plugin-transform-classes" "^7.16.0" + "@babel/plugin-transform-computed-properties" "^7.16.0" + "@babel/plugin-transform-destructuring" "^7.16.0" + "@babel/plugin-transform-dotall-regex" "^7.16.0" + "@babel/plugin-transform-duplicate-keys" "^7.16.0" + "@babel/plugin-transform-exponentiation-operator" "^7.16.0" + "@babel/plugin-transform-for-of" "^7.16.0" + "@babel/plugin-transform-function-name" "^7.16.0" + "@babel/plugin-transform-literals" "^7.16.0" + "@babel/plugin-transform-member-expression-literals" "^7.16.0" + "@babel/plugin-transform-modules-amd" "^7.16.0" + "@babel/plugin-transform-modules-commonjs" "^7.16.0" + "@babel/plugin-transform-modules-systemjs" "^7.16.0" + "@babel/plugin-transform-modules-umd" "^7.16.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.0" + "@babel/plugin-transform-new-target" "^7.16.0" + "@babel/plugin-transform-object-super" "^7.16.0" + "@babel/plugin-transform-parameters" "^7.16.0" + "@babel/plugin-transform-property-literals" "^7.16.0" + "@babel/plugin-transform-regenerator" "^7.16.0" + "@babel/plugin-transform-reserved-words" "^7.16.0" + "@babel/plugin-transform-shorthand-properties" "^7.16.0" + "@babel/plugin-transform-spread" "^7.16.0" + "@babel/plugin-transform-sticky-regex" "^7.16.0" + "@babel/plugin-transform-template-literals" "^7.16.0" + "@babel/plugin-transform-typeof-symbol" "^7.16.0" + "@babel/plugin-transform-unicode-escapes" "^7.16.0" + "@babel/plugin-transform-unicode-regex" "^7.16.0" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.0" + babel-plugin-polyfill-corejs2 "^0.2.3" + babel-plugin-polyfill-corejs3 "^0.3.0" + babel-plugin-polyfill-regenerator "^0.2.3" + core-js-compat "^3.19.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-typescript@^7.14.5": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac" + integrity sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.16.0" -"@babel/runtime@^7.11.2": - version "7.13.10" - resolved "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.13.10.tgz?cache=0&sync_timestamp=1615252192581&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d" - integrity sha1-R9QqV7YJX0Ro2kQDiP262L6/DX0= +"@babel/runtime@^7.11.2", "@babel/runtime@^7.8.4": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz#e27b977f2e2088ba24748bf99b5e1dece64e4f0b" + integrity sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.0.0", "@babel/template@^7.12.13", "@babel/template@^7.12.7": - version "7.12.13" - resolved "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.12.13.tgz?cache=0&sync_timestamp=1612315692774&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftemplate%2Fdownload%2F%40babel%2Ftemplate-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha1-UwJlvooliduzdSOETFvLVZR/syc= +"@babel/template@^7.0.0", "@babel/template@^7.12.7", "@babel/template@^7.16.0", "@babel/template@^7.3.3": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" "@babel/traverse@7.12.1": version "7.12.1" - resolved "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.12.1.tgz?cache=0&sync_timestamp=1617898592673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" - integrity sha1-lBOV4MXMhtXT51yqCV05JFJvDB4= + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" + integrity sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw== dependencies: "@babel/code-frame" "^7.10.4" "@babel/generator" "^7.12.1" @@ -244,42 +1035,47 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15": - version "7.13.15" - resolved "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.13.15.tgz?cache=0&sync_timestamp=1617898592673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7" - integrity sha1-w4v3Z5M03dQCjo4fezqlAZ8Nrac= - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.15" - "@babel/types" "^7.13.14" +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.16.0", "@babel/traverse@^7.7.2": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz#965df6c6bfc0a958c1e739284d3c9fa4a6e3c45b" + integrity sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" debug "^4.1.0" globals "^11.1.0" "@babel/types@7.12.1": version "7.12.1" - resolved "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.12.1.tgz?cache=0&sync_timestamp=1617027606356&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae" - integrity sha1-4QnZq5mo3nNb4ofuPWqZR6GQxK4= + resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae" + integrity sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14": - version "7.13.14" - resolved "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.13.14.tgz?cache=0&sync_timestamp=1617027606356&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" - integrity sha1-w1pKuxXHzUWidG14qzKONiy6zg0= +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.16.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.9.6": + version "7.16.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@commitlint/cli@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/cli/download/@commitlint/cli-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fcli%2Fdownload%2F%40commitlint%2Fcli-11.0.0.tgz#698199bc52afed50aa28169237758fa14a67b5d3" - integrity sha1-aYGZvFKv7VCqKBaSN3WPoUpntdM= + resolved "https://registry.npmjs.org/@commitlint/cli/-/cli-11.0.0.tgz#698199bc52afed50aa28169237758fa14a67b5d3" + integrity sha512-YWZWg1DuqqO5Zjh7vUOeSX76vm0FFyz4y0cpGMFhrhvUi5unc4IVfCXZ6337R9zxuBtmveiRuuhQqnRRer+13g== dependencies: "@babel/runtime" "^7.11.2" "@commitlint/format" "^11.0.0" @@ -296,44 +1092,44 @@ "@commitlint/config-conventional@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/config-conventional/download/@commitlint/config-conventional-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fconfig-conventional%2Fdownload%2F%40commitlint%2Fconfig-conventional-11.0.0.tgz#3fa300a1b639273946de3c3f15e1cda518333422" - integrity sha1-P6MAobY5JzlG3jw/FeHNpRgzNCI= + resolved "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-11.0.0.tgz#3fa300a1b639273946de3c3f15e1cda518333422" + integrity sha512-SNDRsb5gLuDd2PL83yCOQX6pE7gevC79UPFx+GLbLfw6jGnnbO9/tlL76MLD8MOViqGbo7ZicjChO9Gn+7tHhA== dependencies: conventional-changelog-conventionalcommits "^4.3.1" "@commitlint/ensure@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/ensure/download/@commitlint/ensure-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fensure%2Fdownload%2F%40commitlint%2Fensure-11.0.0.tgz#3e796b968ab5b72bc6f8a6040076406306c987fb" - integrity sha1-Pnlrloq1tyvG+KYEAHZAYwbJh/s= + resolved "https://registry.npmjs.org/@commitlint/ensure/-/ensure-11.0.0.tgz#3e796b968ab5b72bc6f8a6040076406306c987fb" + integrity sha512-/T4tjseSwlirKZdnx4AuICMNNlFvRyPQimbZIOYujp9DSO6XRtOy9NrmvWujwHsq9F5Wb80QWi4WMW6HMaENug== dependencies: "@commitlint/types" "^11.0.0" lodash "^4.17.19" "@commitlint/execute-rule@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/execute-rule/download/@commitlint/execute-rule-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fexecute-rule%2Fdownload%2F%40commitlint%2Fexecute-rule-11.0.0.tgz#3ed60ab7a33019e58d90e2d891b75d7df77b4b4d" - integrity sha1-PtYKt6MwGeWNkOLYkbddffd7S00= + resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-11.0.0.tgz#3ed60ab7a33019e58d90e2d891b75d7df77b4b4d" + integrity sha512-g01p1g4BmYlZ2+tdotCavrMunnPFPhTzG1ZiLKTCYrooHRbmvqo42ZZn4QMStUEIcn+jfLb6BRZX3JzIwA1ezQ== "@commitlint/format@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/format/download/@commitlint/format-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fformat%2Fdownload%2F%40commitlint%2Fformat-11.0.0.tgz#ac47b0b9ca46540c0082c721b290794e67bdc51b" - integrity sha1-rEewucpGVAwAgschspB5Tme9xRs= + resolved "https://registry.npmjs.org/@commitlint/format/-/format-11.0.0.tgz#ac47b0b9ca46540c0082c721b290794e67bdc51b" + integrity sha512-bpBLWmG0wfZH/svzqD1hsGTpm79TKJWcf6EXZllh2J/LSSYKxGlv967lpw0hNojme0sZd4a/97R3qA2QHWWSLg== dependencies: "@commitlint/types" "^11.0.0" chalk "^4.0.0" "@commitlint/is-ignored@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/is-ignored/download/@commitlint/is-ignored-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fis-ignored%2Fdownload%2F%40commitlint%2Fis-ignored-11.0.0.tgz#7b803eda56276dbe7fec51eb1510676198468f39" - integrity sha1-e4A+2lYnbb5/7FHrFRBnYZhGjzk= + resolved "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-11.0.0.tgz#7b803eda56276dbe7fec51eb1510676198468f39" + integrity sha512-VLHOUBN+sOlkYC4tGuzE41yNPO2w09sQnOpfS+pSPnBFkNUUHawEuA44PLHtDvQgVuYrMAmSWFQpWabMoP5/Xg== dependencies: "@commitlint/types" "^11.0.0" semver "7.3.2" "@commitlint/lint@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/lint/download/@commitlint/lint-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Flint%2Fdownload%2F%40commitlint%2Flint-11.0.0.tgz#01e062cd1b0e7c3d756aa2c246462e0b6a3348a4" - integrity sha1-AeBizRsOfD11aqLCRkYuC2ozSKQ= + resolved "https://registry.npmjs.org/@commitlint/lint/-/lint-11.0.0.tgz#01e062cd1b0e7c3d756aa2c246462e0b6a3348a4" + integrity sha512-Q8IIqGIHfwKr8ecVZyYh6NtXFmKw4YSEWEr2GJTB/fTZXgaOGtGFZDWOesCZllQ63f1s/oWJYtVv5RAEuwN8BQ== dependencies: "@commitlint/is-ignored" "^11.0.0" "@commitlint/parse" "^11.0.0" @@ -342,8 +1138,8 @@ "@commitlint/load@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/load/download/@commitlint/load-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fload%2Fdownload%2F%40commitlint%2Fload-11.0.0.tgz#f736562f0ffa7e773f8808fea93319042ee18211" - integrity sha1-9zZWLw/6fnc/iAj+qTMZBC7hghE= + resolved "https://registry.npmjs.org/@commitlint/load/-/load-11.0.0.tgz#f736562f0ffa7e773f8808fea93319042ee18211" + integrity sha512-t5ZBrtgvgCwPfxmG811FCp39/o3SJ7L+SNsxFL92OR4WQxPcu6c8taD0CG2lzOHGuRyuMxZ7ps3EbngT2WpiCg== dependencies: "@commitlint/execute-rule" "^11.0.0" "@commitlint/resolve-extends" "^11.0.0" @@ -355,21 +1151,21 @@ "@commitlint/message@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/message/download/@commitlint/message-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fmessage%2Fdownload%2F%40commitlint%2Fmessage-11.0.0.tgz#83554c3cbbc884fd07b473593bc3e94bcaa3ee05" - integrity sha1-g1VMPLvIhP0HtHNZO8PpS8qj7gU= + resolved "https://registry.npmjs.org/@commitlint/message/-/message-11.0.0.tgz#83554c3cbbc884fd07b473593bc3e94bcaa3ee05" + integrity sha512-01ObK/18JL7PEIE3dBRtoMmU6S3ecPYDTQWWhcO+ErA3Ai0KDYqV5VWWEijdcVafNpdeUNrEMigRkxXHQLbyJA== "@commitlint/parse@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/parse/download/@commitlint/parse-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fparse%2Fdownload%2F%40commitlint%2Fparse-11.0.0.tgz#d18b08cf67c35d02115207d7009306a2e8e7c901" - integrity sha1-0YsIz2fDXQIRUgfXAJMGoujnyQE= + resolved "https://registry.npmjs.org/@commitlint/parse/-/parse-11.0.0.tgz#d18b08cf67c35d02115207d7009306a2e8e7c901" + integrity sha512-DekKQAIYWAXIcyAZ6/PDBJylWJ1BROTfDIzr9PMVxZRxBPc1gW2TG8fLgjZfBP5mc0cuthPkVi91KQQKGri/7A== dependencies: conventional-changelog-angular "^5.0.0" conventional-commits-parser "^3.0.0" "@commitlint/read@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/read/download/@commitlint/read-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fread%2Fdownload%2F%40commitlint%2Fread-11.0.0.tgz#f24240548c63587bba139fa5a364cab926077016" - integrity sha1-8kJAVIxjWHu6E5+lo2TKuSYHcBY= + resolved "https://registry.npmjs.org/@commitlint/read/-/read-11.0.0.tgz#f24240548c63587bba139fa5a364cab926077016" + integrity sha512-37V0V91GSv0aDzMzJioKpCoZw6l0shk7+tRG8RkW1GfZzUIytdg3XqJmM+IaIYpaop0m6BbZtfq+idzUwJnw7g== dependencies: "@commitlint/top-level" "^11.0.0" fs-extra "^9.0.0" @@ -377,8 +1173,8 @@ "@commitlint/resolve-extends@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/resolve-extends/download/@commitlint/resolve-extends-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fresolve-extends%2Fdownload%2F%40commitlint%2Fresolve-extends-11.0.0.tgz#158ecbe27d4a2a51d426111a01478e216fbb1036" - integrity sha1-FY7L4n1KKlHUJhEaAUeOIW+7EDY= + resolved "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-11.0.0.tgz#158ecbe27d4a2a51d426111a01478e216fbb1036" + integrity sha512-WinU6Uv6L7HDGLqn/To13KM1CWvZ09VHZqryqxXa1OY+EvJkfU734CwnOEeNlSCK7FVLrB4kmodLJtL1dkEpXw== dependencies: import-fresh "^3.0.0" lodash "^4.17.19" @@ -387,8 +1183,8 @@ "@commitlint/rules@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/rules/download/@commitlint/rules-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Frules%2Fdownload%2F%40commitlint%2Frules-11.0.0.tgz#bdb310cc6fc55c9f8d7d917a22b69055c535c375" - integrity sha1-vbMQzG/FXJ+NfZF6IraQVcU1w3U= + resolved "https://registry.npmjs.org/@commitlint/rules/-/rules-11.0.0.tgz#bdb310cc6fc55c9f8d7d917a22b69055c535c375" + integrity sha512-2hD9y9Ep5ZfoNxDDPkQadd2jJeocrwC4vJ98I0g8pNYn/W8hS9+/FuNpolREHN8PhmexXbkjrwyQrWbuC0DVaA== dependencies: "@commitlint/ensure" "^11.0.0" "@commitlint/message" "^11.0.0" @@ -397,1257 +1193,5916 @@ "@commitlint/to-lines@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/to-lines/download/@commitlint/to-lines-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Fto-lines%2Fdownload%2F%40commitlint%2Fto-lines-11.0.0.tgz#86dea151c10eea41e39ea96fa4de07839258a7fe" - integrity sha1-ht6hUcEO6kHjnqlvpN4Hg5JYp/4= + resolved "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-11.0.0.tgz#86dea151c10eea41e39ea96fa4de07839258a7fe" + integrity sha512-TIDTB0Y23jlCNubDROUVokbJk6860idYB5cZkLWcRS9tlb6YSoeLn1NLafPlrhhkkkZzTYnlKYzCVrBNVes1iw== "@commitlint/top-level@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/top-level/download/@commitlint/top-level-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Ftop-level%2Fdownload%2F%40commitlint%2Ftop-level-11.0.0.tgz#bb2d1b6e5ed3be56874633b59e1f7de118c32783" - integrity sha1-uy0bbl7TvlaHRjO1nh994RjDJ4M= + resolved "https://registry.npmjs.org/@commitlint/top-level/-/top-level-11.0.0.tgz#bb2d1b6e5ed3be56874633b59e1f7de118c32783" + integrity sha512-O0nFU8o+Ws+py5pfMQIuyxOtfR/kwtr5ybqTvR+C2lUPer2x6lnQU+OnfD7hPM+A+COIUZWx10mYQvkR3MmtAA== dependencies: find-up "^5.0.0" "@commitlint/types@^11.0.0": version "11.0.0" - resolved "https://registry.npm.taobao.org/@commitlint/types/download/@commitlint/types-11.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40commitlint%2Ftypes%2Fdownload%2F%40commitlint%2Ftypes-11.0.0.tgz#719cf05fcc1abb6533610a2e0f5dd1e61eac14fe" - integrity sha1-cZzwX8wau2UzYQouD13R5h6sFP4= + resolved "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz#719cf05fcc1abb6533610a2e0f5dd1e61eac14fe" + integrity sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ== + +"@devui-design/icons@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@devui-design/icons/-/icons-1.3.0.tgz#5a3006a31ee4f62e3f9837b68c031898ff148b88" + integrity sha512-eg9PcDXYn1BaUCo6qP7dszFJ4uRycxASLdKzpz27AW34HbHx4kFce36Fhfr2niRjGKYllcMgYe7hgP5KYVOZ8Q== + +"@docsearch/css@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npmjs.org/@docsearch/css/-/css-1.0.0-alpha.28.tgz#c8a2cd8c1bb3a6855c51892e9dbdab5d42fe6e23" + integrity sha512-1AhRzVdAkrWwhaxTX6/R7SnFHz8yLz1W8I/AldlTrfbNvZs9INk1FZiEFTJdgHaP68nhgQNWSGlQiDiI3y2RYg== + +"@docsearch/js@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npmjs.org/@docsearch/js/-/js-1.0.0-alpha.28.tgz#f0fde7b8a6b1e1d8a7ae1e7655c43d959b457b2b" + integrity sha512-2g7aPhBy7FoEyeZW2G3LYHWVa8CFvqyozEz8PXt3hyywdFcmEIqmoCRwn8kboVftrOKCjtPcuLCewsaBoB3uiw== + dependencies: + "@docsearch/react" "^1.0.0-alpha.28" + preact "^10.0.0" + +"@docsearch/react@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npmjs.org/@docsearch/react/-/react-1.0.0-alpha.28.tgz#4f039ed79f8b3332b19a57677b219aebc5010e9d" + integrity sha512-XjJOnCBXn+UZmtuDmgzlVIHnnvh6yHVwG4aFq8AXN6xJEIX3f180FvGaowFWAxgdtHplJxFGux0Xx4piHqBzIw== + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@francoischalifour/autocomplete-core" "^1.0.0-alpha.28" + "@francoischalifour/autocomplete-preset-algolia" "^1.0.0-alpha.28" + algoliasearch "^4.0.0" + +"@emmetio/abbreviation@^2.2.2": + version "2.2.2" + resolved "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.2.2.tgz#746762fd9e7a8c2ea604f580c62e3cfe250e6989" + integrity sha512-TtE/dBnkTCct8+LntkqVrwqQao6EnPAs1YN3cUgxOxTaBlesBCY37ROUAVZrRlG64GNnVShdl/b70RfAI3w5lw== + dependencies: + "@emmetio/scanner" "^1.0.0" + +"@emmetio/css-abbreviation@^2.1.4": + version "2.1.4" + resolved "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.4.tgz#90362e8a1122ce3b76f6c3157907d30182f53f54" + integrity sha512-qk9L60Y+uRtM5CPbB0y+QNl/1XKE09mSO+AhhSauIfr2YOx/ta3NJw2d8RtCFxgzHeRqFRr8jgyzThbu+MZ4Uw== + dependencies: + "@emmetio/scanner" "^1.0.0" + +"@emmetio/scanner@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.0.tgz#065b2af6233fe7474d44823e3deb89724af42b5f" + integrity sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA== + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@francoischalifour/autocomplete-core@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npmjs.org/@francoischalifour/autocomplete-core/-/autocomplete-core-1.0.0-alpha.28.tgz#6b9d8491288e77f831e9b345d461623b0d3f5005" + integrity sha512-rL9x+72btViw+9icfBKUJjZj87FgjFrD2esuTUqtj4RAX3s4AuVZiN8XEsfjQBSc6qJk31cxlvqZHC/BIyYXgg== + +"@francoischalifour/autocomplete-preset-algolia@^1.0.0-alpha.28": + version "1.0.0-alpha.28" + resolved "https://registry.npmjs.org/@francoischalifour/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.28.tgz#a5ad7996f42e43e4acbb4e0010d663746d0e9997" + integrity sha512-bprfNmYt1opFUFEtD2XfY/kEsm13bzHQgU80uMjhuK0DJ914IjolT1GytpkdM6tJ4MBvyiJPP+bTtWO+BZ7c7w== + +"@gar/promisify@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" + integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@intlify/core-base@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/core-base/download/@intlify/core-base-9.1.4.tgz#e5f7fb632b7063c65c8485845c879ad5903a4a0f" - integrity sha1-5ff7YytwY8ZchIWEXIea1ZA6Sg8= +"@hutson/parse-repository-url@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" + integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== + +"@intlify/core-base@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz#e4e8c951010728e4af3a0d13d74cf3f9e7add7f6" + integrity sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw== dependencies: - "@intlify/devtools-if" "9.1.4" - "@intlify/message-compiler" "9.1.4" - "@intlify/message-resolver" "9.1.4" - "@intlify/runtime" "9.1.4" - "@intlify/shared" "9.1.4" - "@intlify/vue-devtools" "9.1.4" + "@intlify/devtools-if" "9.1.9" + "@intlify/message-compiler" "9.1.9" + "@intlify/message-resolver" "9.1.9" + "@intlify/runtime" "9.1.9" + "@intlify/shared" "9.1.9" + "@intlify/vue-devtools" "9.1.9" "@intlify/core@^9.0.0-beta.15": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/core/download/@intlify/core-9.1.4.tgz#fe8ec53e30d4a43de09d7573bebfbae6b8c13ba3" - integrity sha1-/o7FPjDUpD3gnXVzvr+65rjBO6M= + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/core/-/core-9.1.9.tgz#774e739a2ab4ac460a348a35eb0260e787d50556" + integrity sha512-y+B2KaLGYYrbcq4kXhTn9JBphlAyC351l47TMfK9xBEXTXRzgEpXTzTJ23Y85GBwOCembRehQ82sjjtGmJuRjA== dependencies: - "@intlify/core-base" "9.1.4" + "@intlify/core-base" "9.1.9" -"@intlify/devtools-if@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/devtools-if/download/@intlify/devtools-if-9.1.4.tgz#ba79e9dec3b1347842c93008c6bf6dab80f6c170" - integrity sha1-unnp3sOxNHhCyTAIxr9tq4D2wXA= +"@intlify/devtools-if@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz#a30e1dd1256ff2c5c98d8d75d075384fba898e5d" + integrity sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ== dependencies: - "@intlify/shared" "9.1.4" + "@intlify/shared" "9.1.9" -"@intlify/message-compiler@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/message-compiler/download/@intlify/message-compiler-9.1.4.tgz#dbf09979c8ce8b656a3ec6fb80ece15d298ff461" - integrity sha1-2/CZecjOi2VqPsb7gOzhXSmP9GE= +"@intlify/message-compiler@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz#1193cbd224a71c2fb981455b8534a3c766d2948d" + integrity sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ== dependencies: - "@intlify/message-resolver" "9.1.4" - "@intlify/shared" "9.1.4" + "@intlify/message-resolver" "9.1.9" + "@intlify/shared" "9.1.9" source-map "0.6.1" -"@intlify/message-resolver@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/message-resolver/download/@intlify/message-resolver-9.1.4.tgz#6e2ca85435e8d9fe18b8c8fcde66d8aff50676e1" - integrity sha1-biyoVDXo2f4YuMj83mbYr/UGduE= +"@intlify/message-resolver@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz#3155ccd2f5e6d0dc16cad8b7f1d8e97fcda05bfc" + integrity sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA== -"@intlify/runtime@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/runtime/download/@intlify/runtime-9.1.4.tgz#e4a9e9bebd3ba82603f465648c4668855617ebc2" - integrity sha1-5Knpvr07qCYD9GVkjEZohVYX68I= +"@intlify/runtime@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz#2c12ce29518a075629efed0a8ed293ee740cb285" + integrity sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg== dependencies: - "@intlify/message-compiler" "9.1.4" - "@intlify/message-resolver" "9.1.4" - "@intlify/shared" "9.1.4" + "@intlify/message-compiler" "9.1.9" + "@intlify/message-resolver" "9.1.9" + "@intlify/shared" "9.1.9" -"@intlify/shared@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/shared/download/@intlify/shared-9.1.4.tgz#0388515e5458fe1a2314c8f844db31bad26b8558" - integrity sha1-A4hRXlRY/hojFMj4RNsxutJrhVg= +"@intlify/shared@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz#0baaf96128b85560666bec784ffb01f6623cc17a" + integrity sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw== -"@intlify/vue-devtools@9.1.4": - version "9.1.4" - resolved "https://registry.npm.taobao.org/@intlify/vue-devtools/download/@intlify/vue-devtools-9.1.4.tgz#1dc42b86da9d273803ba85a295caf4e7c32cdfa2" - integrity sha1-HcQrhtqdJzgDuoWilcr058Ms36I= +"@intlify/vue-devtools@9.1.9": + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz#2be8f4dbe7f7ed4115676eb32348141d411e426b" + integrity sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og== dependencies: - "@intlify/message-resolver" "9.1.4" - "@intlify/runtime" "9.1.4" - "@intlify/shared" "9.1.4" + "@intlify/message-resolver" "9.1.9" + "@intlify/runtime" "9.1.9" + "@intlify/shared" "9.1.9" -"@nodelib/fs.scandir@2.1.4": - version "2.1.4" - resolved "https://registry.npm.taobao.org/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40nodelib%2Ffs.scandir%2Fdownload%2F%40nodelib%2Ffs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" - integrity sha1-1LNUml213iaD4MEHGrTxQJBLv2k= +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: - "@nodelib/fs.stat" "2.0.4" - run-parallel "^1.1.9" + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": - version "2.0.4" - resolved "https://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" - integrity sha1-o/LdYbq0O424+hCKEhz//kxnZlU= +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@nodelib/fs.walk@^1.2.3": - version "1.2.6" - resolved "https://registry.npm.taobao.org/@nodelib/fs.walk/download/@nodelib/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" - integrity sha1-zOk5azCqWv6eN1Zgj1gxrctT0GM= +"@jest/console@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz#e8ea3a475d3f8162f23d69efbfaa9cbe486bee93" + integrity sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw== dependencies: - "@nodelib/fs.scandir" "2.1.4" - fastq "^1.6.0" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.3.1" + jest-util "^27.3.1" + slash "^3.0.0" -"@types/braces@*": - version "3.0.0" - resolved "https://registry.npm.taobao.org/@types/braces/download/@types/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb" - integrity sha1-faHA1E/xx+tmCjbsB46mG6frQss= +"@jest/core@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz#04992ef1b58b17c459afb87ab56d81e63d386925" + integrity sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg== + dependencies: + "@jest/console" "^27.3.1" + "@jest/reporters" "^27.3.1" + "@jest/test-result" "^27.3.1" + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.3.0" + jest-config "^27.3.1" + jest-haste-map "^27.3.1" + jest-message-util "^27.3.1" + jest-regex-util "^27.0.6" + jest-resolve "^27.3.1" + jest-resolve-dependencies "^27.3.1" + jest-runner "^27.3.1" + jest-runtime "^27.3.1" + jest-snapshot "^27.3.1" + jest-util "^27.3.1" + jest-validate "^27.3.1" + jest-watcher "^27.3.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz#2182defbce8d385fd51c5e7c7050f510bd4c86b1" + integrity sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw== + dependencies: + "@jest/fake-timers" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.3.0" + +"@jest/fake-timers@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz#1fad860ee9b13034762cdb94266e95609dfce641" + integrity sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA== + dependencies: + "@jest/types" "^27.2.5" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.3.1" + jest-mock "^27.3.0" + jest-util "^27.3.1" + +"@jest/globals@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz#ce1dfb03d379237a9da6c1b99ecfaca1922a5f9e" + integrity sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg== + dependencies: + "@jest/environment" "^27.3.1" + "@jest/types" "^27.2.5" + expect "^27.3.1" + +"@jest/reporters@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz#28b5c1f5789481e23788048fa822ed15486430b9" + integrity sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.3.1" + "@jest/test-result" "^27.3.1" + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^27.3.1" + jest-resolve "^27.3.1" + jest-util "^27.3.1" + jest-worker "^27.3.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" -"@types/lodash-es@^4.17.4": - version "4.17.4" - resolved "https://registry.npm.taobao.org/@types/lodash-es/download/@types/lodash-es-4.17.4.tgz#b2e440d2bf8a93584a9fd798452ec497986c9b97" - integrity sha1-suRA0r+Kk1hKn9eYRS7El5hsm5c= +"@jest/source-map@^27.0.6": + version "27.0.6" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f" + integrity sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g== dependencies: - "@types/lodash" "*" + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz#89adee8b771877c69b3b8d59f52f29dccc300194" + integrity sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg== + dependencies: + "@jest/console" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz#4b3bde2dbb05ee74afdae608cf0768e3354683b1" + integrity sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA== + dependencies: + "@jest/test-result" "^27.3.1" + graceful-fs "^4.2.4" + jest-haste-map "^27.3.1" + jest-runtime "^27.3.1" + +"@jest/transform@^27.3.1": + version "27.3.1" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz#ff80eafbeabe811e9025e4b6f452126718455220" + integrity sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.2.5" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.3.1" + jest-regex-util "^27.0.6" + jest-util "^27.3.1" + micromatch "^4.0.4" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" -"@types/lodash@*": - version "4.14.168" - resolved "https://registry.npm.taobao.org/@types/lodash/download/@types/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008" - integrity sha1-/iRjLnm3rePxMoka//hsql5c4Ag= +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" -"@types/micromatch@^4.0.1": - version "4.0.1" - resolved "https://registry.npm.taobao.org/@types/micromatch/download/@types/micromatch-4.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fmicromatch%2Fdownload%2F%40types%2Fmicromatch-4.0.1.tgz#9381449dd659fc3823fd2a4190ceacc985083bc7" - integrity sha1-k4FEndZZ/Dgj/SpBkM6syYUIO8c= +"@jest/types@^27.2.5": + version "27.2.5" + resolved "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz#420765c052605e75686982d24b061b4cbba22132" + integrity sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ== dependencies: - "@types/braces" "*" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" -"@types/minimist@^1.2.0": - version "1.2.1" - resolved "https://registry.npm.taobao.org/@types/minimist/download/@types/minimist-1.2.1.tgz?cache=0&sync_timestamp=1613379620702&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fminimist%2Fdownload%2F%40types%2Fminimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" - integrity sha1-KD9mn/dte4Jg34q3pCYsyD2YglY= +"@lerna/add@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" + integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== + dependencies: + "@lerna/bootstrap" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/validation-error" "4.0.0" + dedent "^0.7.0" + npm-package-arg "^8.1.0" + p-map "^4.0.0" + pacote "^11.2.6" + semver "^7.3.4" -"@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.npm.taobao.org/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4= +"@lerna/bootstrap@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" + integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/has-npm-version" "4.0.0" + "@lerna/npm-install" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/rimraf-dir" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/symlink-binary" "4.0.0" + "@lerna/symlink-dependencies" "4.0.0" + "@lerna/validation-error" "4.0.0" + dedent "^0.7.0" + get-port "^5.1.1" + multimatch "^5.0.0" + npm-package-arg "^8.1.0" + npmlog "^4.1.2" + p-map "^4.0.0" + p-map-series "^2.1.0" + p-waterfall "^2.1.1" + read-package-tree "^5.3.1" + semver "^7.3.4" -"@types/parse-json@^4.0.0": +"@lerna/changed@4.0.0": version "4.0.0" - resolved "https://registry.npm.taobao.org/@types/parse-json/download/@types/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha1-L4u0QUNNFjs1+4/9zNcTiSf/uMA= + resolved "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" + integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== + dependencies: + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/listable" "4.0.0" + "@lerna/output" "4.0.0" -"@vitejs/plugin-vue-jsx@^1.1.0": - version "1.1.3" - resolved "https://registry.npm.taobao.org/@vitejs/plugin-vue-jsx/download/@vitejs/plugin-vue-jsx-1.1.3.tgz#426c68f8a367a603acb82fca6e2b12506ba9fc8e" - integrity sha1-Qmxo+KNnpgOsuC/KbisSUGup/I4= +"@lerna/check-working-tree@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" + integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-syntax-import-meta" "^7.10.4" - "@babel/plugin-transform-typescript" "^7.12.1" - "@vue/babel-plugin-jsx" "^1.0.3" - hash-sum "^2.0.0" + "@lerna/collect-uncommitted" "4.0.0" + "@lerna/describe-ref" "4.0.0" + "@lerna/validation-error" "4.0.0" -"@vitejs/plugin-vue@^1.0.4": - version "1.2.1" - resolved "https://registry.npm.taobao.org/@vitejs/plugin-vue/download/@vitejs/plugin-vue-1.2.1.tgz?cache=0&sync_timestamp=1617156051071&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vitejs%2Fplugin-vue%2Fdownload%2F%40vitejs%2Fplugin-vue-1.2.1.tgz#6de49436fc346f829a56676066428e3f011522ac" - integrity sha1-beSUNvw0b4KaVmdgZkKOPwEVIqw= +"@lerna/child-process@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" + integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== + dependencies: + chalk "^4.1.0" + execa "^5.0.0" + strong-log-transformer "^2.1.0" -"@vue/babel-helper-vue-transform-on@^1.0.2": - version "1.0.2" - resolved "https://registry.npm.taobao.org/@vue/babel-helper-vue-transform-on/download/@vue/babel-helper-vue-transform-on-1.0.2.tgz?cache=0&sync_timestamp=1610814908336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-transform-on%2Fdownload%2F%40vue%2Fbabel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc" - integrity sha1-m5xpHNBvyFUiGiR1w8yDHXdLx9w= +"@lerna/clean@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" + integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/rimraf-dir" "4.0.0" + p-map "^4.0.0" + p-map-series "^2.1.0" + p-waterfall "^2.1.1" + +"@lerna/cli@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" + integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== + dependencies: + "@lerna/global-options" "4.0.0" + dedent "^0.7.0" + npmlog "^4.1.2" + yargs "^16.2.0" -"@vue/babel-plugin-jsx@^1.0.3": - version "1.0.4" - resolved "https://registry.npm.taobao.org/@vue/babel-plugin-jsx/download/@vue/babel-plugin-jsx-1.0.4.tgz?cache=0&sync_timestamp=1617023355862&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-plugin-jsx%2Fdownload%2F%40vue%2Fbabel-plugin-jsx-1.0.4.tgz#077826ca0eccd77cb6ad698254f5821ded5c5189" - integrity sha1-B3gmyg7M13y2rWmCVPWCHe1cUYk= +"@lerna/collect-uncommitted@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" + integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - "@vue/babel-helper-vue-transform-on" "^1.0.2" - camelcase "^6.0.0" - html-tags "^3.1.0" - svg-tags "^1.0.0" + "@lerna/child-process" "4.0.0" + chalk "^4.1.0" + npmlog "^4.1.2" -"@vue/compiler-core@3.0.11", "@vue/compiler-core@^3.0.0", "@vue/compiler-core@^3.0.1", "@vue/compiler-core@^3.0.2": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/compiler-core/download/@vue/compiler-core-3.0.11.tgz#5ef579e46d7b336b8735228758d1c2c505aae69a" - integrity sha1-XvV55G17M2uHNSKHWNHCxQWq5po= +"@lerna/collect-updates@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" + integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.0.11" - estree-walker "^2.0.1" - source-map "^0.6.1" + "@lerna/child-process" "4.0.0" + "@lerna/describe-ref" "4.0.0" + minimatch "^3.0.4" + npmlog "^4.1.2" + slash "^3.0.0" -"@vue/compiler-dom@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/compiler-dom/download/@vue/compiler-dom-3.0.11.tgz#b15fc1c909371fd671746020ba55b5dab4a730ee" - integrity sha1-sV/ByQk3H9ZxdGAgulW12rSnMO4= - dependencies: - "@vue/compiler-core" "3.0.11" - "@vue/shared" "3.0.11" - -"@vue/compiler-sfc@^3.0.5": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/compiler-sfc/download/@vue/compiler-sfc-3.0.11.tgz#cd8ca2154b88967b521f5ad3b10f5f8b6b665679" - integrity sha1-zYyiFUuIlntSH1rTsQ9fi2tmVnk= - dependencies: - "@babel/parser" "^7.13.9" - "@babel/types" "^7.13.0" - "@vue/compiler-core" "3.0.11" - "@vue/compiler-dom" "3.0.11" - "@vue/compiler-ssr" "3.0.11" - "@vue/shared" "3.0.11" - consolidate "^0.16.0" - estree-walker "^2.0.1" - hash-sum "^2.0.0" - lru-cache "^5.1.1" - magic-string "^0.25.7" - merge-source-map "^1.1.0" - postcss "^8.1.10" - postcss-modules "^4.0.0" - postcss-selector-parser "^6.0.4" - source-map "^0.6.1" +"@lerna/command@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" + integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/project" "4.0.0" + "@lerna/validation-error" "4.0.0" + "@lerna/write-log-file" "4.0.0" + clone-deep "^4.0.1" + dedent "^0.7.0" + execa "^5.0.0" + is-ci "^2.0.0" + npmlog "^4.1.2" + +"@lerna/conventional-commits@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" + integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== + dependencies: + "@lerna/validation-error" "4.0.0" + conventional-changelog-angular "^5.0.12" + conventional-changelog-core "^4.2.2" + conventional-recommended-bump "^6.1.0" + fs-extra "^9.1.0" + get-stream "^6.0.0" + lodash.template "^4.5.0" + npm-package-arg "^8.1.0" + npmlog "^4.1.2" + pify "^5.0.0" + semver "^7.3.4" -"@vue/compiler-ssr@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/compiler-ssr/download/@vue/compiler-ssr-3.0.11.tgz#ac5a05fd1257412fa66079c823d8203b6a889a13" - integrity sha1-rFoF/RJXQS+mYHnII9ggO2qImhM= +"@lerna/create-symlink@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" + integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== dependencies: - "@vue/compiler-dom" "3.0.11" - "@vue/shared" "3.0.11" + cmd-shim "^4.1.0" + fs-extra "^9.1.0" + npmlog "^4.1.2" + +"@lerna/create@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" + integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/validation-error" "4.0.0" + dedent "^0.7.0" + fs-extra "^9.1.0" + globby "^11.0.2" + init-package-json "^2.0.2" + npm-package-arg "^8.1.0" + p-reduce "^2.1.0" + pacote "^11.2.6" + pify "^5.0.0" + semver "^7.3.4" + slash "^3.0.0" + validate-npm-package-license "^3.0.4" + validate-npm-package-name "^3.0.0" + whatwg-url "^8.4.0" + yargs-parser "20.2.4" -"@vue/reactivity@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/reactivity/download/@vue/reactivity-3.0.11.tgz#07b588349fd05626b17f3500cbef7d4bdb4dbd0b" - integrity sha1-B7WINJ/QViaxfzUAy+99S9tNvQs= +"@lerna/describe-ref@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" + integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== dependencies: - "@vue/shared" "3.0.11" + "@lerna/child-process" "4.0.0" + npmlog "^4.1.2" -"@vue/runtime-core@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/runtime-core/download/@vue/runtime-core-3.0.11.tgz#c52dfc6acf3215493623552c1c2919080c562e44" - integrity sha1-xS38as8yFUk2I1UsHCkZCAxWLkQ= +"@lerna/diff@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" + integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== dependencies: - "@vue/reactivity" "3.0.11" - "@vue/shared" "3.0.11" + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/validation-error" "4.0.0" + npmlog "^4.1.2" -"@vue/runtime-dom@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/runtime-dom/download/@vue/runtime-dom-3.0.11.tgz#7a552df21907942721feb6961c418e222a699337" - integrity sha1-elUt8hkHlCch/raWHEGOIippkzc= +"@lerna/exec@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" + integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/profiler" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + p-map "^4.0.0" + +"@lerna/filter-options@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" + integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== dependencies: - "@vue/runtime-core" "3.0.11" - "@vue/shared" "3.0.11" - csstype "^2.6.8" + "@lerna/collect-updates" "4.0.0" + "@lerna/filter-packages" "4.0.0" + dedent "^0.7.0" + npmlog "^4.1.2" -"@vue/shared@3.0.11": - version "3.0.11" - resolved "https://registry.npm.taobao.org/@vue/shared/download/@vue/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77" - integrity sha1-INIt0Np9NYuyHBf5vehigVJkLHc= +"@lerna/filter-packages@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" + integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== + dependencies: + "@lerna/validation-error" "4.0.0" + multimatch "^5.0.0" + npmlog "^4.1.2" -"@vuedx/analyze@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/analyze/download/@vuedx/analyze-0.4.1.tgz#9d5b888ee1b9a798794a44283100f8270bbb6e83" - integrity sha1-nVuIjuG5p5h5SkQoMQD4Jwu7boM= +"@lerna/get-npm-exec-opts@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" + integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.1" - "@babel/parser" "^7.12.3" - "@babel/template" "^7.12.7" - "@babel/traverse" "7.12.1" - "@babel/types" "7.12.1" - "@types/micromatch" "^4.0.1" - "@vuedx/compiler-sfc" "0.4.1" - "@vuedx/compiler-tsx" "0.4.1" - "@vuedx/projectconfig" "0.4.1" - "@vuedx/template-ast-types" "0.4.1" - cli-highlight "^2.1.4" - commander "^6.1.0" - fast-glob "^3.2.4" - hash-sum "^2.0.0" - micromatch "^4.0.2" + npmlog "^4.1.2" -"@vuedx/compiler-sfc@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/compiler-sfc/download/@vuedx/compiler-sfc-0.4.1.tgz#e324bc9e0aaff8a4ddb35e40892a7d884f72f431" - integrity sha1-4yS8ngqv+KTds15AiSp9iE9y9DE= +"@lerna/get-packed@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" + integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== dependencies: - "@vue/compiler-core" "^3.0.2" - lru-cache "^6.0.0" - source-map "^0.6.1" + fs-extra "^9.1.0" + ssri "^8.0.1" + tar "^6.1.0" -"@vuedx/compiler-tsx@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/compiler-tsx/download/@vuedx/compiler-tsx-0.4.1.tgz#c22b7632f7528bf7b3a4905ed1b932da49d4bf5c" - integrity sha1-wit2MvdSi/ezpJBe0bky2knUv1w= +"@lerna/github-client@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" + integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== dependencies: - "@babel/parser" "7.12.3" - "@babel/types" "7.12.1" - "@vue/compiler-core" "^3.0.1" - "@vuedx/template-ast-types" "0.4.1" + "@lerna/child-process" "4.0.0" + "@octokit/plugin-enterprise-rest" "^6.0.1" + "@octokit/rest" "^18.1.0" + git-url-parse "^11.4.4" + npmlog "^4.1.2" -"@vuedx/projectconfig@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/projectconfig/download/@vuedx/projectconfig-0.4.1.tgz#73db7ecf1ec38adc996d9180108d4b2ddde1d189" - integrity sha1-c9t+zx7DityZbZGAEI1LLd3h0Yk= +"@lerna/gitlab-client@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" + integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== + dependencies: + node-fetch "^2.6.1" + npmlog "^4.1.2" + whatwg-url "^8.4.0" -"@vuedx/template-ast-types@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/template-ast-types/download/@vuedx/template-ast-types-0.4.1.tgz#5587b93ba0b2d4bf904f6e6cce76992860c0598a" - integrity sha1-VYe5O6Cy1L+QT25sznaZKGDAWYo= +"@lerna/global-options@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" + integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== + +"@lerna/has-npm-version@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" + integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== dependencies: - "@vue/compiler-core" "^3.0.0" + "@lerna/child-process" "4.0.0" + semver "^7.3.4" -"@vuedx/typecheck@^0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/typecheck/download/@vuedx/typecheck-0.4.1.tgz#5235f6a464b3732c9481740d79e444a48bc58e06" - integrity sha1-UjX2pGSzcyyUgXQNeeREpIvFjgY= +"@lerna/import@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" + integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/validation-error" "4.0.0" + dedent "^0.7.0" + fs-extra "^9.1.0" + p-map-series "^2.1.0" + +"@lerna/info@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" + integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== dependencies: - "@vuedx/typescript-plugin-vue" "0.4.1" - "@vuedx/vue-virtual-textdocument" "0.4.1" - chalk "^4.1.0" - fast-glob "^3.2.4" - minimist "^1.2.5" - typescript "^4.0.3" + "@lerna/command" "4.0.0" + "@lerna/output" "4.0.0" + envinfo "^7.7.4" -"@vuedx/typescript-plugin-vue@0.4.1", "@vuedx/typescript-plugin-vue@^0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/typescript-plugin-vue/download/@vuedx/typescript-plugin-vue-0.4.1.tgz#5375ff9e25e1708d24a50b36bbb566a5fc82143f" - integrity sha1-U3X/niXhcI0kpQs2u7VmpfyCFD8= +"@lerna/init@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" + integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== dependencies: - "@intlify/core" "^9.0.0-beta.15" - "@vuedx/analyze" "0.4.1" - "@vuedx/compiler-sfc" "0.4.1" - "@vuedx/projectconfig" "0.4.1" - "@vuedx/template-ast-types" "0.4.1" - "@vuedx/vue-virtual-textdocument" "0.4.1" - de-indent "^1.0.2" - json5 "^2.1.3" - quick-lru "^5.1.1" - vscode-uri "^2.1.2" - vscode-web-custom-data "^0.3.2" + "@lerna/child-process" "4.0.0" + "@lerna/command" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" + write-json-file "^4.3.0" -"@vuedx/vue-virtual-textdocument@0.4.1": - version "0.4.1" - resolved "https://registry.npm.taobao.org/@vuedx/vue-virtual-textdocument/download/@vuedx/vue-virtual-textdocument-0.4.1.tgz#6d61dce6f71c71357ac3e9b5fc3b8d33e5fd4ea2" - integrity sha1-bWHc5vcccTV6w+m1/DuNM+X9TqI= +"@lerna/link@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" + integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== dependencies: - "@vuedx/analyze" "0.4.1" - "@vuedx/compiler-sfc" "0.4.1" - "@vuedx/compiler-tsx" "0.4.1" - source-map "^0.6.1" - vscode-languageserver-textdocument "^1.0.1" - vscode-uri "^2.1.2" + "@lerna/command" "4.0.0" + "@lerna/package-graph" "4.0.0" + "@lerna/symlink-dependencies" "4.0.0" + p-map "^4.0.0" + slash "^3.0.0" -JSONStream@^1.0.4: - version "1.3.5" - resolved "https://registry.npm.taobao.org/JSONStream/download/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha1-MgjB8I06TZkmGrZPkjArwV4RHKA= +"@lerna/list@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" + integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/listable" "4.0.0" + "@lerna/output" "4.0.0" -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U= +"@lerna/listable@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" + integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== + dependencies: + "@lerna/query-graph" "4.0.0" + chalk "^4.1.0" + columnify "^1.5.4" -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1617175602652&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0= +"@lerna/log-packed@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" + integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== dependencies: - color-convert "^1.9.0" + byte-size "^7.0.0" + columnify "^1.5.4" + has-unicode "^2.0.1" + npmlog "^4.1.2" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1617175602652&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= +"@lerna/npm-conf@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" + integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== dependencies: - color-convert "^2.0.1" + config-chain "^1.1.12" + pify "^5.0.0" -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= +"@lerna/npm-dist-tag@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" + integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== + dependencies: + "@lerna/otplease" "4.0.0" + npm-package-arg "^8.1.0" + npm-registry-fetch "^9.0.0" + npmlog "^4.1.2" -anymatch@~3.1.1: - version "3.1.2" - resolved "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz?cache=0&sync_timestamp=1617747544108&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha1-wFV8CWrzLxBhmPT04qODU343hxY= +"@lerna/npm-install@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" + integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== + dependencies: + "@lerna/child-process" "4.0.0" + "@lerna/get-npm-exec-opts" "4.0.0" + fs-extra "^9.1.0" + npm-package-arg "^8.1.0" + npmlog "^4.1.2" + signal-exit "^3.0.3" + write-pkg "^4.0.0" + +"@lerna/npm-publish@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" + integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== + dependencies: + "@lerna/otplease" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + fs-extra "^9.1.0" + libnpmpublish "^4.0.0" + npm-package-arg "^8.1.0" + npmlog "^4.1.2" + pify "^5.0.0" + read-package-json "^3.0.0" + +"@lerna/npm-run-script@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" + integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" + "@lerna/child-process" "4.0.0" + "@lerna/get-npm-exec-opts" "4.0.0" + npmlog "^4.1.2" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE= +"@lerna/otplease@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" + integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== dependencies: - sprintf-js "~1.0.2" + "@lerna/prompt" "4.0.0" -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npm.taobao.org/argparse/download/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg= +"@lerna/output@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" + integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== + dependencies: + npmlog "^4.1.2" -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.npm.taobao.org/array-ify/download/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= +"@lerna/pack-directory@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" + integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== + dependencies: + "@lerna/get-packed" "4.0.0" + "@lerna/package" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + npm-packlist "^2.1.4" + npmlog "^4.1.2" + tar "^6.1.0" + temp-write "^4.0.0" + +"@lerna/package-graph@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" + integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== + dependencies: + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/validation-error" "4.0.0" + npm-package-arg "^8.1.0" + npmlog "^4.1.2" + semver "^7.3.4" -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.npm.taobao.org/arrify/download/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +"@lerna/package@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" + integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== + dependencies: + load-json-file "^6.2.0" + npm-package-arg "^8.1.0" + write-pkg "^4.0.0" -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.npm.taobao.org/at-least-node/download/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha1-YCzUtG6EStTv/JKoARo8RuAjjcI= +"@lerna/prerelease-id-from-version@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" + integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== + dependencies: + semver "^7.3.4" -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= +"@lerna/profiler@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" + integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== + dependencies: + fs-extra "^9.1.0" + npmlog "^4.1.2" + upath "^2.0.1" -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg= +"@lerna/project@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" + integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== + dependencies: + "@lerna/package" "4.0.0" + "@lerna/validation-error" "4.0.0" + cosmiconfig "^7.0.0" + dedent "^0.7.0" + dot-prop "^6.0.1" + glob-parent "^5.1.1" + globby "^11.0.2" + load-json-file "^6.2.0" + npmlog "^4.1.2" + p-map "^4.0.0" + resolve-from "^5.0.0" + write-json-file "^4.3.0" -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= +"@lerna/prompt@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" + integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== + dependencies: + inquirer "^7.3.3" + npmlog "^4.1.2" -bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28= +"@lerna/publish@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" + integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== + dependencies: + "@lerna/check-working-tree" "4.0.0" + "@lerna/child-process" "4.0.0" + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/describe-ref" "4.0.0" + "@lerna/log-packed" "4.0.0" + "@lerna/npm-conf" "4.0.0" + "@lerna/npm-dist-tag" "4.0.0" + "@lerna/npm-publish" "4.0.0" + "@lerna/otplease" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/pack-directory" "4.0.0" + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/pulse-till-done" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + "@lerna/version" "4.0.0" + fs-extra "^9.1.0" + libnpmaccess "^4.0.1" + npm-package-arg "^8.1.0" + npm-registry-fetch "^9.0.0" + npmlog "^4.1.2" + p-map "^4.0.0" + p-pipe "^3.1.0" + pacote "^11.2.6" + semver "^7.3.4" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= +"@lerna/pulse-till-done@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" + integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" + npmlog "^4.1.2" -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= +"@lerna/query-graph@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" + integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== dependencies: - fill-range "^7.0.1" + "@lerna/package-graph" "4.0.0" -browserslist@^4.14.5: - version "4.16.4" - resolved "https://registry.npm.taobao.org/browserslist/download/browserslist-4.16.4.tgz?cache=0&sync_timestamp=1618225847505&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.16.4.tgz#7ebf913487f40caf4637b892b268069951c35d58" - integrity sha1-fr+RNIf0DK9GN7iSsmgGmVHDXVg= +"@lerna/resolve-symlink@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" + integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== dependencies: - caniuse-lite "^1.0.30001208" - colorette "^1.2.2" - electron-to-chromium "^1.3.712" - escalade "^3.1.1" - node-releases "^1.1.71" + fs-extra "^9.1.0" + npmlog "^4.1.2" + read-cmd-shim "^2.0.0" -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M= - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.npm.taobao.org/camelcase-keys/download/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha1-XnVda6UaoiPsfT1S8ld4IQ+dw8A= +"@lerna/rimraf-dir@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" + integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" + "@lerna/child-process" "4.0.0" + npmlog "^4.1.2" + path-exists "^4.0.0" + rimraf "^3.0.2" -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA= +"@lerna/run-lifecycle@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" + integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== + dependencies: + "@lerna/npm-conf" "4.0.0" + npm-lifecycle "^3.1.5" + npmlog "^4.1.2" -camelcase@^6.0.0: - version "6.2.0" - resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha1-kkr4gcnVJaydh/QNlk5c6pgqGAk= +"@lerna/run-topologically@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" + integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== + dependencies: + "@lerna/query-graph" "4.0.0" + p-queue "^6.6.2" -caniuse-lite@^1.0.30001208: - version "1.0.30001208" - resolved "https://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30001208.tgz#a999014a35cebd4f98c405930a057a0d75352eb9" - integrity sha1-qZkBSjXOvU+YxAWTCgV6DXU1Lrk= +"@lerna/run@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" + integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== + dependencies: + "@lerna/command" "4.0.0" + "@lerna/filter-options" "4.0.0" + "@lerna/npm-run-script" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/profiler" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/timer" "4.0.0" + "@lerna/validation-error" "4.0.0" + p-map "^4.0.0" + +"@lerna/symlink-binary@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" + integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== + dependencies: + "@lerna/create-symlink" "4.0.0" + "@lerna/package" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" -chalk@4.1.0, chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha1-ThSHCmGNni7dl92DRf2dncMVZGo= +"@lerna/symlink-dependencies@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" + integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" + "@lerna/create-symlink" "4.0.0" + "@lerna/resolve-symlink" "4.0.0" + "@lerna/symlink-binary" "4.0.0" + fs-extra "^9.1.0" + p-map "^4.0.0" + p-map-series "^2.1.0" -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ= +"@lerna/timer@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" + integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== + +"@lerna/validation-error@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" + integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + npmlog "^4.1.2" -"chokidar@>=2.0.0 <4.0.0": - version "3.5.1" - resolved "https://registry.npm.taobao.org/chokidar/download/chokidar-3.5.1.tgz?cache=0&sync_timestamp=1610719402189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha1-7pznu+vSt59J8wR5nVRo4x4U5oo= +"@lerna/version@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" + integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== + dependencies: + "@lerna/check-working-tree" "4.0.0" + "@lerna/child-process" "4.0.0" + "@lerna/collect-updates" "4.0.0" + "@lerna/command" "4.0.0" + "@lerna/conventional-commits" "4.0.0" + "@lerna/github-client" "4.0.0" + "@lerna/gitlab-client" "4.0.0" + "@lerna/output" "4.0.0" + "@lerna/prerelease-id-from-version" "4.0.0" + "@lerna/prompt" "4.0.0" + "@lerna/run-lifecycle" "4.0.0" + "@lerna/run-topologically" "4.0.0" + "@lerna/validation-error" "4.0.0" + chalk "^4.1.0" + dedent "^0.7.0" + load-json-file "^6.2.0" + minimatch "^3.0.4" + npmlog "^4.1.2" + p-map "^4.0.0" + p-pipe "^3.1.0" + p-reduce "^2.1.0" + p-waterfall "^2.1.1" + semver "^7.3.4" + slash "^3.0.0" + temp-write "^4.0.0" + write-json-file "^4.3.0" + +"@lerna/write-log-file@4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" + integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" + npmlog "^4.1.2" + write-file-atomic "^3.0.3" -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.npm.taobao.org/ci-info/download/ci-info-2.0.0.tgz?cache=0&sync_timestamp=1613628860338&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fci-info%2Fdownload%2Fci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y= +"@ls-lint/ls-lint@^1.10.0": + version "1.10.0" + resolved "https://registry.npmjs.org/@ls-lint/ls-lint/-/ls-lint-1.10.0.tgz#cad20085edc010a3e938aa01bb66d05e5e12b3f3" + integrity sha512-C1vrI8zFp/28CiqCQHtfu/GqUg2iLYZqtlJHCYfqlg6OJopv7lHAPS0rzk06Ev1121yj4Gi/GmXMBlF+j35DcQ== -cli-highlight@^2.1.4: - version "2.1.11" - resolved "https://registry.npm.taobao.org/cli-highlight/download/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha1-SXNvpFLwqvT65YDjCssmgo0twb8= +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&sync_timestamp=1604881199684&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE= +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npm.taobao.org/cliui/download/cliui-7.0.4.tgz?cache=0&sync_timestamp=1604881199684&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08= +"@npmcli/ci-detect@^1.0.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" + integrity sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q== + +"@npmcli/fs@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" + "@gar/promisify" "^1.0.1" + semver "^7.3.5" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg= +"@npmcli/git@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== dependencies: - color-name "1.1.3" + "@npmcli/promise-spawn" "^1.3.2" + lru-cache "^6.0.0" + mkdirp "^1.0.4" + npm-pick-manifest "^6.1.1" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^2.0.2" + +"@npmcli/installed-package-contents@^1.0.6": + version "1.0.7" + resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" + integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== + dependencies: + npm-bundled "^1.1.1" + npm-normalize-package-bin "^1.0.1" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@npmcli/node-gyp@^1.0.2": + version "1.0.3" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= +"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": + version "1.3.2" + resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" + integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== dependencies: - color-name "~1.1.4" + infer-owner "^1.0.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +"@npmcli/run-script@^1.8.2": + version "1.8.6" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== + dependencies: + "@npmcli/node-gyp" "^1.0.2" + "@npmcli/promise-spawn" "^1.3.2" + node-gyp "^7.1.0" + read-package-json-fast "^2.0.1" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= +"@octokit/auth-token@^2.4.4": + version "2.5.0" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" + integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== + dependencies: + "@octokit/types" "^6.0.3" -colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.npm.taobao.org/colorette/download/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha1-y8x51emcrqLb8Q6zom/Ys+as+pQ= +"@octokit/core@^3.5.1": + version "3.5.1" + resolved "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" + integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== + dependencies: + "@octokit/auth-token" "^2.4.4" + "@octokit/graphql" "^4.5.8" + "@octokit/request" "^5.6.0" + "@octokit/request-error" "^2.0.5" + "@octokit/types" "^6.0.3" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^6.0.1": + version "6.0.12" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== + dependencies: + "@octokit/types" "^6.0.3" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^4.5.8": + version "4.8.0" + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" + integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== + dependencies: + "@octokit/request" "^5.6.0" + "@octokit/types" "^6.0.3" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^11.2.0": + version "11.2.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" + integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== + +"@octokit/plugin-enterprise-rest@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" + integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -commander@^6.1.0: - version "6.2.1" - resolved "https://registry.npm.taobao.org/commander/download/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha1-B5LraC37wyWZm7K4T93duhEKxzw= +"@octokit/plugin-paginate-rest@^2.16.8": + version "2.17.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" + integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== + dependencies: + "@octokit/types" "^6.34.0" -commander@^7.1.0: - version "7.2.0" - resolved "https://registry.npm.taobao.org/commander/download/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc= +"@octokit/plugin-request-log@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== -compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.npm.taobao.org/compare-func/download/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha1-+2XnXtvd/S5WhVTotbBf/3pR/LM= +"@octokit/plugin-rest-endpoint-methods@^5.12.0": + version "5.13.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" + integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" + "@octokit/types" "^6.34.0" + deprecation "^2.3.1" -compare-versions@^3.6.0: - version "3.6.0" - resolved "https://registry.npm.taobao.org/compare-versions/download/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" - integrity sha1-GlaJkTaF5ah2N7jT/8p1UU7EHWI= +"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" + integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== + dependencies: + "@octokit/types" "^6.0.3" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.6.0": + version "5.6.2" + resolved "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz#1aa74d5da7b9e04ac60ef232edd9a7438dcf32d8" + integrity sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA== + dependencies: + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.1.0" + "@octokit/types" "^6.16.1" + is-plain-object "^5.0.0" + node-fetch "^2.6.1" + universal-user-agent "^6.0.0" + +"@octokit/rest@^18.1.0": + version "18.12.0" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" + integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== + dependencies: + "@octokit/core" "^3.5.1" + "@octokit/plugin-paginate-rest" "^2.16.8" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^5.12.0" + +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": + version "6.34.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" + integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== + dependencies: + "@octokit/openapi-types" "^11.2.0" + +"@polka/url@^0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz#b21510597fd601e5d7c95008b76bf0d254ebfd31" + integrity sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw== + +"@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" + integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== + +"@rollup/pluginutils@^4.1.1": + version "4.1.1" + resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec" + integrity sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ== + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" -consolidate@^0.16.0: - version "0.16.0" - resolved "https://registry.npm.taobao.org/consolidate/download/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16" - integrity sha1-oRhkdokw8vGUMWYKZZBmaPX73BY= +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== dependencies: - bluebird "^3.7.2" + "@sinonjs/commons" "^1.7.0" -conventional-changelog-angular@^5.0.0: - version "5.0.12" - resolved "https://registry.npm.taobao.org/conventional-changelog-angular/download/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" - integrity sha1-yXm4uSHL/iZALrPaW7/aAthlork= +"@stylelint/postcss-css-in-js@^0.37.2": + version "0.37.2" + resolved "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2" + integrity sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA== dependencies: - compare-func "^2.0.0" - q "^1.5.1" + "@babel/core" ">=7.9.0" -conventional-changelog-conventionalcommits@^4.3.1: - version "4.5.0" - resolved "https://registry.npm.taobao.org/conventional-changelog-conventionalcommits/download/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" - integrity sha1-oC4LBtEdNC/cDwDJHXgmXtC8CmI= +"@stylelint/postcss-markdown@^0.36.2": + version "0.36.2" + resolved "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz#0a540c4692f8dcdfc13c8e352c17e7bfee2bb391" + integrity sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ== dependencies: - compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" + remark "^13.0.0" + unist-util-find-all-after "^3.0.2" -conventional-commits-parser@^3.0.0: - version "3.2.1" - resolved "https://registry.npm.taobao.org/conventional-commits-parser/download/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" - integrity sha1-ukTws7ZYjaLun9jaUI6/9Q0RbOI= +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.16" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - trim-off-newlines "^1.0.0" + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI= +"@types/babel__generator@*": + version "7.6.3" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== dependencies: - safe-buffer "~5.1.1" + "@babel/types" "^7.0.0" -core-js@^3.6.1: - version "3.10.1" - resolved "https://registry.npm.taobao.org/core-js/download/core-js-3.10.1.tgz#e683963978b6806dcc6c0a4a8bd4ab0bdaf3f21a" - integrity sha1-5oOWOXi2gG3MbApKi9SrC9rz8ho= +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" -cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-7.0.0.tgz?cache=0&sync_timestamp=1596321756664&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha1-75tE13OVnK5j3ezRIt4jhTtg+NM= +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" + "@babel/types" "^7.3.0" -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4= +"@types/braces@*": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz#5a284d193cfc61abb2e5a50d36ebbc50d942a32b" + integrity sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ== + +"@types/chalk@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" + integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== + dependencies: + chalk "*" + +"@types/commander@^2.12.2": + version "2.12.2" + resolved "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae" + integrity sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q== + dependencies: + commander "*" + +"@types/fs-extra@^9.0.13": + version "9.0.13" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" + integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== + dependencies: + "@types/node" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^26.0.23": + version "26.0.24" + resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" + integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + +"@types/lodash-es@^4.17.4", "@types/lodash-es@^4.17.5": + version "4.17.5" + resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.5.tgz#1c3fdd16849d84aea43890b1c60da379fb501353" + integrity sha512-SHBoI8/0aoMQWAgUHMQ599VM6ZiSKg8sh/0cFqqlQQMyY9uEplc0ULU5yQNzcvdR4ZKa0ey8+vFmahuRbOCT1A== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.176" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.176.tgz#641150fc1cda36fbfa329de603bbb175d7ee20c0" + integrity sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ== + +"@types/markdown-it@^12.0.1": + version "12.2.3" + resolved "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + +"@types/micromatch@^4.0.1": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz#ce29c8b166a73bf980a5727b1e4a4d099965151d" + integrity sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA== + dependencies: + "@types/braces" "*" + +"@types/minimatch@^3.0.3": + version "3.0.5" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/minimist@^1.2.0": + version "1.2.2" + resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + +"@types/node@*", "@types/node@^16.11.6": + version "16.11.6" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" + integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/ora@^3.2.0": + version "3.2.0" + resolved "https://registry.npmjs.org/@types/ora/-/ora-3.2.0.tgz#b2f65d1283a8f36d8b0f9ee767e0732a2f429362" + integrity sha512-jll99xUKpiFbIFZSQcxm4numfsLaOWBzWNaRk3PvTSE7BPqTzzOCFmS0mQ7m8qkTfmYhuYbehTGsxkvRLPC++w== + dependencies: + ora "*" + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prettier@^2.1.5": + version "2.4.1" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" + integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== + +"@types/prompts@^2.0.14": + version "2.0.14" + resolved "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.14.tgz#10cb8899844bb0771cabe57c1becaaaca9a3b521" + integrity sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": + version "2.0.6" + resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^15.0.0": + version "15.0.14" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^4.27.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.27.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@vitejs/plugin-vue-jsx@^1.1.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-1.2.0.tgz#a4216bdbb8b12800537d39e3b5711fcf2eb470ef" + integrity sha512-Y4Er2bn8bHNiUziJizcVT1yQKTq6oOJeBrKkxvjo2yKT/RTSK1ZlkP/qnzchxxuBkx0tYG4Aaxbb9xuVnNNDEA== + dependencies: + "@babel/core" "^7.15.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-transform-typescript" "^7.15.4" + "@rollup/pluginutils" "^4.1.1" + "@vue/babel-plugin-jsx" "^1.0.7" + hash-sum "^2.0.0" + +"@vitejs/plugin-vue@^1.2.3", "@vitejs/plugin-vue@^1.3.0", "@vitejs/plugin-vue@^1.4.0": + version "1.9.4" + resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.9.4.tgz#4f48485432cbb986a9fb9d254dc33ce30ddccbfa" + integrity sha512-0CZqaCoChriPTTtGkERy1LGPcYjGFpi2uYRhBPIkqJqUGV5JnJFhQAgh6oH9j5XZHfrRaisX8W0xSpO4T7S78A== + +"@volar/code-gen@^0.27.24": + version "0.27.24" + resolved "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.27.24.tgz#ccdbe858951c1ee4e0c3979232d52412dc46756a" + integrity sha512-s4j/QqOZUW03PeD6LmVYI00Q1C3CfJEOePDOQwDvCTUov4lFk0iSBtFyYhjlLyQ1pdtV1+TDTErkj2aMQtc4PA== + dependencies: + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + +"@volar/html2pug@^0.27.13": + version "0.27.13" + resolved "https://registry.npmjs.org/@volar/html2pug/-/html2pug-0.27.13.tgz#48dfa73ecf1ef1955a02a046d0c88845950fac85" + integrity sha512-3NYgNA5F3PDsKbbpOrVdGy2S7ZYmZIbFmbp1A/27DDzjj/uIC9Pj7HXVvbYOzi8HcOxUPt0BMrh4TVzBUaCFww== + dependencies: + domelementtype "^2.2.0" + domhandler "^4.2.0" + htmlparser2 "^6.1.0" + pug "^3.0.2" + +"@volar/shared@^0.27.24": + version "0.27.24" + resolved "https://registry.npmjs.org/@volar/shared/-/shared-0.27.24.tgz#a33457ec8ac0b0d367ed54c9e21913a5f8c2d6c2" + integrity sha512-Mi8a4GQaiorfb+o4EqOXDZm9E/uBJXgScFgF+NhtcMBOUKHNMKQyLI7YRGumtyJTTdaX7nSDJjGGTkv23tcOtQ== + dependencies: + upath "^2.0.1" + vscode-jsonrpc "^8.0.0-next.2" + vscode-uri "^3.0.2" + +"@volar/source-map@^0.27.24": + version "0.27.24" + resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-0.27.24.tgz#60f2e070c169be82cbf7ffa296a30c2823c5205f" + integrity sha512-2I5a7cXqekZ66D6lHep7ttJgvVVtPEBUIe1hnpcGbnXWNA2ya6f6jKNNyTmrXQyfkh32IEuaUd4kocR+3AKMag== + dependencies: + "@volar/shared" "^0.27.24" + +"@volar/transforms@^0.27.24": + version "0.27.24" + resolved "https://registry.npmjs.org/@volar/transforms/-/transforms-0.27.24.tgz#68ebc53dca2e36884e247c0866ec3d24ed815784" + integrity sha512-sOHi1ZSapFlxn7yPl4MO5TXd9aWC0BVq2CgXAJ2EESb+ddh2uJbGQgLLNocX+MDh419cUuuFT2QAJpuWHhJcng== + dependencies: + "@volar/shared" "^0.27.24" + vscode-languageserver "^8.0.0-next.2" + +"@vscode/emmet-helper@^2.7.0": + version "2.8.2" + resolved "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.8.2.tgz#9b2ce4fdd62cf3fda45cf8af67c012cfce55edc9" + integrity sha512-A/+pkBYQq2JTow1A2flfTmEOmiF780KpdkoX7VBjQ7wujeA+CFUPd17YdeIa9aim20+J5Jp7SFujPDwVFiQucQ== + dependencies: + emmet "^2.3.0" + jsonc-parser "^2.3.0" + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.15.1" + vscode-nls "^5.0.0" + vscode-uri "^2.1.2" + +"@vue/babel-helper-vue-transform-on@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc" + integrity sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA== + +"@vue/babel-plugin-jsx@^1.0.6", "@vue/babel-plugin-jsx@^1.0.7": + version "1.1.1" + resolved "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.1.tgz#0c5bac27880d23f89894cd036a37b55ef61ddfc1" + integrity sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + "@vue/babel-helper-vue-transform-on" "^1.0.2" + camelcase "^6.0.0" + html-tags "^3.1.0" + svg-tags "^1.0.0" + +"@vue/compiler-core@3.2.21", "@vue/compiler-core@^3.0.0", "@vue/compiler-core@^3.0.1", "@vue/compiler-core@^3.0.2": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.21.tgz#26566c32b2ad838199d471ef5df620a83846f24e" + integrity sha512-NhhiQZNG71KNq1h5pMW/fAXdTF7lJRaSI7LDm2edhHXVz1ROMICo8SreUmQnSf4Fet0UPBVqJ988eF4+936iDQ== + dependencies: + "@babel/parser" "^7.15.0" + "@vue/shared" "3.2.21" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.21", "@vue/compiler-dom@^3.2.19": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.21.tgz#d6f6c85364ef8888f9c4e9122bfba11e78fb398c" + integrity sha512-gsJD3DpYZSYquiA7UIPsMDSlAooYWDvHPq9VRsqzJEk2PZtFvLvHPb4aaMD8Ufd62xzYn32cnnkzsEOJhyGilA== + dependencies: + "@vue/compiler-core" "3.2.21" + "@vue/shared" "3.2.21" + +"@vue/compiler-sfc@3.2.21", "@vue/compiler-sfc@^3.0.11", "@vue/compiler-sfc@^3.0.5", "@vue/compiler-sfc@^3.1.1", "@vue/compiler-sfc@^3.2.1": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.21.tgz#42639ee49e725afb7d8f1d1940e75dc17a56002c" + integrity sha512-+yDlUSebKpz/ovxM2vLRRx7w/gVfY767pOfYTgbIhAs+ogvIV2BsIt4fpxlThnlCNChJ+yE0ERUNoROv2kEGEQ== + dependencies: + "@babel/parser" "^7.15.0" + "@vue/compiler-core" "3.2.21" + "@vue/compiler-dom" "3.2.21" + "@vue/compiler-ssr" "3.2.21" + "@vue/ref-transform" "3.2.21" + "@vue/shared" "3.2.21" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.21": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.21.tgz#37d124f89e8adef9fd56b85775de4b5310a0436e" + integrity sha512-eU+A0iWYy+1zAo2CRIJ0zSVlv1iuGAIbNRCnllSJ31pV1lX3jypJYzGbJlSRAbB7VP6E+tYveVT1Oq8JKewa3g== + dependencies: + "@vue/compiler-dom" "3.2.21" + "@vue/shared" "3.2.21" + +"@vue/devtools-api@^6.0.0-beta.18": + version "6.0.0-beta.20" + resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.20.tgz#b5405c9a84fb44687d05e7c4c7854b1639141106" + integrity sha512-21u2jFOk8jbAneeGpDwZQ0W66RJa0IBDUyVl6SgKnn2cRFjLWzKj+ukXjpLhYr1KASyCe5E5U4jXwChVo0YUAw== + +"@vue/reactivity@3.2.21", "@vue/reactivity@^3.2.19": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.21.tgz#073ad144192ed78a07e151e95a3baa515e4099a2" + integrity sha512-7C57zFm/5E3SSTUhVuYj1InDwuJ+GIVQ/z+H43C9sST85gIThGXVhksl1yWTAadf8Yz4T5lSbqi5Ds8U/ueWcw== + dependencies: + "@vue/shared" "3.2.21" + +"@vue/ref-transform@3.2.21": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.21.tgz#b0c554c9f640c3f005f77e676066aa0faba90984" + integrity sha512-uiEWWBsrGeun9O7dQExYWzXO3rHm/YdtFNXDVqCSoPypzOVxWxdiL+8hHeWzxMB58fVuV2sT80aUtIVyaBVZgQ== + dependencies: + "@babel/parser" "^7.15.0" + "@vue/compiler-core" "3.2.21" + "@vue/shared" "3.2.21" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/runtime-core@3.2.21": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.21.tgz#e12dac8c3893b7aebfc37e32066718d8aa686ac5" + integrity sha512-7oOxKaU0D2IunOAMOOHZgJVrHg63xwng8BZx3fbgmakqEIMwHhQcp+5GV1sOg/sWW7R4UhaRDIUCukO2GRVK2Q== + dependencies: + "@vue/reactivity" "3.2.21" + "@vue/shared" "3.2.21" + +"@vue/runtime-dom@3.2.21": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.21.tgz#33dd15bc85281e773177a30dc6931c294bd77aa1" + integrity sha512-apBdriD6QsI4ywbllY8kjr9/0scGuStDuvLbJULPQkFPtHzntd51bP5PQTQVAEIc9kwnTozmj6x6ZdX/cwo7xA== + dependencies: + "@vue/runtime-core" "3.2.21" + "@vue/shared" "3.2.21" + csstype "^2.6.8" + +"@vue/server-renderer@3.2.21", "@vue/server-renderer@^3.1.1", "@vue/server-renderer@^3.2.1": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.21.tgz#887d0a44de76f72313cff2686a24c0315231d634" + integrity sha512-QBgYqVgI7XCSBCqGa4LduV9vpfQFdZBOodFmq5Txk5W/v1KrJ1LoOh2Q0RHiRgtoK/UR9uyvRVcYqOmwHkZNEg== + dependencies: + "@vue/compiler-ssr" "3.2.21" + "@vue/shared" "3.2.21" + +"@vue/shared@3.2.21", "@vue/shared@^3.2.19": + version "3.2.21" + resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.21.tgz#4cd80c0e62cf65a7adab2449e86b6f0cb33a130b" + integrity sha512-5EQmIPK6gw4UVYUbM959B0uPsJ58+xoMESCZs3N89XyvJ9e+fX4pqEPrOGV8OroIk3SbEvJcC+eYc8BH9JQrHA== + +"@vue/test-utils@^2.0.0-rc.9": + version "2.0.0-rc.16" + resolved "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.0.0-rc.16.tgz#59380f02870f856ac002a29c02681d3f3fcbafeb" + integrity sha512-TubikDVkI2LuRKRPSLv3lYpbpvvucT2DIcGqfBVpvYs4W19u0EBTJEdmfwmSuLY7H1TyAr9Stur3PI1sWWvTGQ== + +"@vuedx/analyze@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/analyze/-/analyze-0.4.1.tgz#9d5b888ee1b9a798794a44283100f8270bbb6e83" + integrity sha512-7FBFWboGCFDVtMnc+egZU0UpdKFfuyhRVjs+pycWvZ630eKsGK4zKRKmJBXqccctWO2FRRRuW4pXfi1SbJGY0w== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.12.7" + "@babel/traverse" "7.12.1" + "@babel/types" "7.12.1" + "@types/micromatch" "^4.0.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/compiler-tsx" "0.4.1" + "@vuedx/projectconfig" "0.4.1" + "@vuedx/template-ast-types" "0.4.1" + cli-highlight "^2.1.4" + commander "^6.1.0" + fast-glob "^3.2.4" + hash-sum "^2.0.0" + micromatch "^4.0.2" + +"@vuedx/compiler-sfc@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/compiler-sfc/-/compiler-sfc-0.4.1.tgz#e324bc9e0aaff8a4ddb35e40892a7d884f72f431" + integrity sha512-WmiNcf6RsTTRqb0oaUhQQ/b0Eg+o+XZRdIqlgvqU5OYxTSYiajDz+Rc+2jIjByFL4WRwyfkKnKPk7C58JW6WGA== + dependencies: + "@vue/compiler-core" "^3.0.2" + lru-cache "^6.0.0" + source-map "^0.6.1" + +"@vuedx/compiler-tsx@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/compiler-tsx/-/compiler-tsx-0.4.1.tgz#c22b7632f7528bf7b3a4905ed1b932da49d4bf5c" + integrity sha512-qlK9HDrMxcOnh4/yX4/gXaEaas4L4qpN4UskfyyGLM5NmBWSjX5dGagTvKsNd0WIl5RBIYiwEYLkuoCfOJGwUw== + dependencies: + "@babel/parser" "7.12.3" + "@babel/types" "7.12.1" + "@vue/compiler-core" "^3.0.1" + "@vuedx/template-ast-types" "0.4.1" + +"@vuedx/projectconfig@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/projectconfig/-/projectconfig-0.4.1.tgz#73db7ecf1ec38adc996d9180108d4b2ddde1d189" + integrity sha512-rQMfQzEzeg7Y7+D2P+HDwPYiG5LRv+iE5klARAwtW/PZ27sn/PT40taDkgw199bwpZaYT2bKAwMU1CN/ATF+pg== + +"@vuedx/template-ast-types@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/template-ast-types/-/template-ast-types-0.4.1.tgz#5587b93ba0b2d4bf904f6e6cce76992860c0598a" + integrity sha512-PK465sch8Jzh33wJjYbWoXf41yp7xGNxyqW+AmEJ02HiB4HRHaK2RdHxc6FutyluEaTurgDFNdr2iAkiHVZeoA== + dependencies: + "@vue/compiler-core" "^3.0.0" + +"@vuedx/typecheck@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/typecheck/-/typecheck-0.4.1.tgz#5235f6a464b3732c9481740d79e444a48bc58e06" + integrity sha512-fNd6+N5HVX2qGMKlL6X+e1FIn1GO37ErfgGMnV7UdCzUyOsfzVldEw6sNu1NHyZ0pnPZduQ0rNMDaY88BJHtZQ== + dependencies: + "@vuedx/typescript-plugin-vue" "0.4.1" + "@vuedx/vue-virtual-textdocument" "0.4.1" + chalk "^4.1.0" + fast-glob "^3.2.4" + minimist "^1.2.5" + typescript "^4.0.3" + +"@vuedx/typescript-plugin-vue@0.4.1", "@vuedx/typescript-plugin-vue@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.1.tgz#5375ff9e25e1708d24a50b36bbb566a5fc82143f" + integrity sha512-JK2PJc05u1/PfHd3QJ9jmPBzbqBsORzliglt8Xpd/wsV9pfRsIF/Qtg5bRkqc495MpiSZiyTgLFOxov216P3TA== + dependencies: + "@intlify/core" "^9.0.0-beta.15" + "@vuedx/analyze" "0.4.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/projectconfig" "0.4.1" + "@vuedx/template-ast-types" "0.4.1" + "@vuedx/vue-virtual-textdocument" "0.4.1" + de-indent "^1.0.2" + json5 "^2.1.3" + quick-lru "^5.1.1" + vscode-uri "^2.1.2" + vscode-web-custom-data "^0.3.2" + +"@vuedx/vue-virtual-textdocument@0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@vuedx/vue-virtual-textdocument/-/vue-virtual-textdocument-0.4.1.tgz#6d61dce6f71c71357ac3e9b5fc3b8d33e5fd4ea2" + integrity sha512-uyBXaf3/Y2QdssfLG1hmQKbSD/2tYM2eeeHKK56Klz1RzkRBxBAP0rkKS/riHzDZfVuHQ6QP4qa4QpTSav5RGQ== + dependencies: + "@vuedx/analyze" "0.4.1" + "@vuedx/compiler-sfc" "0.4.1" + "@vuedx/compiler-tsx" "0.4.1" + source-map "^0.6.1" + vscode-languageserver-textdocument "^1.0.1" + vscode-uri "^2.1.2" + +JSONStream@^1.0.4: + version "1.3.5" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +abbrev@1: + version "1.1.1" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.5: + version "1.3.7" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.5.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== + +add-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" + integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= + +agent-base@6, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agentkeepalive@^4.1.3: + version "4.1.4" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" + integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== + dependencies: + debug "^4.1.0" + depd "^1.1.2" + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.6.3" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" + integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +algoliasearch@^4.0.0: + version "4.11.0" + resolved "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.11.0.tgz#234befb3ac355c094077f0edf3777240b1ee013c" + integrity sha512-IXRj8kAP2WrMmj+eoPqPc6P7Ncq1yZkFiyDrjTBObV1ADNL8Z/KdZ+dWC5MmYcBLAbcB/mMCpak5N/D1UIZvsA== + dependencies: + "@algolia/cache-browser-local-storage" "4.11.0" + "@algolia/cache-common" "4.11.0" + "@algolia/cache-in-memory" "4.11.0" + "@algolia/client-account" "4.11.0" + "@algolia/client-analytics" "4.11.0" + "@algolia/client-common" "4.11.0" + "@algolia/client-personalization" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/logger-common" "4.11.0" + "@algolia/logger-console" "4.11.0" + "@algolia/requester-browser-xhr" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/requester-node-http" "4.11.0" + "@algolia/transporter" "4.11.0" + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +aproba@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@~1.1.2: + version "1.1.7" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= + +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +asap@^2.0.0, asap@~2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-never@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" + integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async-validator@^4.0.2: + version "4.0.7" + resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe" + integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +autoprefixer@^9.8.6: + version "9.8.8" + resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +babel-jest@^27.0.2, babel-jest@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz#0636a3404c68e07001e434ac4956d82da8a80022" + integrity sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ== + dependencies: + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^27.2.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.2.0: + version "27.2.0" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277" + integrity sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" + integrity sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.4" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.3.0.tgz#fa7ca3d1ee9ddc6193600ffb632c9785d54918af" + integrity sha512-JLwi9vloVdXLjzACL80j24bG6/T1gYxwowG44dg6HN/7aTPdyPbJJidf6ajoA3RPHHtW0j9KMrSOLpIZpAnPpg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.4" + core-js-compat "^3.18.0" + +babel-plugin-polyfill-regenerator@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz#2e9808f5027c4336c994992b48a4262580cb8d6d" + integrity sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.4" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.2.0: + version "27.2.0" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz#556bbbf340608fed5670ab0ea0c8ef2449fba885" + integrity sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg== + dependencies: + babel-plugin-jest-hoist "^27.2.0" + babel-preset-current-node-syntax "^1.0.0" + +babel-walk@3.0.0-canary-5: + version "3.0.0-canary-5" + resolved "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" + integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw== + dependencies: + "@babel/types" "^7.9.6" + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +balanced-match@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" + integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +before-after-hook@^2.2.0: + version "2.2.2" + resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bl@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz#6928804a41e9da9034868e1c50ca88f21f57aea2" + integrity sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.17.6: + version "4.17.6" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d" + integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw== + dependencies: + caniuse-lite "^1.0.30001274" + electron-to-chromium "^1.3.886" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= + +byte-size@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" + integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^15.0.5, cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001274: + version "1.0.30001278" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001278.tgz#51cafc858df77d966b17f59b5839250b24417fff" + integrity sha512-mpF9KeH8u5cMoEmIic/cr7PNS+F5LWBk0t2ekGT60lFf0Wq+n9LspAj0g3P+o7DQhD3sUdlMln4YFAWhFYn9jg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@*, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" + integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= + dependencies: + is-regex "^1.0.3" + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.2" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +ci-info@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" + integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-highlight@^2.1.4: + version "2.1.11" + resolved "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.6.0: + version "2.6.1" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-truncate@2.1.0, cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone-regexp@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" + integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q== + dependencies: + is-regexp "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cmd-shim@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" + integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== + dependencies: + mkdirp-infer-owner "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== + +colorette@^2.0.16: + version "2.0.16" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + +columnify@^1.5.4: + version "1.5.4" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@*, commander@^8.1.0, commander@^8.2.0, commander@^8.3.0: + version "8.3.0" + resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +commander@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== + dependencies: + array-ify "^1.0.0" + dot-prop "^5.1.0" + +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.0.2" + typedarray "^0.0.6" + +config-chain@^1.1.12: + version "1.1.13" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constantinople@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" + integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw== + dependencies: + "@babel/parser" "^7.6.0" + "@babel/types" "^7.6.1" + +conventional-changelog-angular@^5.0.0, conventional-changelog-angular@^5.0.12: + version "5.0.13" + resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" + integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== + dependencies: + compare-func "^2.0.0" + q "^1.5.1" + +conventional-changelog-conventionalcommits@^4.3.1: + version "4.6.1" + resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.1.tgz#f4c0921937050674e578dc7875f908351ccf4014" + integrity sha512-lzWJpPZhbM1R0PIzkwzGBCnAkH5RKJzJfFQZcl/D+2lsJxAwGnDKBqn/F4C1RD31GJNn8NuKWQzAZDAVXPp2Mw== + dependencies: + compare-func "^2.0.0" + lodash "^4.17.15" + q "^1.5.1" + +conventional-changelog-core@^4.2.2: + version "4.2.4" + resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" + integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== + dependencies: + add-stream "^1.0.0" + conventional-changelog-writer "^5.0.0" + conventional-commits-parser "^3.2.0" + dateformat "^3.0.0" + get-pkg-repo "^4.0.0" + git-raw-commits "^2.0.8" + git-remote-origin-url "^2.0.0" + git-semver-tags "^4.1.1" + lodash "^4.17.15" + normalize-package-data "^3.0.0" + q "^1.5.1" + read-pkg "^3.0.0" + read-pkg-up "^3.0.0" + through2 "^4.0.0" + +conventional-changelog-preset-loader@^2.3.4: + version "2.3.4" + resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" + integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== + +conventional-changelog-writer@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec" + integrity sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g== + dependencies: + conventional-commits-filter "^2.0.7" + dateformat "^3.0.0" + handlebars "^4.7.6" + json-stringify-safe "^5.0.1" + lodash "^4.17.15" + meow "^8.0.0" + semver "^6.0.0" + split "^1.0.0" + through2 "^4.0.0" + +conventional-commits-filter@^2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" + integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== + dependencies: + lodash.ismatch "^4.4.0" + modify-values "^1.0.0" + +conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.2.0: + version "3.2.3" + resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.3.tgz#fc43704698239451e3ef35fd1d8ed644f46bd86e" + integrity sha512-YyRDR7On9H07ICFpRm/igcdjIqebXbvf4Cff+Pf0BrBys1i1EOzx9iFXNlAbdrLAR8jf7bkUYkDAr8pEy0q4Pw== + dependencies: + JSONStream "^1.0.4" + is-text-path "^1.0.1" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + +conventional-recommended-bump@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" + integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== + dependencies: + concat-stream "^2.0.0" + conventional-changelog-preset-loader "^2.3.4" + conventional-commits-filter "^2.0.7" + conventional-commits-parser "^3.2.0" + git-raw-commits "^2.0.8" + git-semver-tags "^4.1.1" + meow "^8.0.0" + q "^1.5.1" + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +core-js-compat@^3.18.0, core-js-compat@^3.19.0: + version "3.19.1" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.1.tgz#fe598f1a9bf37310d77c3813968e9f7c7bb99476" + integrity sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g== + dependencies: + browserslist "^4.17.6" + semver "7.0.0" + +core-js@^3.6.1: + version "3.19.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz#f6f173cae23e73a7d88fa23b6e9da329276c6641" + integrity sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csso@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" csstype@^2.6.8: - version "2.6.16" - resolved "https://registry.npm.taobao.org/csstype/download/csstype-2.6.16.tgz?cache=0&sync_timestamp=1614159821728&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcsstype%2Fdownload%2Fcsstype-2.6.16.tgz#544d69f547013b85a40d15bff75db38f34fe9c39" - integrity sha1-VE1p9UcBO4WkDRW/912zjzT+nDk= + version "2.6.18" + resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz#980a8b53085f34af313410af064f2bd241784218" + integrity sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ== + +dargs@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" + integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +dateformat@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= + +debug@2.6.9, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.2" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + +decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + +detect-indent@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= + +detect-indent@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +dezalgo@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + +diacritics@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" + integrity sha1-PvqHMj67hj5mls67AILUj/PW96E= + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +diff-sequences@^27.0.6: + version "27.0.6" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" + integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +doctypes@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" + integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@1, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.2" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== + dependencies: + domelementtype "^2.2.0" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-prop@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + +duplexer@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +electron-to-chromium@^1.3.886: + version "1.3.890" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.890.tgz#e7143b659f73dc4d0512d1ae4baeb0fb9e7bc835" + integrity sha512-VWlVXSkv0cA/OOehrEyqjUTHwV8YXCPTfPvbtoeU2aHR21vI4Ejh5aC4AxUwOmbLbBgb6Gd3URZahoCxtBqCYQ== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emmet@^2.3.0: + version "2.3.4" + resolved "https://registry.npmjs.org/emmet/-/emmet-2.3.4.tgz#5ba0d7a5569a68c7697dfa890c772e4f3179d123" + integrity sha512-3IqSwmO+N2ZGeuhDyhV/TIOJFUbkChi53bcasSNRE7Yd+4eorbbYz4e53TpMECt38NtYkZNupQCZRlwdAYA42A== + dependencies: + "@emmetio/abbreviation" "^2.2.2" + "@emmetio/css-abbreviation" "^2.1.4" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encoding@^0.1.12: + version "0.1.13" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +enquirer@^2.3.5, enquirer@^2.3.6: + version "2.3.6" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +envinfo@^7.7.4: + version "7.8.1" + resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +esbuild-android-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.12.tgz#e1f199dc05405cdc6670c00fb6c793822bf8ae4c" + integrity sha512-TSVZVrb4EIXz6KaYjXfTzPyyRpXV5zgYIADXtQsIenjZ78myvDGaPi11o4ZSaHIwFHsuwkB6ne5SZRBwAQ7maw== + +esbuild-darwin-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.12.tgz#f5c59e622955c01f050e5a7ac9c1d41db714b94d" + integrity sha512-c51C+N+UHySoV2lgfWSwwmlnLnL0JWj/LzuZt9Ltk9ub1s2Y8cr6SQV5W3mqVH1egUceew6KZ8GyI4nwu+fhsw== + +esbuild-darwin-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.12.tgz#8abae74c2956a8aa568fc52c78829338c4a4b988" + integrity sha512-JvAMtshP45Hd8A8wOzjkY1xAnTKTYuP/QUaKp5eUQGX+76GIie3fCdUUr2ZEKdvpSImNqxiZSIMziEiGB5oUmQ== + +esbuild-freebsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.12.tgz#6ad2ab8c0364ee7dd2d6e324d876a8e60ae75d12" + integrity sha512-r6On/Skv9f0ZjTu6PW5o7pdXr8aOgtFOEURJZYf1XAJs0IQ+gW+o1DzXjVkIoT+n1cm3N/t1KRJfX71MPg/ZUA== + +esbuild-freebsd-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.12.tgz#6f38155f4c300ac4c8adde1fde3cc6a4440a8294" + integrity sha512-F6LmI2Q1gii073kmBE3NOTt/6zLL5zvZsxNLF8PMAwdHc+iBhD1vzfI8uQZMJA1IgXa3ocr3L3DJH9fLGXy6Yw== + +esbuild-linux-32@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.12.tgz#b1d15e330188a8c21de75c3f0058628a3eefade7" + integrity sha512-U1UZwG3UIwF7/V4tCVAo/nkBV9ag5KJiJTt+gaCmLVWH3bPLX7y+fNlhIWZy8raTMnXhMKfaTvWZ9TtmXzvkuQ== + +esbuild-linux-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.12.tgz#25bd64b66162b02348e32d8f12e4c9ee61f1d070" + integrity sha512-YpXSwtu2NxN3N4ifJxEdsgd6Q5d8LYqskrAwjmoCT6yQnEHJSF5uWcxv783HWN7lnGpJi9KUtDvYsnMdyGw71Q== + +esbuild-linux-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.12.tgz#ba582298457cc5c9ac823a275de117620c06537f" + integrity sha512-sgDNb8kb3BVodtAlcFGgwk+43KFCYjnFOaOfJibXnnIojNWuJHpL6aQJ4mumzNWw8Rt1xEtDQyuGK9f+Y24jGA== + +esbuild-linux-arm@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.12.tgz#6bc81c957bff22725688cc6359c29a25765be09b" + integrity sha512-SyiT/JKxU6J+DY2qUiSLZJqCAftIt3uoGejZ0HDnUM2MGJqEGSGh7p1ecVL2gna3PxS4P+j6WAehCwgkBPXNIw== + +esbuild-linux-mips64le@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.12.tgz#ef3c4aba3e585d847cbade5945a8b4a5c62c7ce2" + integrity sha512-qQJHlZBG+QwVIA8AbTEtbvF084QgDi4DaUsUnA+EolY1bxrG+UyOuGflM2ZritGhfS/k7THFjJbjH2wIeoKA2g== + +esbuild-linux-ppc64le@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.12.tgz#a21fb64e80c38bef06122e48283990fc6db578e1" + integrity sha512-2dSnm1ldL7Lppwlo04CGQUpwNn5hGqXI38OzaoPOkRsBRWFBozyGxTFSee/zHFS+Pdh3b28JJbRK3owrrRgWNw== + +esbuild-netbsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.12.tgz#1ea7fc8cfce88a20a4047b867ef184049a6641ae" + integrity sha512-D4raxr02dcRiQNbxOLzpqBzcJNFAdsDNxjUbKkDMZBkL54Z0vZh4LRndycdZAMcIdizC/l/Yp/ZsBdAFxc5nbA== + +esbuild-openbsd-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.12.tgz#adde32f2f1b05dc4bd4fc544d6ea5a4379f9ca4d" + integrity sha512-KuLCmYMb2kh05QuPJ+va60bKIH5wHL8ypDkmpy47lzwmdxNsuySeCMHuTv5o2Af1RUn5KLO5ZxaZeq4GEY7DaQ== + +esbuild-register@^2.6.0: + version "2.6.0" + resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-2.6.0.tgz#9f19a54c82be751dd87673d6a66d7b9e1cdd8498" + integrity sha512-2u4AtnCXP5nivtIxZryiZOUcEQkOzFS7UhAqibUEmaTAThJ48gDLYTBF/Fsz+5r0hbV1jrFE6PQvPDUrKZNt/Q== + dependencies: + esbuild "^0.12.8" + jsonc-parser "^3.0.0" + +esbuild-sunos-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.12.tgz#a7ecaf52b7364fbee76dc8aa707fa3e1cff3342c" + integrity sha512-jBsF+e0woK3miKI8ufGWKG3o3rY9DpHvCVRn5eburMIIE+2c+y3IZ1srsthKyKI6kkXLvV4Cf/E7w56kLipMXw== + +esbuild-windows-32@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.12.tgz#a8756033dc905c4b7bea19be69f7ee68809f8770" + integrity sha512-L9m4lLFQrFeR7F+eLZXG82SbXZfUhyfu6CexZEil6vm+lc7GDCE0Q8DiNutkpzjv1+RAbIGVva9muItQ7HVTkQ== + +esbuild-windows-64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.12.tgz#ae694aa66ca078acb8509b2da31197ed1f40f798" + integrity sha512-k4tX4uJlSbSkfs78W5d9+I9gpd+7N95W7H2bgOMFPsYREVJs31+Q2gLLHlsnlY95zBoPQMIzHooUIsixQIBjaQ== + +esbuild-windows-arm64@0.13.12: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.12.tgz#782c5a8bd6d717ea55aaafe648f9926ca36a4a88" + integrity sha512-2tTv/BpYRIvuwHpp2M960nG7uvL+d78LFW/ikPItO+2GfK51CswIKSetSpDii+cjz8e9iSPgs+BU4o8nWICBwQ== + +esbuild@^0.12.8: + version "0.12.29" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz#be602db7c4dc78944a9dbde0d1ea19d36c1f882d" + integrity sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g== + +esbuild@^0.13.12, esbuild@^0.13.2: + version "0.13.12" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz#9cac641594bf03cf34145258c093d743ebbde7ca" + integrity sha512-vTKKUt+yoz61U/BbrnmlG9XIjwpdIxmHB8DlPR0AAW6OdS+nBQBci6LUHU2q9WbBobMEIQxxDpKbkmOGYvxsow== + optionalDependencies: + esbuild-android-arm64 "0.13.12" + esbuild-darwin-64 "0.13.12" + esbuild-darwin-arm64 "0.13.12" + esbuild-freebsd-64 "0.13.12" + esbuild-freebsd-arm64 "0.13.12" + esbuild-linux-32 "0.13.12" + esbuild-linux-64 "0.13.12" + esbuild-linux-arm "0.13.12" + esbuild-linux-arm64 "0.13.12" + esbuild-linux-mips64le "0.13.12" + esbuild-linux-ppc64le "0.13.12" + esbuild-netbsd-64 "0.13.12" + esbuild-openbsd-64 "0.13.12" + esbuild-sunos-64 "0.13.12" + esbuild-windows-32 "0.13.12" + esbuild-windows-64 "0.13.12" + esbuild-windows-arm64 "0.13.12" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.0: + version "2.7.1" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.24.2: + version "2.25.2" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz#b3b9160efddb702fc1636659e71ba1d10adbe9e9" + integrity sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.0" + has "^1.0.3" + is-core-module "^2.7.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.11.0" + +eslint-plugin-vue@^7.11.1: + version "7.20.0" + resolved "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.20.0.tgz#98c21885a6bfdf0713c3a92957a5afeaaeed9253" + integrity sha512-oVNDqzBC9h3GO+NTgWeLMhhGigy6/bQaQbHS+0z7C4YEu/qK/yxHvca/2PTZtGNPsCrHwOTgKMrwu02A9iPBmw== + dependencies: + eslint-utils "^2.1.0" + natural-compare "^1.4.0" + semver "^6.3.0" + vue-eslint-parser "^7.10.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7.28.0: + version "7.32.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.2.1: + version "6.2.1" + resolved "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.1, estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^4.0.4: + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execall@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" + integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow== + dependencies: + clone-regexp "^2.1.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz#d0f170b1f5c8a2009bab0beffd4bb94f043e38e7" + integrity sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg== + dependencies: + "@jest/types" "^27.2.5" + ansi-styles "^5.0.0" + jest-get-type "^27.3.1" + jest-matcher-utils "^27.3.1" + jest-message-util "^27.3.1" + jest-regex-util "^27.0.6" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.5, fast-glob@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastest-levenshtein@^1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" + integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== + dependencies: + semver-regex "^3.1.2" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.0.0, fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-minipass@^2.0.0, fs-minipass@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-pkg-repo@^4.0.0: + version "4.2.1" + resolved "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" + integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== + dependencies: + "@hutson/parse-repository-url" "^3.0.0" + hosted-git-info "^4.0.0" + through2 "^2.0.0" + yargs "^16.2.0" + +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + +get-stdin@8.0.0, get-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +git-raw-commits@^2.0.0, git-raw-commits@^2.0.8: + version "2.0.10" + resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" + integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== + dependencies: + dargs "^7.0.0" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + +git-remote-origin-url@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" + integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= + dependencies: + gitconfiglocal "^1.0.0" + pify "^2.3.0" + +git-semver-tags@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" + integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== + dependencies: + meow "^8.0.0" + semver "^6.0.0" + +git-up@^4.0.0: + version "4.0.5" + resolved "https://registry.npmjs.org/git-up/-/git-up-4.0.5.tgz#e7bb70981a37ea2fb8fe049669800a1f9a01d759" + integrity sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA== + dependencies: + is-ssh "^1.3.0" + parse-url "^6.0.0" + +git-url-parse@^11.4.4: + version "11.6.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605" + integrity sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g== + dependencies: + git-up "^4.0.0" + +gitconfiglocal@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" + integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= + dependencies: + ini "^1.3.2" + +glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.0" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.2, globby@^11.0.3: + version "11.0.4" + resolved "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" + integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= + +gonzales-pe@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== + dependencies: + minimist "^1.2.5" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4: + version "4.2.8" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +gray-matter@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + +handlebars@^4.7.6: + version "4.7.7" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-unicode@^2.0.0, has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-sum@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" + integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== + +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" + integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== + dependencies: + lru-cache "^6.0.0" -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.npm.taobao.org/dargs/download/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha1-BAFcQd4Ly2nshAUPPZvgyvjW1cw= +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" -de-indent@^1.0.2: - version "1.0.2" - resolved "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" - integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -debug@^4.1.0: - version "4.3.1" - resolved "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4= +htmlparser2@^3.10.0: + version "3.10.1" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== dependencies: - ms "2.1.2" + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" -decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.npm.taobao.org/decamelize-keys/download/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" -decamelize@^1.1.0, decamelize@^1.2.0: +http-cache-semantics@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-signature@~1.2.0: version "1.2.0" - resolved "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz?cache=0&sync_timestamp=1610348667495&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" -dot-prop@^5.1.0: - version "5.3.0" - resolved "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha1-kMzOcIzZzYLMTcjD3dmr3VWyDog= +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== dependencies: - is-obj "^2.0.0" + agent-base "6" + debug "4" -electron-to-chromium@^1.3.712: - version "1.3.712" - resolved "https://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.712.tgz#ae467ffe5f95961c6d41ceefe858fc36eb53b38f" - integrity sha1-rkZ//l+VlhxtQc7v6Fj8NutTs48= +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1614683062095&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha1-VXBmIEatKeLpFucariYKvf9Pang= +husky@^4.3.7: + version "4.3.8" + resolved "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^7.0.0" + find-versions "^4.0.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^5.0.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" -entities@~2.1.0: - version "2.1.0" - resolved "https://registry.npm.taobao.org/entities/download/entities-2.1.0.tgz?cache=0&sync_timestamp=1611536604219&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fentities%2Fdownload%2Fentities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" - integrity sha1-mS0xKc999ocLlsV4WMJJoSD4uLU= +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha1-tKxAZIEH/c3PriQvQovqihTU8b8= +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: - is-arrayish "^0.2.1" + safer-buffer ">= 2.1.2 < 3.0.0" -esbuild@^0.9.3: - version "0.9.7" - resolved "https://registry.npm.taobao.org/esbuild/download/esbuild-0.9.7.tgz?cache=0&sync_timestamp=1618228973806&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesbuild%2Fdownload%2Fesbuild-0.9.7.tgz#ea0d639cbe4b88ec25fbed4d6ff00c8d788ef70b" - integrity sha1-6g1jnL5LiOwl++1Nb/AMjXiO9ws= +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npm.taobao.org/escalade/download/escalade-3.1.1.tgz?cache=0&sync_timestamp=1602567260560&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA= +ignore-walk@^3.0.3: + version "3.0.4" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha1-E7BM2z5sXRnfkatph6hpVhmwqnE= +ignore@^5.1.4, ignore@^5.1.8: + version "5.1.9" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" + integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== -estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.npm.taobao.org/estree-walker/download/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw= +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= +import-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + +import-local@^3.0.2: + version "3.0.3" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== dependencies: - is-extendable "^0.1.0" + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -fast-glob@^3.2.4: - version "3.2.5" - resolved "https://registry.npm.taobao.org/fast-glob/download/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha1-eTmvKmVt55pPGQGQPuityqfLlmE= +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + once "^1.3.0" + wrappy "1" -fastq@^1.6.0: - version "1.11.0" - resolved "https://registry.npm.taobao.org/fastq/download/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" - integrity sha1-u5+5VaBxMKkY62PB9RYcwypdCFg= +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.2, ini@^1.3.4, ini@^1.3.5: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +init-package-json@^2.0.2: + version "2.0.5" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" + integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== + dependencies: + npm-package-arg "^8.1.5" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "^4.1.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + validate-npm-package-name "^3.0.0" + +inquirer@^7.3.3: + version "7.3.3" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +inquirer@^8.1.2, inquirer@^8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== dependencies: - reusify "^1.0.4" + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== dependencies: - to-regex-range "^5.0.1" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk= +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" + has-bigints "^1.0.1" -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npm.taobao.org/find-up/download/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw= +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" + binary-extensions "^2.0.0" -find-versions@^4.0.0: +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.7.0: + version "2.8.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-expression@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/find-versions/download/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" - integrity sha1-PFflc7+XdpuMuN8Wk0tieRXaSWU= + resolved "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" + integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A== dependencies: - semver-regex "^3.1.2" + acorn "^7.1.1" + object-assign "^4.1.1" -fs-extra@^9.0.0: - version "9.1.0" - resolved "https://registry.npm.taobao.org/fs-extra/download/fs-extra-9.1.0.tgz?cache=0&sync_timestamp=1611075953795&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffs-extra%2Fdownload%2Ffs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha1-WVRGDHZKjaIJS6NVS/g55rmnyG0= +is-extendable@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" + number-is-nan "^1.0.0" -fs.realpath@^1.0.0: +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-interactive@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -fsevents@~2.3.1: - version "2.3.2" - resolved "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0= +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= -generic-names@^2.0.1: +is-negative-zero@^2.0.1: version "2.0.1" - resolved "https://registry.npm.taobao.org/generic-names/download/generic-names-2.0.1.tgz?cache=0&sync_timestamp=1603542772846&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgeneric-names%2Fdownload%2Fgeneric-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" - integrity sha1-+KN46tLMqno08DF7BVVIMq5BuHI= + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== dependencies: - loader-utils "^1.1.0" + has-tostringtag "^1.0.0" -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA= +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34= +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= -get-stdin@8.0.0: - version "8.0.0" - resolved "https://registry.npm.taobao.org/get-stdin/download/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" - integrity sha1-y61qc/63X27rIrqeAfiaooqpelM= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -git-raw-commits@^2.0.0: - version "2.0.10" - resolved "https://registry.npm.taobao.org/git-raw-commits/download/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" - integrity sha1-4iVe2VY7HJw+pr0FgGQQKQKXu8E= - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -glob-parent@^5.1.0, glob-parent@~5.1.0: - version "5.1.2" - resolved "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ= +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: - is-glob "^4.0.1" + isobject "^3.0.1" -glob@^7.0.0: - version "7.1.6" - resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1612268417812&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY= +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-promise@^2.0.0: + version "2.2.2" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.0.3, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.npm.taobao.org/global-dirs/download/global-dirs-0.1.1.tgz?cache=0&sync_timestamp=1610454690113&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobal-dirs%2Fdownload%2Fglobal-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-regexp@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" + integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-ssh@^1.3.0: + version "1.3.3" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" + integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== dependencies: - ini "^1.3.4" + protocols "^1.1.0" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npm.taobao.org/globals/download/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4= +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.6" - resolved "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha1-/wQLKwhTsjw9MQJ1I3BvGIXXa+4= +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" -gray-matter@^4.0.2: - version "4.0.2" - resolved "https://registry.npm.taobao.org/gray-matter/download/gray-matter-4.0.2.tgz#9aa379e3acaf421193fce7d2a28cebd4518ac454" - integrity sha1-mqN546yvQhGT/OfSoozr1FGKxFQ= +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - js-yaml "^3.11.0" - kind-of "^6.0.2" - section-matter "^1.0.0" - strip-bom-string "^1.0.0" + has-symbols "^1.0.2" -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.npm.taobao.org/hard-rejection/download/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha1-HG7aXBaFxjlCdm15u0Cudzzs2IM= +is-text-path@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" + integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= + dependencies: + text-extensions "^1.0.0" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= +is-unicode-supported@^1.0.0, is-unicode-supported@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.1.0.tgz#9127b71f9fa82f52ca5c20e982e7bec0ee31ee1e" + integrity sha512-lDcxivp8TJpLG75/DpatAqNzOpDPSpED8XNtrpBHTdQ2InQ1PbW78jhwSxyxhhu+xbVSast2X38bwj8atwoUQA== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y= +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== dependencies: - function-bind "^1.1.1" + call-bind "^1.0.0" -hash-sum@^2.0.0: - version "2.0.0" - resolved "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" - integrity sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo= +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -highlight.js@^10.7.1: - version "10.7.2" - resolved "https://registry.npm.taobao.org/highlight.js/download/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360" - integrity sha1-iTGbhh7cZsSIVO0ebaIeqJ+Ec2A= +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k= +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -hosted-git-info@^4.0.1: - version "4.0.2" - resolved "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" - integrity sha1-XkJVB+7eT+qEa3Ji8IOEVsQgmWE= - dependencies: - lru-cache "^6.0.0" +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -html-tags@^3.1.0: - version "3.1.0" - resolved "https://registry.npm.taobao.org/html-tags/download/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" - integrity sha1-e15vfmZen7QfMAB+2eDUHpf7IUA= +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -husky@^4.3.7: - version "4.3.8" - resolved "https://registry.npm.taobao.org/husky/download/husky-4.3.8.tgz?cache=0&sync_timestamp=1617005423094&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhusky%2Fdownload%2Fhusky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" - integrity sha1-MRRAYL6WP9aFDlzI8Bmh3+GUKW0= +istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: - chalk "^4.0.0" - ci-info "^2.0.0" - compare-versions "^3.6.0" - cosmiconfig "^7.0.0" - find-versions "^4.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^5.0.0" - please-upgrade-node "^3.2.0" - slash "^3.0.0" - which-pm-runs "^1.0.0" - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" -icss-utils@^5.0.0: +istanbul-lib-instrument@^5.0.4: version "5.1.0" - resolved "https://registry.npm.taobao.org/icss-utils/download/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha1-xr5oWKvQE9do6YNmrkfiXViHsa4= + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.3.0.tgz?cache=0&sync_timestamp=1608469455957&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha1-NxYsJfy566oublPVtNiM4X2eDCs= +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npm.taobao.org/indent-string/download/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= +istanbul-reports@^3.0.2: + version "3.0.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz#a2580107e71279ea6d661ddede929ffc6d693384" + integrity sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= +jest-changed-files@^27.3.0: + version "27.3.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz#22a02cc2b34583fc66e443171dc271c0529d263c" + integrity sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg== dependencies: - once "^1.3.0" - wrappy "1" + "@jest/types" "^27.2.5" + execa "^5.0.0" + throat "^6.0.1" -inherits@2, inherits@^2.0.3: - version "2.0.4" - resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= +jest-circus@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz#1679e74387cbbf0c6a8b42de963250a6469e0797" + integrity sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw== + dependencies: + "@jest/environment" "^27.3.1" + "@jest/test-result" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.3.1" + is-generator-fn "^2.0.0" + jest-each "^27.3.1" + jest-matcher-utils "^27.3.1" + jest-message-util "^27.3.1" + jest-runtime "^27.3.1" + jest-snapshot "^27.3.1" + jest-util "^27.3.1" + pretty-format "^27.3.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" -ini@^1.3.4: - version "1.3.8" - resolved "https://registry.npm.taobao.org/ini/download/ini-1.3.8.tgz?cache=0&sync_timestamp=1607907797039&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fini%2Fdownload%2Fini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw= +jest-cli@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz#b576f9d146ba6643ce0a162d782b40152b6b1d16" + integrity sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q== + dependencies: + "@jest/core" "^27.3.1" + "@jest/test-result" "^27.3.1" + "@jest/types" "^27.2.5" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.3.1" + jest-util "^27.3.1" + jest-validate "^27.3.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz#cb3b7f6aaa8c0a7daad4f2b9573899ca7e09bbad" + integrity sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^27.3.1" + "@jest/types" "^27.2.5" + babel-jest "^27.3.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-circus "^27.3.1" + jest-environment-jsdom "^27.3.1" + jest-environment-node "^27.3.1" + jest-get-type "^27.3.1" + jest-jasmine2 "^27.3.1" + jest-regex-util "^27.0.6" + jest-resolve "^27.3.1" + jest-runner "^27.3.1" + jest-util "^27.3.1" + jest-validate "^27.3.1" + micromatch "^4.0.4" + pretty-format "^27.3.1" + +jest-diff@^26.0.0: + version "26.6.2" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.npm.taobao.org/interpret/download/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha1-Zlq4vE2iendKQFhOgS4+D6RbGh4= +jest-diff@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz#d2775fea15411f5f5aeda2a5e02c2f36440f6d55" + integrity sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.0.6" + jest-get-type "^27.3.1" + pretty-format "^27.3.1" -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +jest-docblock@^27.0.6: + version "27.0.6" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" + integrity sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA== + dependencies: + detect-newline "^3.0.0" -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= +jest-each@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz#14c56bb4f18dd18dc6bdd853919b5f16a17761ff" + integrity sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ== dependencies: - binary-extensions "^2.0.0" + "@jest/types" "^27.2.5" + chalk "^4.0.0" + jest-get-type "^27.3.1" + jest-util "^27.3.1" + pretty-format "^27.3.1" + +jest-environment-jsdom@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz#63ac36d68f7a9303494df783494856222b57f73e" + integrity sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg== + dependencies: + "@jest/environment" "^27.3.1" + "@jest/fake-timers" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.3.0" + jest-util "^27.3.1" + jsdom "^16.6.0" + +jest-environment-node@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz#af7d0eed04edafb740311b303f3fe7c8c27014bb" + integrity sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw== + dependencies: + "@jest/environment" "^27.3.1" + "@jest/fake-timers" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + jest-mock "^27.3.0" + jest-util "^27.3.1" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +jest-get-type@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz#a8a2b0a12b50169773099eee60a0e6dd11423eff" + integrity sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg== + +jest-haste-map@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz#7656fbd64bf48bda904e759fc9d93e2c807353ee" + integrity sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg== + dependencies: + "@jest/types" "^27.2.5" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.0.6" + jest-serializer "^27.0.6" + jest-util "^27.3.1" + jest-worker "^27.3.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz#df6d3d07c7dafc344feb43a0072a6f09458d32b0" + integrity sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^27.3.1" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.3.1" + is-generator-fn "^2.0.0" + jest-each "^27.3.1" + jest-matcher-utils "^27.3.1" + jest-message-util "^27.3.1" + jest-runtime "^27.3.1" + jest-snapshot "^27.3.1" + jest-util "^27.3.1" + pretty-format "^27.3.1" + throat "^6.0.1" + +jest-leak-detector@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz#7fb632c2992ef707a1e73286e1e704f9cc1772b2" + integrity sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg== + dependencies: + jest-get-type "^27.3.1" + pretty-format "^27.3.1" + +jest-matcher-utils@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz#257ad61e54a6d4044e080d85dbdc4a08811e9c1c" + integrity sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w== + dependencies: + chalk "^4.0.0" + jest-diff "^27.3.1" + jest-get-type "^27.3.1" + pretty-format "^27.3.1" -is-core-module@^2.2.0: - version "2.2.0" - resolved "https://registry.npm.taobao.org/is-core-module/download/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - integrity sha1-lwN+89UiJNhRY/VZeytj2a/tmBo= +jest-message-util@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz#f7c25688ad3410ab10bcb862bcfe3152345c6436" + integrity sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg== dependencies: - has "^1.0.3" + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.2.5" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.3.1" + slash "^3.0.0" + stack-utils "^2.0.3" -is-extendable@^0.1.0: - version "0.1.1" - resolved "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +jest-mock@^27.3.0: + version "27.3.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz#ddf0ec3cc3e68c8ccd489bef4d1f525571a1b867" + integrity sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw== + dependencies: + "@jest/types" "^27.2.5" + "@types/node" "*" -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= +jest-regex-util@^27.0.6: + version "27.0.6" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" + integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw= +jest-resolve-dependencies@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz#85b99bdbdfa46e2c81c6228fc4c91076f624f6e2" + integrity sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A== dependencies: - is-extglob "^2.1.1" + "@jest/types" "^27.2.5" + jest-regex-util "^27.0.6" + jest-snapshot "^27.3.1" -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= +jest-resolve@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz#0e5542172a1aa0270be6f66a65888647bdd74a3e" + integrity sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw== + dependencies: + "@jest/types" "^27.2.5" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.3.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.3.1" + jest-validate "^27.3.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI= +jest-runner@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz#1d594dcbf3bd8600a7e839e790384559eaf96e3e" + integrity sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww== + dependencies: + "@jest/console" "^27.3.1" + "@jest/environment" "^27.3.1" + "@jest/test-result" "^27.3.1" + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.0.6" + jest-environment-jsdom "^27.3.1" + jest-environment-node "^27.3.1" + jest-haste-map "^27.3.1" + jest-leak-detector "^27.3.1" + jest-message-util "^27.3.1" + jest-resolve "^27.3.1" + jest-runtime "^27.3.1" + jest-util "^27.3.1" + jest-worker "^27.3.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz#80fa32eb85fe5af575865ddf379874777ee993d7" + integrity sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg== + dependencies: + "@jest/console" "^27.3.1" + "@jest/environment" "^27.3.1" + "@jest/globals" "^27.3.1" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.3.1" + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.3.1" + jest-message-util "^27.3.1" + jest-mock "^27.3.0" + jest-regex-util "^27.0.6" + jest-resolve "^27.3.1" + jest-snapshot "^27.3.1" + jest-util "^27.3.1" + jest-validate "^27.3.1" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^16.2.0" + +jest-serializer@^27.0.6: + version "27.0.6" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1" + integrity sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz#1da5c0712a252d70917d46c037054f5918c49ee4" + integrity sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/parser" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.3.1" + graceful-fs "^4.2.4" + jest-diff "^27.3.1" + jest-get-type "^27.3.1" + jest-haste-map "^27.3.1" + jest-matcher-utils "^27.3.1" + jest-message-util "^27.3.1" + jest-resolve "^27.3.1" + jest-util "^27.3.1" + natural-compare "^1.4.0" + pretty-format "^27.3.1" + semver "^7.3.2" + +jest-util@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz#a58cdc7b6c8a560caac9ed6bdfc4e4ff23f80429" + integrity sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw== + dependencies: + "@jest/types" "^27.2.5" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= +jest-validate@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz#3a395d61a19cd13ae9054af8cdaf299116ef8a24" + integrity sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q== + dependencies: + "@jest/types" "^27.2.5" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.3.1" + leven "^3.1.0" + pretty-format "^27.3.1" + +jest-watcher@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz#ba5e0bc6aa843612b54ddb7f009d1cbff7e05f3e" + integrity sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA== + dependencies: + "@jest/test-result" "^27.3.1" + "@jest/types" "^27.2.5" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.3.1" + string-length "^4.0.1" -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.npm.taobao.org/is-text-path/download/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= +jest-worker@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz#0def7feae5b8042be38479799aeb7b5facac24b2" + integrity sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g== dependencies: - text-extensions "^1.0.0" + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.0.4: + version "27.3.1" + resolved "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz#b5bab64e8f56b6f7e275ba1836898b0d9f1e5c8a" + integrity sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng== + dependencies: + "@jest/core" "^27.3.1" + import-local "^3.0.2" + jest-cli "^27.3.1" + +js-stringify@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" + integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1586796305651&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk= + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.11.0: +js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc= + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q= + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.npm.taobao.org/json-parse-even-better-errors/download/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0= + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json5@^1.0.1: version "1.0.1" - resolved "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4= + resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== dependencies: minimist "^1.2.0" json5@^2.1.2, json5@^2.1.3: version "2.2.0" - resolved "https://registry.npm.taobao.org/json5/download/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha1-Lf7+cgxrpSXZ69kJlQ8FFTFsiaM= + resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" +jsonc-parser@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" + integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== + +jsonc-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" + integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== + jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.npm.taobao.org/jsonfile/download/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4= + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: universalify "^2.0.0" optionalDependencies: graceful-fs "^4.1.6" -jsonparse@^1.2.0: +jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" - resolved "https://registry.npm.taobao.org/jsonparse/download/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jstransformer@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" + integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= + dependencies: + is-promise "^2.0.0" + promise "^7.0.1" + kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" - resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0= + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +known-css-properties@^0.21.0: + version "0.21.0" + resolved "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d" + integrity sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw== + +kolorist@^1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/kolorist/-/kolorist-1.5.0.tgz#a06f7dd11d1b5fdb743d79c8acd4e1ecbcbd89b3" + integrity sha512-pPobydIHK884YBtkS/tWSZXpSAEpcMbilyun3KL37ot935qL2HNKm/tI45i/Rd+MxdIWEhm7/LmUQzWZYK+Qhg== + +lerna@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" + integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== + dependencies: + "@lerna/add" "4.0.0" + "@lerna/bootstrap" "4.0.0" + "@lerna/changed" "4.0.0" + "@lerna/clean" "4.0.0" + "@lerna/cli" "4.0.0" + "@lerna/create" "4.0.0" + "@lerna/diff" "4.0.0" + "@lerna/exec" "4.0.0" + "@lerna/import" "4.0.0" + "@lerna/info" "4.0.0" + "@lerna/init" "4.0.0" + "@lerna/link" "4.0.0" + "@lerna/list" "4.0.0" + "@lerna/publish" "4.0.0" + "@lerna/run" "4.0.0" + "@lerna/version" "4.0.0" + import-local "^3.0.2" + npmlog "^4.1.2" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libnpmaccess@^4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" + integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== + dependencies: + aproba "^2.0.0" + minipass "^3.1.1" + npm-package-arg "^8.1.2" + npm-registry-fetch "^11.0.0" + +libnpmpublish@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" + integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== + dependencies: + normalize-package-data "^3.0.2" + npm-package-arg "^8.1.2" + npm-registry-fetch "^11.0.0" + semver "^7.1.3" + ssri "^8.0.1" lines-and-columns@^1.1.6: version "1.1.6" - resolved "https://registry.npm.taobao.org/lines-and-columns/download/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= linkify-it@^3.0.1: - version "3.0.2" - resolved "https://registry.npm.taobao.org/linkify-it/download/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8" - integrity sha1-9V7ri8HTrnVASeEkqzu1bZd5f7g= + version "3.0.3" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== dependencies: uc.micro "^1.0.1" -loader-utils@^1.1.0: - version "1.4.0" - resolved "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha1-xXm140yzSxp07cbB+za/o3HVphM= +lint-staged@^11.0.0: + version "11.2.6" + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-11.2.6.tgz#f477b1af0294db054e5937f171679df63baa4c43" + integrity sha512-Vti55pUnpvPE0J9936lKl0ngVeTdSZpEdTNhASbkaWX7J5R9OEifo1INBGQuGW4zmy6OG+TcWPJ3m5yuy5Q8Tg== + dependencies: + cli-truncate "2.1.0" + colorette "^1.4.0" + commander "^8.2.0" + cosmiconfig "^7.0.1" + debug "^4.3.2" + enquirer "^2.3.6" + execa "^5.1.1" + listr2 "^3.12.2" + micromatch "^4.0.4" + normalize-path "^3.0.0" + please-upgrade-node "^3.2.0" + string-argv "0.3.1" + stringify-object "3.3.0" + supports-color "8.1.1" + +listr2@^3.12.2: + version "3.13.3" + resolved "https://registry.npmjs.org/listr2/-/listr2-3.13.3.tgz#d8f6095c9371b382c9b1c2bc33c5941d8e177f11" + integrity sha512-VqAgN+XVfyaEjSaFewGPcDs5/3hBbWVaX1VgWv2f52MF7US45JuARlArULctiB44IIcEk3JF7GtoFCLqEdeuPA== + dependencies: + cli-truncate "^2.1.0" + clone "^2.1.2" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rxjs "^7.4.0" + through "^2.3.8" + wrap-ansi "^7.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +load-json-file@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" + integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== + dependencies: + graceful-fs "^4.1.15" + parse-json "^5.0.0" + strip-bom "^4.0.0" + type-fest "^0.6.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha1-Gvujlq/WdqbUJQTQpno6frn2KqA= + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.npm.taobao.org/locate-path/download/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha1-VTIeswn+u8WcSAHZMackUqaB0oY= + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" -lodash-es@^4.17.20: +lodash-es@^4.17.20, lodash-es@^4.17.21: version "4.17.21" - resolved "https://registry.npm.taobao.org/lodash-es/download/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4= + resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash@^4.17.15, lodash@^4.17.19: +lodash.ismatch@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" + integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" - resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1613835817439&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw= + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz?cache=0&sync_timestamp=1594429283037&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA= +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-symbols@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-5.0.0.tgz#7720d3c6a56c365e1f658916069ba18d941092ca" + integrity sha512-zBsSKauX7sM0kcqrf8VpMRPqcWzU6a/Wi7iEl0QlVSCiIZ4CctaLdfVdiZUn6q2/nenyt392qJqpw9FhNAwqxQ== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^1.0.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== dependencies: - yallist "^3.0.2" + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +longest-streak@^2.0.0: + version "2.0.4" + resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" + integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594429283037&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ= + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" magic-string@^0.25.7: version "0.25.7" - resolved "https://registry.npm.taobao.org/magic-string/download/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE= + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: sourcemap-codec "^1.4.4" +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-fetch-happen@^8.0.9: + version "8.0.14" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" + integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.0.5" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + promise-retry "^2.0.1" + socks-proxy-agent "^5.0.0" + ssri "^8.0.0" + +make-fetch-happen@^9.0.1: + version "9.1.0" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.2.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.2" + promise-retry "^2.0.1" + socks-proxy-agent "^6.0.0" + ssri "^8.0.0" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + map-obj@^1.0.0: version "1.0.1" - resolved "https://registry.npm.taobao.org/map-obj/download/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.npm.taobao.org/map-obj/download/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha1-5Oo5nbyXmuc1yDyGPdMb3zZCd7c= + version "4.3.0" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +markdown-it-anchor@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-7.1.0.tgz#30fb21497bf59e83ff4d1ddc052d821962e2489e" + integrity sha512-loQggrwsIkkP7TOrESvmYkV2ikbQNNKhHcWyqC7/C2CmfHl1tkUizJJU8C5aGgg7J6oXVQJx17gk7i47tNn/lQ== -markdown-it@^12.0.4: - version "12.0.4" - resolved "https://registry.npm.taobao.org/markdown-it/download/markdown-it-12.0.4.tgz?cache=0&sync_timestamp=1610612279176&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmarkdown-it%2Fdownload%2Fmarkdown-it-12.0.4.tgz#eec8247d296327eac3ba9746bdeec9cfcc751e33" - integrity sha1-7sgkfSljJ+rDupdGve7Jz8x1HjM= +markdown-it-container@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b" + integrity sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw== + +markdown-it-emoji@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-2.0.0.tgz#3164ad4c009efd946e98274f7562ad611089a231" + integrity sha512-39j7/9vP/CPCKbEI44oV8yoPJTpvfeReTn/COgRhSpNrjWF3PfP/JUxxB0hxV6ynOY8KH8Y8aX9NMDdo6z+6YQ== + +markdown-it-table-of-contents@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.5.2.tgz#2f941d386c277887910f2c7a8a16f5a17acb829c" + integrity sha512-6o+rxSwzXmXCUn1n8QGTSpgbcnHBG6lUU8x7A5Cssuq5vbfzTfitfGPvQ5PZkp+gP1NGS/DR2rkYqJPn0rbZ1A== + +markdown-it@^12.0.4, markdown-it@^12.0.6: + version "12.2.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-12.2.0.tgz#091f720fd5db206f80de7a8d1f1a7035fd0d38db" + integrity sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg== dependencies: argparse "^2.0.1" entities "~2.1.0" @@ -1655,15 +7110,60 @@ markdown-it@^12.0.4: mdurl "^1.0.1" uc.micro "^1.0.5" +matchit@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz#c4ccf17d9c824cc1301edbcffde9b75a61d10a7c" + integrity sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA== + dependencies: + "@arr/every" "^1.0.0" + +mathml-tag-names@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" + integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== + +mdast-util-from-markdown@^0.8.0: + version "0.8.5" + resolved "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" + integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-string "^2.0.0" + micromark "~2.11.0" + parse-entities "^2.0.0" + unist-util-stringify-position "^2.0.0" + +mdast-util-to-markdown@^0.6.0: + version "0.6.5" + resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" + integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== + dependencies: + "@types/unist" "^2.0.0" + longest-streak "^2.0.0" + mdast-util-to-string "^2.0.0" + parse-entities "^2.0.0" + repeat-string "^1.0.0" + zwitch "^1.0.0" + +mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + mdurl@^1.0.1: version "1.0.1" - resolved "https://registry.npm.taobao.org/mdurl/download/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= meow@^8.0.0: version "8.1.2" - resolved "https://registry.npm.taobao.org/meow/download/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha1-vL5FvaDuFynTUMA8/8g5WjbE6Jc= + resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" + integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== dependencies: "@types/minimist" "^1.2.0" camelcase-keys "^6.2.2" @@ -1677,42 +7177,88 @@ meow@^8.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha1-L93n5gIJOfcJBqaPLXrmheTIxkY= +meow@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" + integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== dependencies: - source-map "^0.6.1" + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize "^1.2.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.18.0" + yargs-parser "^20.2.3" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.3.0: version "1.4.1" - resolved "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4= + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromark@~2.11.0: + version "2.11.4" + resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" + integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== + dependencies: + debug "^4.0.0" + parse-entities "^2.0.0" -micromatch@^4.0.2: +micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" - resolved "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.4.tgz?cache=0&sync_timestamp=1618054787196&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k= + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" picomatch "^2.2.3" +mime-db@1.50.0, "mime-db@>= 1.43.0 < 2": + version "1.50.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.33" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== + dependencies: + mime-db "1.50.0" + +mime@^2.3.1: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + min-indent@^1.0.0: version "1.0.1" - resolved "https://registry.npm.taobao.org/min-indent/download/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha1-pj9oFnOzBXH76LwlaGrnRu76mGk= + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist-options@4.1.0: version "4.1.0" - resolved "https://registry.npm.taobao.org/minimist-options/download/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha1-wGVXE8U6ii69d/+iR9NCxA8BBhk= + resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== dependencies: arrify "^1.0.1" is-plain-obj "^1.1.0" @@ -1720,728 +7266,3154 @@ minimist-options@4.1.0: minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" - resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: + version "1.4.1" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-json-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" + integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== + dependencies: + jsonparse "^1.3.1" + minipass "^3.0.0" + +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: + version "3.1.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== + dependencies: + yallist "^4.0.0" + +minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +minizlib@^2.0.0, minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mitt@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd" + integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ== + +mkdirp-infer-owner@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" + integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== + dependencies: + chownr "^2.0.0" + infer-owner "^1.0.4" + mkdirp "^1.0.3" + +mkdirp@^0.5.1, mkdirp@^0.5.5: + version "0.5.5" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +modify-values@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" + integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@2.1.2: version "2.1.2" - resolved "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multimatch@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" + integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + +mute-stream@0.0.8, mute-stream@~0.0.4: + version "0.0.8" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== mz@^2.4.0: version "2.7.0" - resolved "https://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI= + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== dependencies: any-promise "^1.0.0" object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@^3.1.22: - version "3.1.22" - resolved "https://registry.npm.taobao.org/nanoid/download/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" - integrity sha1-s1+Pt9FRmQqK69WqUBXAPPcm+EQ= +nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2, negotiator@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-fetch@^2.6.1: + version "2.6.6" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + dependencies: + whatwg-url "^5.0.0" + +node-gyp@^5.0.2: + version "5.1.1" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" + integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.2" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.1.2" + request "^2.88.0" + rimraf "^2.6.3" + semver "^5.7.1" + tar "^4.4.12" + which "^1.3.1" + +node-gyp@^7.1.0: + version "7.1.2" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" -node-releases@^1.1.71: - version "1.1.71" - resolved "https://registry.npm.taobao.org/node-releases/download/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" - integrity sha1-yxM0sXmJaxyJ7P3UtyX7e738fbs= +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" -normalize-package-data@^2.5.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" - resolved "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&sync_timestamp=1616087339475&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg= + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" resolve "^1.10.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0: - version "3.0.2" - resolved "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-3.0.2.tgz?cache=0&sync_timestamp=1616087339475&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" - integrity sha1-yuXEEK4kNPmmwbqmXVvDuTZshpk= +normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: + version "3.0.3" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" - resolve "^1.20.0" + is-core-module "^2.5.0" semver "^7.3.4" validate-npm-package-license "^3.0.1" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-selector@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" + integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= + +normalize-url@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +npm-bundled@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-install-checks@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== + dependencies: + semver "^7.1.1" + +npm-lifecycle@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" + integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== + dependencies: + byline "^5.0.0" + graceful-fs "^4.1.15" + node-gyp "^5.0.2" + resolve-from "^4.0.0" + slide "^1.1.6" + uid-number "0.0.6" + umask "^1.1.0" + which "^1.3.1" + +npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: + version "8.1.5" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== + dependencies: + hosted-git-info "^4.0.1" + semver "^7.3.4" + validate-npm-package-name "^3.0.0" + +npm-packlist@^2.1.4: + version "2.2.2" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" + integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== + dependencies: + glob "^7.1.6" + ignore-walk "^3.0.3" + npm-bundled "^1.1.1" + npm-normalize-package-bin "^1.0.1" + +npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" + integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== + dependencies: + npm-install-checks "^4.0.0" + npm-normalize-package-bin "^1.0.1" + npm-package-arg "^8.1.2" + semver "^7.3.4" + +npm-registry-fetch@^11.0.0: + version "11.0.0" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== + dependencies: + make-fetch-happen "^9.0.1" + minipass "^3.1.3" + minipass-fetch "^1.3.0" + minipass-json-stream "^1.0.1" + minizlib "^2.0.0" + npm-package-arg "^8.0.0" + +npm-registry-fetch@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" + integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== + dependencies: + "@npmcli/ci-detect" "^1.0.0" + lru-cache "^6.0.0" + make-fetch-happen "^8.0.9" + minipass "^3.1.3" + minipass-fetch "^1.3.0" + minipass-json-stream "^1.0.1" + minizlib "^2.0.0" + npm-package-arg "^8.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== -object-assign@^4.0.1: +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" - resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -once@^1.3.0: +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3: + version "2.1.3" + resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.4.0: version "1.4.0" - resolved "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + opencollective-postinstall@^2.0.2: version "2.0.3" - resolved "https://registry.npm.taobao.org/opencollective-postinstall/download/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha1-eg//l49tv6TQBiOPusmO1BmMMlk= + resolved "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ora@*, ora@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ora/-/ora-6.0.1.tgz#68caa9fd6c485a40d6f46c50a3940fa3df99c7f3" + integrity sha512-TDdKkKHdWE6jo/6pIa5U5AWcSVfpNRFJ8sdRJpioGNVPLAzZzHs/N+QhUfF7ZbyoC+rnDuNTKzeDJUbAza9g4g== + dependencies: + bl "^5.0.0" + chalk "^4.1.2" + cli-cursor "^4.0.0" + cli-spinners "^2.6.0" + is-interactive "^2.0.0" + is-unicode-supported "^1.1.0" + log-symbols "^5.0.0" + strip-ansi "^7.0.1" + wcwidth "^1.0.1" + +ora@^5.4.0, ora@^5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.npm.taobao.org/p-limit/download/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE= + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.npm.taobao.org/p-limit/download/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs= + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha1-o0KLtwiLOmApL2aRkni3wpetTwc= + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.npm.taobao.org/p-locate/download/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ= + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" +p-map-series@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" + integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-pipe@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" + integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== + +p-queue@^6.6.2: + version "6.6.2" + resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== + dependencies: + eventemitter3 "^4.0.4" + p-timeout "^3.2.0" + +p-reduce@^2.0.0, p-reduce@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" + integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== + +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-try@^2.0.0: version "2.2.0" - resolved "https://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha1-yyhoVA4xPWHeWPr741zpAE1VQOY= + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +p-waterfall@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" + integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== + dependencies: + p-reduce "^2.0.0" + +pacote@^11.2.6: + version "11.3.5" + resolved "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== + dependencies: + "@npmcli/git" "^2.1.0" + "@npmcli/installed-package-contents" "^1.0.6" + "@npmcli/promise-spawn" "^1.2.0" + "@npmcli/run-script" "^1.8.2" + cacache "^15.0.5" + chownr "^2.0.0" + fs-minipass "^2.1.0" + infer-owner "^1.0.4" + minipass "^3.1.3" + mkdirp "^1.0.3" + npm-package-arg "^8.0.1" + npm-packlist "^2.1.4" + npm-pick-manifest "^6.0.0" + npm-registry-fetch "^11.0.0" + promise-retry "^2.0.1" + read-package-json-fast "^2.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.1.0" parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI= + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-json@^5.0.0: version "5.2.0" - resolved "https://registry.npm.taobao.org/parse-json/download/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80= + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-path@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" + integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== + dependencies: + is-ssh "^1.3.0" + protocols "^1.4.0" + qs "^6.9.4" + query-string "^6.13.8" + +parse-url@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" + integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== + dependencies: + is-ssh "^1.3.0" + normalize-url "^6.1.0" + parse-path "^4.0.0" + protocols "^1.4.0" + parse5-htmlparser2-tree-adapter@^6.0.0: version "6.0.1" - resolved "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha1-LN+a2CMyEUA3DU2/XT6Sx8jdxuY= + resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== dependencies: parse5 "^6.0.1" +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parse5@^5.1.1: version "5.1.1" - resolved "https://registry.npm.taobao.org/parse5/download/parse5-5.1.1.tgz?cache=0&sync_timestamp=1595849256977&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse5%2Fdownload%2Fparse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg= + resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.npm.taobao.org/parse5/download/parse5-6.0.1.tgz?cache=0&sync_timestamp=1595849256977&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse5%2Fdownload%2Fparse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha1-4aHAhcVps9wIMhGE8Zo5zCf3wws= +patch-vue-directive-ssr@^0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/patch-vue-directive-ssr/-/patch-vue-directive-ssr-0.0.1.tgz#2eac731f59cdb766d4d613bc24e522ded6ff1bb8" + integrity sha512-n84llktHah+EXUGo+RvmTJcAQJQVW0kHHHiJ34ZSLijzhHi32zCMjCc5VAFv4jmdC91bpaYGPk0cDW1D8hQ3GQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM= + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha1-1i27VnlAXXLEc37FhgDp3c8G0kw= + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" path-type@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/path-type/download/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs= + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pify@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" + +polka@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz#588bee0c5806dbc6c64958de3a1251860e9f2e26" + integrity sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw== + dependencies: + "@polka/url" "^0.5.0" + trouter "^2.0.1" + +postcss-html@^0.36.0: + version "0.36.0" + resolved "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" + integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw== + dependencies: + htmlparser2 "^3.10.0" + +postcss-less@^3.1.4: + version "3.1.4" + resolved "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" + integrity sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA== + dependencies: + postcss "^7.0.14" + +postcss-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= + +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" + integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= + +postcss-safe-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" + integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== + dependencies: + postcss "^7.0.26" + +postcss-sass@^0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3" + integrity sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg== + dependencies: + gonzales-pe "^4.3.0" + postcss "^7.0.21" + +postcss-scss@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" + integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA== + dependencies: + postcss "^7.0.6" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.5: + version "6.0.6" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-syntax@^0.36.2: + version "0.36.2" + resolved "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" + integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w== + +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.1.10, postcss@^8.3.8: + version "8.3.11" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" + integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^0.6.2" + +preact@^10.0.0: + version "10.5.15" + resolved "https://registry.npmjs.org/preact/-/preact-10.5.15.tgz#6df94d8afecf3f9e10a742fd8c362ddab464225f" + integrity sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prettier@^2.2.1: + version "2.4.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" + integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== + +pretty-format@^26.0.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +pretty-format@^27.3.1: + version "27.3.1" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz#7e9486365ccdd4a502061fa761d3ab9ca1b78df5" + integrity sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA== + dependencies: + "@jest/types" "^27.2.5" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +prismjs@^1.23.0: + version "1.25.0" + resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.2.3" - resolved "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" - integrity sha1-RlVH81nMwgbTxI5Goby4m/fuYZ0= +promise@^7.0.1: + version "7.3.1" + resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-5.0.0.tgz?cache=0&sync_timestamp=1602859073068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpkg-dir%2Fdownload%2Fpkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha1-oC1q6+a6EzqSj3Suwguv3+a452A= +prompts@^2.0.1, prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: - find-up "^5.0.0" + kleur "^3.0.3" + sisteransi "^1.0.5" -please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.npm.taobao.org/please-upgrade-node/download/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha1-rt3T+ZTJM+StmLmdmlVu+g4v6UI= +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= dependencies: - semver-compare "^1.0.0" + read "1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +protocols@^1.1.0, protocols@^1.4.0: + version "1.4.8" + resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" + integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== + +psl@^1.1.28, psl@^1.1.33: + version "1.8.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -postcss-modules-extract-imports@^3.0.0: +pug-attrs@^3.0.0: version "3.0.0" - resolved "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-3.0.0.tgz?cache=0&sync_timestamp=1602588284500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-extract-imports%2Fdownload%2Fpostcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha1-zaHwR8CugMl9vijD52pDuIAldB0= + resolved "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" + integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA== + dependencies: + constantinople "^4.0.1" + js-stringify "^1.0.2" + pug-runtime "^3.0.0" + +pug-code-gen@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce" + integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg== + dependencies: + constantinople "^4.0.1" + doctypes "^1.1.0" + js-stringify "^1.0.2" + pug-attrs "^3.0.0" + pug-error "^2.0.0" + pug-runtime "^3.0.0" + void-elements "^3.1.0" + with "^7.0.0" + +pug-error@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" + integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== -postcss-modules-local-by-default@^4.0.0: +pug-filters@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha1-67tU+uFZjuz99pGgKz/zs5ClpRw= + resolved "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" + integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A== dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" + constantinople "^4.0.1" + jstransformer "1.0.0" + pug-error "^2.0.0" + pug-walk "^2.0.0" + resolve "^1.15.1" -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-3.0.0.tgz?cache=0&sync_timestamp=1602593265225&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-scope%2Fdownload%2Fpostcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha1-nvMVFFbTu/oSDKRImN/Kby+gHwY= +pug-lexer@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" + integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w== dependencies: - postcss-selector-parser "^6.0.4" + character-parser "^2.2.0" + is-expression "^4.0.0" + pug-error "^2.0.0" -postcss-modules-values@^4.0.0: +pug-linker@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-4.0.0.tgz?cache=0&sync_timestamp=1602586268180&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-values%2Fdownload%2Fpostcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha1-18Xn5ow7s8myfL9Iyguz/7RgLJw= + resolved "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" + integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw== dependencies: - icss-utils "^5.0.0" + pug-error "^2.0.0" + pug-walk "^2.0.0" -postcss-modules@^4.0.0: - version "4.0.0" - resolved "https://registry.npm.taobao.org/postcss-modules/download/postcss-modules-4.0.0.tgz#2bc7f276ab88f3f1b0fadf6cbd7772d43b5f3b9b" - integrity sha1-K8fydquI8/Gw+t9svXdy1DtfO5s= +pug-load@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" + integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ== dependencies: - generic-names "^2.0.1" - icss-replace-symbols "^1.1.0" - lodash.camelcase "^4.3.0" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - string-hash "^1.1.1" + object-assign "^4.1.1" + pug-walk "^2.0.0" -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: - version "6.0.4" - resolved "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-6.0.4.tgz?cache=0&sync_timestamp=1601045363609&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" - integrity sha1-VgdaE4CgRgTDiwY+p3Z6Epr1wrM= +pug-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" + integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw== dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - util-deprecate "^1.0.2" + pug-error "^2.0.0" + token-stream "1.0.0" -postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha1-RD9qIM7WSBor2k+oUypuVdeJoss= +pug-runtime@^3.0.0, pug-runtime@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" + integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg== -postcss@^8.1.10, postcss@^8.2.1: - version "8.2.10" - resolved "https://registry.npm.taobao.org/postcss/download/postcss-8.2.10.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss%2Fdownload%2Fpostcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b" - integrity sha1-ynoEKqiv9JSzNND/Pp53B59vcCs= +pug-strip-comments@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" + integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ== dependencies: - colorette "^1.2.2" - nanoid "^3.1.22" - source-map "^0.6.1" + pug-error "^2.0.0" + +pug-walk@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" + integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== + +pug@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" + integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw== + dependencies: + pug-code-gen "^3.0.2" + pug-filters "^4.0.0" + pug-lexer "^5.0.1" + pug-linker "^4.0.0" + pug-load "^3.0.0" + pug-parser "^6.0.0" + pug-runtime "^3.0.1" + pug-strip-comments "^2.0.0" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== q@^1.5.1: version "1.5.1" - resolved "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@^6.9.4: + version "6.10.1" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^6.13.8: + version "6.14.1" + resolved "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" + integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== + dependencies: + decode-uri-component "^0.2.0" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.npm.taobao.org/queue-microtask/download/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha1-SSkii7xyTfrEPg77BYyve2z7YkM= + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== quick-lru@^4.0.1: version "4.0.1" - resolved "https://registry.npm.taobao.org/quick-lru/download/quick-lru-4.0.1.tgz?cache=0&sync_timestamp=1612316527120&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquick-lru%2Fdownload%2Fquick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha1-W4h48ROlgheEjGSCAmxz4bpXcn8= + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== quick-lru@^5.1.1: version "5.1.1" - resolved "https://registry.npm.taobao.org/quick-lru/download/quick-lru-5.1.1.tgz?cache=0&sync_timestamp=1612316527120&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquick-lru%2Fdownload%2Fquick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha1-NmST5rPkKjpoheLpnRj4D7eoyTI= + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +read-cmd-shim@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" + integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== + +read-package-json-fast@^2.0.1: + version "2.0.3" + resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== + dependencies: + json-parse-even-better-errors "^2.3.0" + npm-normalize-package-bin "^1.0.1" + +read-package-json@^2.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" + integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== + dependencies: + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^2.0.0" + npm-normalize-package-bin "^1.0.0" + +read-package-json@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" + integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== + dependencies: + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^3.0.0" + npm-normalize-package-bin "^1.0.0" + +read-package-json@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-4.1.1.tgz#153be72fce801578c1c86b8ef2b21188df1b9eea" + integrity sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw== + dependencies: + glob "^7.1.1" + json-parse-even-better-errors "^2.3.0" + normalize-package-data "^3.0.0" + npm-normalize-package-bin "^1.0.0" + +read-package-tree@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" + integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== + dependencies: + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + util-promisify "^2.1.0" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" read-pkg-up@^7.0.1: version "7.0.1" - resolved "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-7.0.1.tgz?cache=0&sync_timestamp=1616916344510&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg-up%2Fdownload%2Fread-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha1-86YTV1hFlzOuK5VjgFbhhU5+9Qc= + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" read-pkg "^5.2.0" type-fest "^0.8.1" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + read-pkg@^5.2.0: version "5.2.0" - resolved "https://registry.npm.taobao.org/read-pkg/download/read-pkg-5.2.0.tgz?cache=0&sync_timestamp=1616915145764&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg%2Fdownload%2Fread-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w= + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" normalize-package-data "^2.5.0" parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@3, readable-stream@^3.0.0: +read@1, read@~1.0.1: + version "1.0.7" + resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= + dependencies: + mute-stream "~0.0.4" + +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" - resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.npm.taobao.org/readdirp/download/readdirp-3.5.0.tgz?cache=0&sync_timestamp=1615717487560&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freaddirp%2Fdownload%2Freaddirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - integrity sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4= +readable-stream@^2.0.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdir-scoped-modules@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" rechoir@^0.6.2: version "0.6.2" - resolved "https://registry.npm.taobao.org/rechoir/download/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" redent@^3.0.0: version "3.0.0" - resolved "https://registry.npm.taobao.org/redent/download/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha1-5Ve3mYMWu1PJ8fVvpiY1LGljBZ8= + resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== dependencies: indent-string "^4.0.0" strip-indent "^3.0.0" +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha1-ysLazIoepnX+qrrriugziYrkb1U= + version "0.13.9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== + dependencies: + jsesc "~0.5.0" + +remark-parse@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" + integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== + dependencies: + mdast-util-from-markdown "^0.8.0" + +remark-stringify@^9.0.0: + version "9.0.1" + resolved "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" + integrity sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg== + dependencies: + mdast-util-to-markdown "^0.6.0" + +remark@^13.0.0: + version "13.0.0" + resolved "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" + integrity sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA== + dependencies: + remark-parse "^9.0.0" + remark-stringify "^9.0.0" + unified "^9.1.0" + +repeat-string@^1.0.0: + version "1.6.1" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request-light@^0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/request-light/-/request-light-0.5.4.tgz#497a98c6d8ae49536417a5e2d7f383b934f3e38c" + integrity sha512-t3566CMweOFlUk7Y1DJMu5OrtpoZEb6aSTsLQVT3wtrIEJ5NhcY9G/Oqxvjllzl4a15zXfFlcr9q40LbLVQJqw== + +request@^2.88.0, request@^2.88.2: + version "2.88.2" + resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" - resolved "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs= + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" resolve-from@5.0.0, resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha1-w1IlhD3493bfIcV1V7wIfp39/Gk= + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY= + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-global@1.0.0, resolve-global@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/resolve-global/download/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha1-oqed9K8so/Sb93753azTItrRklU= + resolved "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" + integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== dependencies: global-dirs "^0.1.1" -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.19.0, resolve@^1.20.0: +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.20.0: version "1.20.0" - resolved "https://registry.npm.taobao.org/resolve/download/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU= + resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: is-core-module "^2.2.0" path-parse "^1.0.6" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + reusify@^1.0.4: version "1.0.4" - resolved "https://registry.npm.taobao.org/reusify/download/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY= + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rollup@^2.38.5: - version "2.45.1" - resolved "https://registry.npm.taobao.org/rollup/download/rollup-2.45.1.tgz#eae2b94dc2088b4e0a3b7197a5a1ee0bdd589d5c" - integrity sha1-6uK5TcIIi04KO3GXpaHuC91YnVw= +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^2.57.0: + version "2.59.0" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.59.0.tgz#108c61b0fa0a37ebc8d1f164f281622056f0db59" + integrity sha512-l7s90JQhCQ6JyZjKgo7Lq1dKh2RxatOM+Jr6a9F7WbS9WgKbocyUSeLmZl8evAse7y96Ae98L2k1cBOwWD8nHw== optionalDependencies: - fsevents "~2.3.1" + fsevents "~2.3.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.npm.taobao.org/run-parallel/download/run-parallel-1.2.0.tgz?cache=0&sync_timestamp=1612926584650&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frun-parallel%2Fdownload%2Frun-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4= + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" -safe-buffer@~5.1.1: +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +rxjs@^7.2.0, rxjs@^7.4.0: + version "7.4.0" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w== + dependencies: + tslib "~2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sass@^1.32.2: - version "1.32.8" - resolved "https://registry.npm.taobao.org/sass/download/sass-1.32.8.tgz?cache=0&sync_timestamp=1613700358988&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass%2Fdownload%2Fsass-1.32.8.tgz#f16a9abd8dc530add8834e506878a2808c037bdc" - integrity sha1-8WqavY3FMK3Yg05QaHiigIwDe9w= + version "1.43.4" + resolved "https://registry.npmjs.org/sass/-/sass-1.43.4.tgz#68c7d6a1b004bef49af0d9caf750e9b252105d1f" + integrity sha512-/ptG7KE9lxpGSYiXn7Ar+lKOv37xfWsZRtFYal2QHNigyVQDx685VFT/h7ejVr+R8w7H4tmUgtulsKl5YpveOg== dependencies: - chokidar ">=2.0.0 <4.0.0" + chokidar ">=3.0.0 <4.0.0" + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" section-matter@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/section-matter/download/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" - integrity sha1-6QQZU1BngOwB1Z8pKhnHuFC4QWc= + resolved "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== dependencies: extend-shallow "^2.0.1" kind-of "^6.0.0" semver-compare@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/semver-compare/download/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= semver-regex@^3.1.2: - version "3.1.2" - resolved "https://registry.npm.taobao.org/semver-regex/download/semver-regex-3.1.2.tgz#34b4c0d361eef262e07199dbef316d0f2ab11807" - integrity sha1-NLTA02Hu8mLgcZnb7zFtDyqxGAc= + version "3.1.3" + resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" + integrity sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ== -"semver@2 || 3 || 4 || 5": +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: version "5.7.1" - resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1616463863424&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== semver@7.3.2: version "7.3.2" - resolved "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz?cache=0&sync_timestamp=1616463863424&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg= + resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^6.3.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" - resolved "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1616463863424&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0= + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.4: +semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" - resolved "https://registry.npm.taobao.org/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1616463863424&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc= + resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -set-blocking@^2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + shelljs@^0.8.4: version "0.8.4" - resolved "https://registry.npm.taobao.org/shelljs/download/shelljs-0.8.4.tgz?cache=0&sync_timestamp=1587787249542&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshelljs%2Fdownload%2Fshelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - integrity sha1-3naE/ut2f4cWsyYHiooAh1iQ48I= + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.5" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== + +sirv@^1.0.12: + version "1.0.18" + resolved "https://registry.npmjs.org/sirv/-/sirv-1.0.18.tgz#105fab52fb656ce8a2bebbf36b11052005952899" + integrity sha512-f2AOPogZmXgJ9Ma2M22ZEhc1dNtRIzcEkiflMFeVTRq+OViOZMvH1IPMVOwrKaxpSaHioBJiDR0SluRqGa7atA== + dependencies: + "@polka/url" "^1.0.0-next.20" + mime "^2.3.1" + totalist "^1.0.0" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" - resolved "https://registry.npm.taobao.org/slash/download/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ= + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slide@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= + +smart-buffer@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== + dependencies: + agent-base "^6.0.2" + debug "4" + socks "^2.3.3" + +socks-proxy-agent@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" + integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.3.3, socks@^2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.1.0" -source-map@0.6.1, source-map@^0.6.1: +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +sort-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" + integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== + dependencies: + is-plain-obj "^2.0.0" + +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== + +source-map-support@^0.5.6: + version "0.5.20" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.5.0: version "0.5.7" - resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + sourcemap-codec@^1.4.4: version "1.4.8" - resolved "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ= + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== spdx-correct@^3.0.0: version "3.1.1" - resolved "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha1-3s6BrJweZxPl99G28X1Gj6U9iak= + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: version "2.3.0" - resolved "https://registry.npm.taobao.org/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0= + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: version "3.0.1" - resolved "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha1-z3D1BILu/cmOPOCmgz5KU87rpnk= + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.7" - resolved "https://registry.npm.taobao.org/spdx-license-ids/download/spdx-license-ids-3.0.7.tgz?cache=0&sync_timestamp=1606610773474&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdx-license-ids%2Fdownload%2Fspdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" - integrity sha1-6cGKQQ5e1+EkQqVJ+9ivp2cDjWU= + version "3.0.10" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" + integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== + +specificity@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" + integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== split2@^3.0.0: version "3.2.2" - resolved "https://registry.npm.taobao.org/split2/download/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha1-vyzyo32DgxLCSciSBv16F90SNl8= + resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== dependencies: readable-stream "^3.0.0" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -string-hash@^1.1.1: - version "1.1.3" - resolved "https://registry.npm.taobao.org/string-hash/download/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" - integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.npm.taobao.org/string-width/download/string-width-4.2.2.tgz?cache=0&sync_timestamp=1614522149804&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring-width%2Fdownload%2Fstring-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU= +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + +string-argv@0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" string_decoder@^1.1.1: version "1.3.0" - resolved "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI= +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: - ansi-regex "^5.0.0" + safe-buffer "~5.1.0" + +stringify-object@3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strong-log-transformer@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" + integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== + dependencies: + duplexer "^0.1.1" + minimist "^1.2.0" + through "^2.3.4" + +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" + integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= + +stylelint-config-recommended-scss@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-4.3.0.tgz#717dc253b4cab246da654cee208e499c5c797ae4" + integrity sha512-/noGjXlO8pJTr/Z3qGMoaRFK8n1BFfOqmAbX1RjTIcl4Yalr+LUb1zb9iQ7pRx1GsEBXOAm4g2z5/jou/pfMPg== + dependencies: + stylelint-config-recommended "^5.0.0" + +stylelint-config-recommended@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-5.0.0.tgz#fb5653f495a60b4938f2ad3e77712d9e1039ae78" + integrity sha512-c8aubuARSu5A3vEHLBeOSJt1udOdS+1iue7BmJDTSXoCBmfEQmmWX+59vYIj3NQdJBY6a/QRv1ozVFpaB9jaqA== + +stylelint-config-standard@^22.0.0: + version "22.0.0" + resolved "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-22.0.0.tgz#c860be9a13ebbc1b084456fa10527bf13a44addf" + integrity sha512-uQVNi87SHjqTm8+4NIP5NMAyY/arXrBgimaaT7skvRfE9u3JKXRK9KBkbr4pVmeciuCcs64kAdjlxfq6Rur7Hw== + dependencies: + stylelint-config-recommended "^5.0.0" + +stylelint-scss@^3.20.1: + version "3.21.0" + resolved "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.21.0.tgz#9f50898691b16b1c1ca3945837381d98c5b22331" + integrity sha512-CMI2wSHL+XVlNExpauy/+DbUcB/oUZLARDtMIXkpV/5yd8nthzylYd1cdHeDMJVBXeYHldsnebUX6MoV5zPW4A== + dependencies: + lodash "^4.17.15" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +stylelint@^13.13.1: + version "13.13.1" + resolved "https://registry.npmjs.org/stylelint/-/stylelint-13.13.1.tgz#fca9c9f5de7990ab26a00f167b8978f083a18f3c" + integrity sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ== + dependencies: + "@stylelint/postcss-css-in-js" "^0.37.2" + "@stylelint/postcss-markdown" "^0.36.2" + autoprefixer "^9.8.6" + balanced-match "^2.0.0" + chalk "^4.1.1" + cosmiconfig "^7.0.0" + debug "^4.3.1" + execall "^2.0.0" + fast-glob "^3.2.5" + fastest-levenshtein "^1.0.12" + file-entry-cache "^6.0.1" + get-stdin "^8.0.0" + global-modules "^2.0.0" + globby "^11.0.3" + globjoin "^0.1.4" + html-tags "^3.1.0" + ignore "^5.1.8" + import-lazy "^4.0.0" + imurmurhash "^0.1.4" + known-css-properties "^0.21.0" + lodash "^4.17.21" + log-symbols "^4.1.0" + mathml-tag-names "^2.1.3" + meow "^9.0.0" + micromatch "^4.0.4" + normalize-selector "^0.2.0" + postcss "^7.0.35" + postcss-html "^0.36.0" + postcss-less "^3.1.4" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^4.0.2" + postcss-sass "^0.4.4" + postcss-scss "^2.1.1" + postcss-selector-parser "^6.0.5" + postcss-syntax "^0.36.2" + postcss-value-parser "^4.1.0" + resolve-from "^5.0.0" + slash "^3.0.0" + specificity "^0.4.1" + string-width "^4.2.2" + strip-ansi "^6.0.0" + style-search "^0.1.0" + sugarss "^2.0.0" + svg-tags "^1.0.0" + table "^6.6.0" + v8-compile-cache "^2.3.0" + write-file-atomic "^3.0.3" -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npm.taobao.org/strip-bom-string/download/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= +sugarss@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" + integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== + dependencies: + postcss "^7.0.2" -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/strip-indent/download/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha1-wy4c7pQLazQyx3G8LFS8znPNMAE= +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: - min-indent "^1.0.0" + has-flag "^4.0.0" supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1611393963969&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1611393963969&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" + supports-color "^7.0.0" svg-tags@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/svg-tags/download/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= +svgo@^2.3.0: + version "2.8.0" + resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +table@^6.0.9, table@^6.6.0: + version "6.7.3" + resolved "https://registry.npmjs.org/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" + integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tar@^4.4.12: + version "4.4.19" + resolved "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + +tar@^6.0.2, tar@^6.1.0: + version "6.1.11" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +temp-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + +temp-write@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" + integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== + dependencies: + graceful-fs "^4.1.15" + is-stream "^2.0.0" + make-dir "^3.0.0" + temp-dir "^1.0.0" + uuid "^3.3.2" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-extensions@^1.0.0: version "1.9.0" - resolved "https://registry.npm.taobao.org/text-extensions/download/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha1-GFPkX+45yUXOb2w2stZZtaq8KiY= + resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= thenify-all@^1.0.0: version "1.6.0" - resolved "https://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= dependencies: thenify ">= 3.1.0 < 4" "thenify@>= 3.1.0 < 4": version "3.3.1" - resolved "https://registry.npm.taobao.org/thenify/download/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8= + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== dependencies: any-promise "^1.0.0" +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + through2@^4.0.0: version "4.0.2" - resolved "https://registry.npm.taobao.org/through2/download/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha1-p846wqeosLlmyA58SfBITDsjl2Q= + resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== dependencies: readable-stream "3" -"through@>=2.2.7 <3": +through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: version "2.3.8" - resolved "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" +token-stream@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" + integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= + +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + trim-newlines@^3.0.0: - version "3.0.0" - resolved "https://registry.npm.taobao.org/trim-newlines/download/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" - integrity sha1-eXJjBKaomKqDc0JymNVMLuixyzA= + version "3.0.1" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -trim-off-newlines@^1.0.0: - version "1.0.1" - resolved "https://registry.npm.taobao.org/trim-off-newlines/download/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" - integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +trouter@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz#2726a5f8558e090d24c3a393f09eaab1df232df6" + integrity sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ== + dependencies: + matchit "^1.0.0" + +tsconfig-paths@^3.11.0: + version "3.11.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" + integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.18.0: version "0.18.1" - resolved "https://registry.npm.taobao.org/type-fest/download/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha1-20vBUaSiz07r+a3V23VQjbbMhB8= + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" + integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" + integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== type-fest@^0.6.0: version "0.6.0" - resolved "https://registry.npm.taobao.org/type-fest/download/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha1-jSojcNPfiG61yQraHFv2GIrPg4s= + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.npm.taobao.org/type-fest/download/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha1-CeJJ696FHTseSNJ8EFREZn8XuD0= + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -typescript@^4.0.3, typescript@^4.1.3: - version "4.2.4" - resolved "https://registry.npm.taobao.org/typescript/download/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha1-hhC1l0feAo/aiYqK7w4QPxVtCWE= +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@^4.0.3, typescript@^4.3.2, typescript@^4.4.4: + version "4.4.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" - resolved "https://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" - integrity sha1-nEEagCpAmpH8bPdAgbq6NLJEmaw= + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.1.4: + version "3.14.3" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz#c0f25dfea1e8e5323eccf59610be08b6043c15cf" + integrity sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g== + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= + +umask@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= -uniq@^1.0.1: +unbox-primitive@^1.0.1: version "1.0.1" - resolved "https://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +unified@^9.1.0: + version "9.2.2" + resolved "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" + integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unist-util-find-all-after@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz#fdfecd14c5b7aea5e9ef38d5e0d5f774eeb561f6" + integrity sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ== + dependencies: + unist-util-is "^4.0.0" + +unist-util-is@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" + integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== + +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^2.0.0: version "2.0.0" - resolved "https://registry.npm.taobao.org/universalify/download/universalify-2.0.0.tgz?cache=0&sync_timestamp=1603180163852&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +upath@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" + integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" -util-deprecate@^1.0.1, util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -validate-npm-package-license@^3.0.1: +util-promisify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" + integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= + dependencies: + object.getownpropertydescriptors "^2.0.3" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" - resolved "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha1-/JH2uce6FchX9MssXe/uw51PQQo= + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile@^4.0.0: + version "4.2.1" + resolved "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" + integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + vite-plugin-md@^0.6.0: - version "0.6.3" - resolved "https://registry.npm.taobao.org/vite-plugin-md/download/vite-plugin-md-0.6.3.tgz#9a8a4ca244675107144f9e8ea16046e89d08226a" - integrity sha1-mopMokRnUQcUT56OoWBG6J0IImo= + version "0.6.7" + resolved "https://registry.npmjs.org/vite-plugin-md/-/vite-plugin-md-0.6.7.tgz#6318b059a6d968030c908c81f066a8e81ed0c0bc" + integrity sha512-R9i61r1y6gfelJKtHiHkw6NOkucFzGRgy7VL7bqMufiSh1UNyYKZrpiQtagzavpBlJSVk34lfEyfyKpQyeuocQ== dependencies: - gray-matter "^4.0.2" - markdown-it "^12.0.4" + gray-matter "^4.0.3" + markdown-it "^12.0.6" -vite@^2.0.5: - version "2.1.5" - resolved "https://registry.npm.taobao.org/vite/download/vite-2.1.5.tgz#4857da441c62f7982c83cbd5f42a00330f20c9c1" - integrity sha1-SFfaRBxi95gsg8vV9CoAMw8gycE= +vite-svg-loader@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/vite-svg-loader/-/vite-svg-loader-2.2.0.tgz#b5d6ca948b03e45320cb4f96c44bf88f5bef0a2c" + integrity sha512-FP6qCN57coIOwmtah68ofpi4dewGmfzPcoKe76RMnJoz7qBTXxQVm2BlnH0YzGeCbOcjm9NKauJ1I6J9OlUUtg== dependencies: - esbuild "^0.9.3" - postcss "^8.2.1" - resolve "^1.19.0" - rollup "^2.38.5" + "@vue/compiler-sfc" "^3.0.11" + svgo "^2.3.0" + +vite@^2.3.7, vite@^2.4.4: + version "2.6.13" + resolved "https://registry.npmjs.org/vite/-/vite-2.6.13.tgz#16b3ec85a66d5b461ac29a903874d4357f9af432" + integrity sha512-+tGZ1OxozRirTudl4M3N3UTNJOlxdVo/qBl2IlDEy/ZpTFcskp+k5ncNjayR3bRYTCbqSOFz2JWGN1UmuDMScA== + dependencies: + esbuild "^0.13.2" + postcss "^8.3.8" + resolve "^1.20.0" + rollup "^2.57.0" optionalDependencies: - fsevents "~2.3.1" + fsevents "~2.3.2" + +vitepress-theme-demoblock@^1.2.2: + version "1.3.2" + resolved "https://registry.npmjs.org/vitepress-theme-demoblock/-/vitepress-theme-demoblock-1.3.2.tgz#d423818ee38041b33ecdf9738b3ad3cf4775e40b" + integrity sha512-uyzdb28sq2hSNzU4KeITNayWNPYUqvUWcahcqQZVvAoPlSr1tF9vGraRQWEhAFW//MII3tM/mncYLfICJfmISw== + dependencies: + camelcase "^6.2.0" + globby "^11.0.2" + kolorist "^1.5.0" + markdown-it "^12.0.4" + minimist "^1.2.5" + prettier "^2.2.1" + vitepress "^0.16.1" + yaml "^2.0.0-6" + +vitepress@^0.15.6: + version "0.15.6" + resolved "https://registry.npmjs.org/vitepress/-/vitepress-0.15.6.tgz#b3d2487384f60deb5e0be7da1f1896c1db75025e" + integrity sha512-+knoqxT6V3DAAP6ojXmwsbplqjPvf256xFJfAJdzu4WArJSXGoserPIhtLK7fOFKPQrcb8S6H9RpIshY31/hLg== + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@docsearch/js" "^1.0.0-alpha.28" + "@types/markdown-it" "^12.0.1" + "@vitejs/plugin-vue" "^1.2.3" + "@vue/compiler-sfc" "^3.1.1" + "@vue/server-renderer" "^3.1.1" + chalk "^4.1.1" + compression "^1.7.4" + debug "^4.3.2" + diacritics "^1.3.0" + escape-html "^1.0.3" + fs-extra "^10.0.0" + globby "^11.0.3" + gray-matter "^4.0.3" + lru-cache "^6.0.0" + markdown-it "^12.0.6" + markdown-it-anchor "^7.1.0" + markdown-it-container "^3.0.0" + markdown-it-emoji "^2.0.0" + markdown-it-table-of-contents "^0.5.2" + minimist "^1.2.5" + ora "^5.4.0" + polka "^0.5.2" + prismjs "^1.23.0" + sirv "^1.0.12" + vite "^2.3.7" + vue "^3.1.1" + +vitepress@^0.16.1: + version "0.16.1" + resolved "https://registry.npmjs.org/vitepress/-/vitepress-0.16.1.tgz#70ba4326a4bdc7152f264868c0775615c0bc16d5" + integrity sha512-jsgNY+b4mngVHQ1mZZ7ZGJliup/nM0jwdKTGoptwVzSQfkx5i3lF14jRRMb6ulC+9X5xbQ7N/zNcWqVWMFd/cQ== + dependencies: + "@docsearch/css" "^1.0.0-alpha.28" + "@docsearch/js" "^1.0.0-alpha.28" + "@types/markdown-it" "^12.0.1" + "@vitejs/plugin-vue" "^1.4.0" + "@vue/compiler-sfc" "^3.2.1" + "@vue/server-renderer" "^3.2.1" + chalk "^4.1.1" + compression "^1.7.4" + debug "^4.3.2" + diacritics "^1.3.0" + escape-html "^1.0.3" + fs-extra "^10.0.0" + globby "^11.0.3" + gray-matter "^4.0.3" + lru-cache "^6.0.0" + markdown-it "^12.0.6" + markdown-it-anchor "^7.1.0" + markdown-it-container "^3.0.0" + markdown-it-emoji "^2.0.0" + markdown-it-table-of-contents "^0.5.2" + minimist "^1.2.5" + ora "^5.4.0" + polka "^0.5.2" + prismjs "^1.23.0" + sirv "^1.0.12" + vite "^2.4.4" + vue "^3.2.1" + +void-elements@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + +vscode-css-languageservice@^5.1.4: + version "5.1.8" + resolved "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-5.1.8.tgz#36cb389788ffc2d5e6630ffc84e55ee38f8a2338" + integrity sha512-Si1sMykS8U/p8LYgLGPCfZD1YFT0AtvUJQp9XJGw64DZWhtwYo28G2l64USLS9ge4ZPMZpwdpOK7PfbVKfgiiA== + dependencies: + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-html-languageservice@^4.0.7: + version "4.1.1" + resolved "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.1.1.tgz#93739c9f3d0c12c8249bad23f5005850c289ec38" + integrity sha512-rrDyCiOgMwOPgchpPGAeLzjYVVEW/Ror2/a1BWUEI3S9+NQhA9vj4SQkzmH6g2Bq9S9SV0OQeadD+xphOf1N3w== + dependencies: + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-json-languageservice@^4.1.7: + version "4.1.9" + resolved "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.9.tgz#fb48edc69e37167c3cafd447c3fa898052d87b61" + integrity sha512-kxNHitUy2fCxmP6vAp0SRLrUSuecUYzzxlC+85cC3jJlFHWmvtCJOzikC+kcUnIdls9fQSB8n0yHs8Sl6taxJw== + dependencies: + jsonc-parser "^3.0.0" + vscode-languageserver-textdocument "^1.0.1" + vscode-languageserver-types "^3.16.0" + vscode-nls "^5.0.0" + vscode-uri "^3.0.2" + +vscode-jsonrpc@8.0.0-next.3, vscode-jsonrpc@^8.0.0-next.2: + version "8.0.0-next.3" + resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.3.tgz#b55edff0e550b03f3804aade44aca2699af27255" + integrity sha512-2wRiBR5tZAXZ4UxIO4F0cT/zN6OpruoWO0vc7EpQZxVfumb0pYiSegB+PaOzXCuFQzh7YEshW/XMg4zTz3FGVQ== + +vscode-languageserver-protocol@3.17.0-next.9: + version "3.17.0-next.9" + resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.9.tgz#0fd4ad43611c96acd83d8d998dbe76668f60e604" + integrity sha512-DGkRmbI1hRBMY6HU6MOyza5AvYp0+HcbMf2qdmI98luyQJ26dOfHY5K38OS4hlTHhdJg9RypTQ/uBbLZehmn1Q== + dependencies: + vscode-jsonrpc "8.0.0-next.3" + vscode-languageserver-types "3.17.0-next.4" vscode-languageserver-textdocument@^1.0.1: - version "1.0.1" - resolved "https://registry.npm.taobao.org/vscode-languageserver-textdocument/download/vscode-languageserver-textdocument-1.0.1.tgz#178168e87efad6171b372add1dea34f53e5d330f" - integrity sha1-F4Fo6H761hcbNyrdHeo09T5dMw8= + version "1.0.2" + resolved "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz#2f9f6bd5b5eb3d8e21424c0c367009216f016236" + integrity sha512-T7uPC18+f8mYE4lbVZwb3OSmvwTZm3cuFhrdx9Bn2l11lmp3SvSuSVjy2JtvrghzjAo4G6Trqny2m9XGnFnWVA== + +vscode-languageserver-types@3.17.0-next.4: + version "3.17.0-next.4" + resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.4.tgz#f6788b375ec163da8b381f2f3e3f547cbc7fbeec" + integrity sha512-MraVkZDhfqa3ftnKW9rEDeqsV+ji8OrtEjx6mVjzVGm5U2XXT+mdqDWyQ+y0Gvb2/aa2oJJQyTAaDmRTUKiUbg== + +vscode-languageserver-types@^3.15.1, vscode-languageserver-types@^3.16.0: + version "3.16.0" + resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== + +vscode-languageserver@^8.0.0-next.2: + version "8.0.0-next.3" + resolved "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.0-next.3.tgz#36c701a6844ec269505539e3b84a37693760a52f" + integrity sha512-uxL/tKUa/gRdvQINVmMnK32d6LwfTPTvF7l1iZIFDuAdhGrQ+Po+4lS3w4hwQSeUmapM1WMELXNBFca/u3H5Uw== + dependencies: + vscode-languageserver-protocol "3.17.0-next.9" + +vscode-nls@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" + integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== + +vscode-pug-languageservice@^0.27.24: + version "0.27.24" + resolved "https://registry.npmjs.org/vscode-pug-languageservice/-/vscode-pug-languageservice-0.27.24.tgz#fa805c4d3e33dee3681e660a0767136738e68370" + integrity sha512-GSvsFB+rPhAD7cBlEKCVNNsFGIaOnp/0zyLw3WpYbXY24vJZafXu1kHvtYaaQXJRnIhqp5EI5p+EqpdI3hTBnw== + dependencies: + "@volar/code-gen" "^0.27.24" + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + "@volar/transforms" "^0.27.24" + pug-lexer "^5.0.1" + pug-parser "^6.0.0" + vscode-languageserver "^8.0.0-next.2" + +vscode-typescript-languageservice@^0.27.25: + version "0.27.25" + resolved "https://registry.npmjs.org/vscode-typescript-languageservice/-/vscode-typescript-languageservice-0.27.25.tgz#acd211723b600108c25515388b75d55ce15bb056" + integrity sha512-nxpJI9MnF2rn5rKL/032Qrsq3T9DgM3slK5fwZp3suNdo90JG2zFTs3Ola8n62k7+KWu4A775obxyb4wLIW6Gw== + dependencies: + "@volar/shared" "^0.27.24" + semver "^7.3.5" + upath "^2.0.1" + vscode-languageserver "^8.0.0-next.2" + vscode-languageserver-textdocument "^1.0.1" vscode-uri@^2.1.2: version "2.1.2" - resolved "https://registry.npm.taobao.org/vscode-uri/download/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" - integrity sha1-yNQN6T61evMfPHFd1lDiyiwJbxw= + resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" + integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A== + +vscode-uri@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz#ecfd1d066cb8ef4c3a208decdbab9a8c23d055d0" + integrity sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA== + +vscode-vue-languageservice@^0.27.0: + version "0.27.30" + resolved "https://registry.npmjs.org/vscode-vue-languageservice/-/vscode-vue-languageservice-0.27.30.tgz#1f32b0203dd233582f74a457428519a6318f039e" + integrity sha512-nPnUNCMqqHfxcCPLyLWvmgbNCgos3SwvPcl/CzAnMbqcjLtNZppsdI7bKX3EEj0Jbg6SGLQ9NanIvZaMI1bsUA== + dependencies: + "@volar/code-gen" "^0.27.24" + "@volar/html2pug" "^0.27.13" + "@volar/shared" "^0.27.24" + "@volar/source-map" "^0.27.24" + "@volar/transforms" "^0.27.24" + "@vscode/emmet-helper" "^2.7.0" + "@vue/compiler-dom" "^3.2.19" + "@vue/reactivity" "^3.2.19" + "@vue/shared" "^3.2.19" + request-light "^0.5.4" + upath "^2.0.1" + vscode-css-languageservice "^5.1.4" + vscode-html-languageservice "^4.0.7" + vscode-json-languageservice "^4.1.7" + vscode-languageserver "^8.0.0-next.2" + vscode-languageserver-textdocument "^1.0.1" + vscode-pug-languageservice "^0.27.24" + vscode-typescript-languageservice "^0.27.25" vscode-web-custom-data@^0.3.2: - version "0.3.3" - resolved "https://registry.npm.taobao.org/vscode-web-custom-data/download/vscode-web-custom-data-0.3.3.tgz#9e1f2388c718d6f190038a19d144834a436b876f" - integrity sha1-nh8jiMcY1vGQA4oZ0USDSkNrh28= + version "0.3.6" + resolved "https://registry.npmjs.org/vscode-web-custom-data/-/vscode-web-custom-data-0.3.6.tgz#7ff374bd39ee4a7c05c77c997d9410520e1d02bc" + integrity sha512-9r2DOv4YMXL/WBTBB6zxde93hmg6AM7thr7GMR6c5LvPxXe/lwD8gsrJGe0tha4CUvoz86ElUieThGVpM+4PLg== + +vue-eslint-parser@^7.10.0: + version "7.11.0" + resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz#214b5dea961007fcffb2ee65b8912307628d0daf" + integrity sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg== + dependencies: + debug "^4.1.1" + eslint-scope "^5.1.1" + eslint-visitor-keys "^1.1.0" + espree "^6.2.1" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^6.3.0" vue-router@^4.0.3: - version "4.0.6" - resolved "https://registry.npm.taobao.org/vue-router/download/vue-router-4.0.6.tgz#91750db507d26642f225b0ec6064568e5fe448d6" - integrity sha1-kXUNtQfSZkLyJbDsYGRWjl/kSNY= + version "4.0.12" + resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.12.tgz#8dc792cddf5bb1abcc3908f9064136de7e13c460" + integrity sha512-CPXvfqe+mZLB1kBWssssTiWg4EQERyqJZes7USiqfW9B5N2x+nHlnsM1D3b5CaJ6qgCvMmYJnz+G0iWjNCvXrg== + dependencies: + "@vue/devtools-api" "^6.0.0-beta.18" + +vue-tsc@^0.2.2: + version "0.2.3" + resolved "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.2.3.tgz#12bf48e3c9b1e553d31aad0c641722d5d15841d8" + integrity sha512-0ahxAnQolmv6EOnv5zxeMi4vCpM4PkhjU70i/EI44OzMWq4OErjLZhEh8EXOLtMx6FBRuuqS5fiBXcuqLpoL7Q== + dependencies: + vscode-vue-languageservice "^0.27.0" + +vue@^3.1.1, vue@^3.2.1: + version "3.2.21" + resolved "https://registry.npmjs.org/vue/-/vue-3.2.21.tgz#55f5665172d95cf97e806b9aad0a375180be23a1" + integrity sha512-jpy7ckXdyclfRzqLjL4mtq81AkzQleE54KjZsJg/9OorNVurAxdlU5XpD49GpjKdnftuffKUvx2C5jDOrgc/zg== + dependencies: + "@vue/compiler-dom" "3.2.21" + "@vue/compiler-sfc" "3.2.21" + "@vue/runtime-dom" "3.2.21" + "@vue/server-renderer" "3.2.21" + "@vue/shared" "3.2.21" + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" -vue@^3.0.5: - version "3.0.11" - resolved "https://registry.npm.taobao.org/vue/download/vue-3.0.11.tgz?cache=0&sync_timestamp=1617324200123&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f" - integrity sha1-yC+VlMv03MhpJB1MjdPgjZqPS18= +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +wcwidth@^1.0.0, wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - "@vue/compiler-dom" "3.0.11" - "@vue/runtime-dom" "3.0.11" - "@vue/shared" "3.0.11" + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" which-module@^2.0.0: version "2.0.0" - resolved "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= which-pm-runs@^1.0.0: version "1.0.0" - resolved "https://registry.npm.taobao.org/which-pm-runs/download/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= +which@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +with@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" + integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w== + dependencies: + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + assert-never "^1.2.1" + babel-walk "3.0.0-canary-5" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + wrap-ansi@^6.2.0: version "6.2.0" - resolved "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha1-6Tk7oHEC5skaOyIUePAlfNKFblM= + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" @@ -2449,8 +10421,8 @@ wrap-ansi@^6.2.0: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM= + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" @@ -2458,51 +10430,133 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^2.4.2: + version "2.4.3" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write-json-file@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" + integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== + dependencies: + detect-indent "^5.0.0" + graceful-fs "^4.1.15" + make-dir "^2.1.0" + pify "^4.0.1" + sort-keys "^2.0.0" + write-file-atomic "^2.4.2" + +write-json-file@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" + integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== + dependencies: + detect-indent "^6.0.0" + graceful-fs "^4.1.15" + is-plain-obj "^2.0.0" + make-dir "^3.0.0" + sort-keys "^4.0.0" + write-file-atomic "^3.0.0" + +write-pkg@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" + integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== + dependencies: + sort-keys "^2.0.0" + type-fest "^0.4.1" + write-json-file "^3.2.0" + +ws@^7.4.6: + version "7.5.5" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^4.0.0: version "4.0.3" - resolved "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8= + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.npm.taobao.org/y18n/download/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU= + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^3.0.2: +yallist@^3.0.0, yallist@^3.1.1: version "3.1.1" - resolved "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha1-27fa+b/YusmrRev2ArjLrQ1dCP0= + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI= + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.10.0: version "1.10.2" - resolved "https://registry.npm.taobao.org/yaml/download/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha1-IwHF/78StGfejaIzOkWeKeeSDks= + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.0.0-6: + version "2.0.0-8" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.0.0-8.tgz#226365f0d804ba7fb8cc2b527a00a7a4a3d8ea5f" + integrity sha512-QaYgJZMfWD6fKN/EYMk6w1oLWPCr1xj9QaPSZW5qkDb3y8nGCXhy2Ono+AF4F+CSL/vGcqswcAT0BaS//pgD2A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== yargs-parser@^18.1.2: version "18.1.3" - resolved "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-18.1.3.tgz?cache=0&sync_timestamp=1615419388743&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A= + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.7" - resolved "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-20.2.7.tgz?cache=0&sync_timestamp=1615419388743&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha1-Yd+FwRPt+1p6TjbriqYO9CPLyQo= + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs@^15.1.0: version "15.4.1" - resolved "https://registry.npm.taobao.org/yargs/download/yargs-15.4.1.tgz?cache=0&sync_timestamp=1618195657622&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg= + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" decamelize "^1.2.0" @@ -2516,10 +10570,10 @@ yargs@^15.1.0: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.0: +yargs@^16.0.0, yargs@^16.2.0: version "16.2.0" - resolved "https://registry.npm.taobao.org/yargs/download/yargs-16.2.0.tgz?cache=0&sync_timestamp=1618195657622&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha1-HIK/D2tqZur85+8w43b0mhJHf2Y= + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" escalade "^3.1.1" @@ -2529,7 +10583,17 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yarn@^1.22.11: + version "1.22.17" + resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz#bf910747d22497b573131f7341c0e1d15c74036c" + integrity sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ== + yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npm.taobao.org/yocto-queue/download/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha1-ApTrPe4FAo0x7hpfosVWpqrxChs= + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zwitch@^1.0.0: + version "1.0.5" + resolved "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" + integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==