浏览代码

Merge branch 'next' of https://github.com/jdf2e/nutui into next

Drjnigfubo 3 年之前
父节点
当前提交
038155ed2f

+ 9 - 8
README.md

@@ -50,15 +50,16 @@
 
 ##  特性
 
-* 🚀 70+ 高质量组件(3.0 持续开发中),覆盖移动端主流场景
-* 💪 支持小程序开发
+* 🚀 70+ 高质量组件覆盖移动端主流场景
+* 💪 支持一套代码同时开发多端小程序+H5
 * 📖 基于京东APP 10.0 视觉规范
 * 🍭 支持按需引用
 * 📖 详尽的文档和示例
 * 💪 支持 TypeScript
 * 💪 支持服务端渲染(测试阶段)
-* 🍭 支持定制主题
-* 🍭 单元测试覆盖(3.0 开发中),保障稳定性
+* 🍭 支持定制主题,内置 700+ 个主题变量
+* 🌍 国际化支持(开发中,计划2022-Q2支持)
+* 🍭 单元测试覆盖率超过 80%,保障稳定性
 * 📖 提供 Sketch 设计资源
 
 ## 示例 H5 & 小程序
@@ -72,14 +73,14 @@
 
 ## 版本说明
 
-> @next 和 @nutui-taro 属于并行版本,存在部分的差异化,版本号始终保持一致。如果想要兼容低版本,请使用 @nutui/nutui
+> @nutui/nutui 和 @nutui/nutui-taro 属于并行版本,存在部分的差异化,版本号始终保持一致。如果想要兼容低版本 ios 10 以下,请使用 @nutui/nutui@2
 
 | 版本 | 支持的框架 | 视觉规范 | 支持的应用类型 | 兼容
 | --- | --- | --- | --- | --- |
-| @nutui/nutui  | Vue 2x | 京东 APP 7.0 规范 | H5 | 现代浏览器及 Android >= 4.0、iOS >= 8.0
-| @nutui/nutui-jdl  | Vue 2x | [京东物流视觉规范](https://nutui.jd.com/jdl/#/design) | H5 | 现代浏览器及 Android >= 4.0、iOS >= 8.0
-| @nutui/nutui@next  | Vue 3x | 京东 [APP 10.0](https://nutui.jd.com/#/resource) 规范 | H5 | 现代浏览器以 Chrome >= 51、iOS >= 10.0(与 Vue3 一致)
+| @nutui/nutui  | Vue 3x | 京东 [APP 10.0](https://nutui.jd.com/#/resource) 规范 | H5 | 现代浏览器以 Chrome >= 51、iOS >= 10.0(与 Vue3 一致)
 | @nutui/nutui-taro  | Vue3 + Taro | 京东 [APP 10.0](https://nutui.jd.com/#/resource) 规范 | H5&小程序,可[开发多端](https://nutui.jd.com/#/starttaro) | 现代浏览器及 Chrome >= 51、iOS >= 10.0(与 Vue3 一致)
+| @nutui/nutui@2  | Vue 2x | 京东 APP 7.0 规范 | H5 | 现代浏览器及 Android >= 4.0、iOS >= 8.0
+| @nutui/nutui-jdl  | Vue 2x | [京东物流视觉规范](https://nutui.jd.com/jdl/#/design) | H5 | 现代浏览器及 Android >= 4.0、iOS >= 8.0
 
 
 ## 构建版本

+ 47 - 0
jd/generate-taro-route.js

@@ -0,0 +1,47 @@
+const fse = require('fs-extra');
+const config = require('../src/config.json');
+const targetBaseUrl = `${process.cwd()}/src`;
+const taroConfig = `${targetBaseUrl}/sites/mobile-taro/vue/src/app.config.ts`;
+
+// 创建 config
+const createConfig = async () => {
+  let configRef = [];
+
+  return new Promise((res, rej) => {
+    config.nav.map((item) => {
+      let co = {
+        root: item.enName,
+        pages: []
+      };
+
+      item.packages.map((it) => {
+        if (!(it.exportEmpty == false) && it.show) {
+          co.pages.push(`pages/${it.name.toLowerCase()}/index`);
+        }
+      });
+
+      configRef.push(co);
+    });
+
+    res(configRef);
+  });
+};
+
+const create = async () => {
+  const configTemplate = {
+    pages: ['pages/index/index'],
+    subpackages: '',
+    window: {
+      backgroundTextStyle: 'light',
+      navigationBarBackgroundColor: '#fff',
+      navigationBarTitleText: 'NutUI',
+      navigationBarTextStyle: 'black'
+    }
+  };
+
+  configTemplate.subpackages = await createConfig();
+
+  fse.writeFileSync(taroConfig, `export default ${JSON.stringify(configTemplate)}`, 'utf8');
+};
+
+create();

+ 27 - 0
jd/generate-types-taro.js

@@ -0,0 +1,27 @@
+const config = require('../src/config.json');
+const path = require('path');
+const fs = require('fs-extra');
+let importStr = ``;
+const packages = [];
+config.nav.map((item) => {
+  item.packages.forEach((element) => {
+    let { name } = element;
+    const filePath = path.join(`./src/packages/__VUE/${name.toLowerCase()}/index.taro.vue`);
+    importStr += `import ${name} from './__VUE/${name.toLowerCase()}/${
+      fs.existsSync(filePath) ? 'index.taro' : 'index'
+    }';\n`;
+
+    packages.push(name);
+  });
+});
+let installFunction = `
+export { ${packages.join(',')} };`;
+let fileStr = importStr + installFunction;
+fs.outputFileSync(path.resolve(__dirname, '../dist/types/nutui.d.ts'), fileStr, 'utf8');
+fs.outputFileSync(
+  path.resolve(__dirname, '../dist/types/index.d.ts'),
+  `import * as NutUI from './nutui';
+export default NutUI;
+export * from './nutui';`,
+  'utf8'
+);

+ 10 - 31
jd/generate-types.js

@@ -1,45 +1,24 @@
 const config = require('../src/config.json');
 const path = require('path');
 const fs = require('fs-extra');
-let importStr = `import { App } from 'vue';
-declare class UIComponent {
-  static install(vue: App): void;
-  $props: any;
-}\n`;
+let importStr = ``;
 const packages = [];
 config.nav.map((item) => {
   item.packages.forEach((element) => {
-    let { name, show, exportEmpty, type } = element;
-    if (show || exportEmpty) {
-      importStr +=
-        type == 'methods' ? `declare const ${name}: any;\n` : `declare class ${name} extends UIComponent {}\n`;
-      packages.push(name);
-    }
+    let { name } = element;
+    importStr += `import ${name} from './__VUE/${name.toLowerCase()}';\n`;
+
+    packages.push(name);
   });
 });
 let installFunction = `
-export interface InstallationOptions {
-  locale?: any;
-  lang?: any;
-}
-declare function install(app: App, options?: InstallationOptions): void;
-export { ${packages.join(',')},install };
-declare const _default: {
-  install: typeof install;
-  version: string;
-};
-export default _default;`;
+export { ${packages.join(',')} };`;
 let fileStr = importStr + installFunction;
-fs.outputFile(path.resolve(__dirname, '../dist/nutui.d.ts'), fileStr, 'utf8', (error) => {
-  // logger.success(`${package_config_path} 文件写入成功`);
-});
-fs.outputFile(
-  path.resolve(__dirname, '../dist/index.d.ts'),
+fs.outputFileSync(path.resolve(__dirname, '../dist/types/nutui.d.ts'), fileStr, 'utf8');
+fs.outputFileSync(
+  path.resolve(__dirname, '../dist/types/index.d.ts'),
   `import * as NutUI from './nutui';
 export default NutUI;
 export * from './nutui';`,
-  'utf8',
-  (error) => {
-    // logger.success(`${package_config_path} 文件写入成功`);
-  }
+  'utf8'
 );

+ 13 - 4
package.json

@@ -5,7 +5,13 @@
   "main": "dist/nutui.umd.js",
   "module": "dist/nutui.es.js",
   "style": "dist/style.css",
-  "typings": "dist/index.d.ts",
+  "typings": "dist/types/index.d.ts",
+  "exports": {
+    ".": {
+      "import": "./dist/nutui.es.js",
+      "require": "./dist/nutui.umd.js"
+    }
+  },
   "keywords": [
     "nutui",
     "nutui2",
@@ -36,12 +42,12 @@
     "checked": "npm run generate:file && tsc",
     "checked:taro:vue": "npm run generate:file:taro:vue",
     "dev": "npm run checked && vite --open --force",
-    "dev:taro:vue": "npm run checked:taro:vue && cd src/sites/mobile-taro/vue/ && npm run dev:weapp",
+    "dev:taro:vue": "npm run createTaroConfig && npm run checked:taro:vue && cd src/sites/mobile-taro/vue/ && npm run dev:weapp",
     "dev:taro:h5": "npm run checked:taro:vue && cd src/sites/mobile-taro/vue/ && npm run dev:h5",
     "build:site": "npm run checked && vite build",
     "build:site:oss": "npm run checked && vite build --base=/nutui/3x/",
     "build": "npm run checked && vite build --config vite.config.build.ts && vite build --config vite.config.build.disperse.ts && npm run generate:types && npm run generate:themes && vite build --config vite.config.build.css.ts",
-    "build:taro:vue": "npm run checked:taro:vue && vite build --config vite.config.build.taro.vue.ts && vite build --config vite.config.build.taro.vue.disperse.ts && npm run generate:types && npm run generate:themes && vite build --config vite.config.build.css.ts",
+    "build:taro:vue": "npm run checked:taro:vue && vite build --config vite.config.build.taro.vue.ts && vite build --config vite.config.build.taro.vue.disperse.ts && npm run generate:types:taro && npm run generate:themes && vite build --config vite.config.build.css.ts",
     "serve": "vite preview",
     "upload": "yarn build:site:oss && node ./jd/upload.js",
     "add": "node jd/createComponentMode.js",
@@ -50,12 +56,14 @@
     "generate:file": "node jd/generate-nutui.js",
     "generate:file:taro:vue": "node jd/generate-nutui-taro-vue.js",
     "generate:types": "node jd/generate-types.js",
+    "generate:types:taro": "node jd/generate-types-taro.js",
     "generate:themes": "node jd/generate-themes.js",
     "prepare": "husky install",
     "test": "jest",
     "release": "standard-version -a",
     "codeformat": "prettier --write .",
-    "copydocs": "node ./jd/copymd.js"
+    "copydocs": "node ./jd/copymd.js",
+    "createTaroConfig": "node ./jd/generate-taro-route.js"
   },
   "standard-version": {
     "scripts": {
@@ -103,6 +111,7 @@
     "ts-jest": "^26.5.5",
     "typescript": "^4.1.5",
     "vite": "^2.7.13",
+    "vite-plugin-dts": "^1.0.5",
     "vite-plugin-md": "^0.11.8",
     "vue": "^3.2.30",
     "vue-jest": "^5.0.0-alpha.7"

+ 6 - 1
src/config.json

@@ -750,6 +750,8 @@
           "desc": "音频播放器",
           "sort": 25,
           "show": true,
+          "exportEmpty":false,
+          "exportEmptyTaro":false,
           "author": "yangxiaolu"
         },
         {
@@ -760,6 +762,8 @@
           "desc": "音频操作按钮",
           "sort": 26,
           "show": false,
+          "exportEmpty":false,
+          "exportEmptyTaro":false,
           "author": "yangxiaolu"
         }
 
@@ -834,6 +838,8 @@
           "taro": false,
           "show": true,
           "tarodoc": true,
+          "exportEmpty":false,
+          "exportEmptyTaro":false,
           "author": "zy19940510"
         },
 
@@ -1018,7 +1024,6 @@
         }
       ]
     },
-
     {
       "name": "特色组件",
       "enName": "business",

+ 2 - 0
src/packages/__VUE/checkbox/doc.md

@@ -248,6 +248,8 @@ app.use(Checkbox).use(CheckboxGroup).use(Icon);
 | icon-size | [图标尺寸](#/icon) | String、Number | `18`
 | icon-name | [图标名称](#/icon),选中前(建议和`icon-active-name`一起修改) | String | `'check-normal'`
 | icon-active-name | [图标名称](#/icon),选中后(建议和`icon-name`一起修改) | String | `'checked'`
+| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
+| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label | 复选框的文本内容 | String | -
 
 

+ 12 - 2
src/packages/__VUE/checkbox/index.taro.vue

@@ -35,6 +35,14 @@ export default create({
     label: {
       type: String,
       default: ''
+    },
+    iconClassPrefix: {
+      type: String,
+      default: 'nut-icon'
+    },
+    iconFontClassName: {
+      type: String,
+      default: 'nutui-iconfont'
     }
   },
   emits: ['change', 'update:modelValue'],
@@ -71,11 +79,13 @@ export default create({
     };
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName } = props;
+      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
       return h(nutIcon, {
         name: !pValue.value ? iconName : iconActiveName,
         size: iconSize,
-        class: color.value
+        class: color.value,
+        classPrefix: iconClassPrefix,
+        fontClassName: iconFontClassName
       });
     };
 

+ 12 - 2
src/packages/__VUE/checkbox/index.vue

@@ -36,6 +36,14 @@ export default create({
     label: {
       type: String,
       default: ''
+    },
+    iconClassPrefix: {
+      type: String,
+      default: 'nut-icon'
+    },
+    iconFontClassName: {
+      type: String,
+      default: 'nutui-iconfont'
     }
   },
   emits: ['change', 'update:modelValue'],
@@ -72,11 +80,13 @@ export default create({
     };
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName } = props;
+      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
       return h(nutIcon, {
         name: !pValue.value ? iconName : iconActiveName,
         size: iconSize,
-        class: color.value
+        class: color.value,
+        classPrefix: iconClassPrefix,
+        fontClassName: iconFontClassName
       });
     };
 

+ 1 - 1
src/packages/__VUE/countdown/index.taro.vue

@@ -71,7 +71,7 @@ export default create({
     }
   },
   components: {},
-  emits: ['input', 'on-end', 'on-restart', 'on-paused'],
+  emits: ['input', 'on-end', 'on-restart', 'on-paused', 'update:modelValue'],
 
   setup(props, { emit, slots }) {
     // console.log('componentName', componentName);

+ 2 - 0
src/packages/__VUE/numberkeyboard/doc.md

@@ -69,6 +69,7 @@ export default{
       type="rightColumn"
       v-model:visible="visible"
       :custom-key="customKey"
+      :confirm-text="支付"
       @input="input"
       @close="close"
     >
@@ -252,6 +253,7 @@ export default{
 | overlay | 是否显示遮罩  | Boolean| true |
 | v-model:value | 当前输入值		 | String | - |
 | maxlength  | 输入值最大长度,结合 v-model 使用 | number <br> String| 6 |
+| confirm-text  | 自定义完成按钮文字,如"支付","下一步","提交"等 | String | 完成 |
 
 
 ### Event

+ 5 - 1
src/packages/__VUE/numberkeyboard/index.taro.vue

@@ -61,7 +61,7 @@
             </div>
           </div>
           <div class="key-board-wrapper" @click="closeBoard()" v-if="title == ''">
-            <div :class="['key', 'finish', { activeFinsh: clickKeyIndex == 'finish' }]"> 完成 </div>
+            <div :class="['key', 'finish', { activeFinsh: clickKeyIndex == 'finish' }]"> {{ confirmText }} </div>
           </div>
         </div>
       </div>
@@ -75,6 +75,10 @@ import { createComponent } from '../../utils/create';
 const { create } = createComponent('numberkeyboard');
 export default create({
   props: {
+    confirmText: {
+      type: String,
+      default: '完成'
+    },
     title: {
       type: String,
       default: ''

+ 5 - 1
src/packages/__VUE/numberkeyboard/index.vue

@@ -62,7 +62,7 @@
             </div>
           </div>
           <div class="key-board-wrapper key-board-finish" @click="closeBoard()" v-if="title == ''">
-            <div :class="['key', 'finish', { activeFinsh: clickKeyIndex == 'finish' }]"> 完成 </div>
+            <div :class="['key', 'finish', { activeFinsh: clickKeyIndex == 'finish' }]"> {{ confirmText }} </div>
           </div>
         </div>
       </div>
@@ -76,6 +76,10 @@ import { createComponent } from '../../utils/create';
 const { create } = createComponent('numberkeyboard');
 export default create({
   props: {
+    confirmText: {
+      type: String,
+      default: '完成'
+    },
     title: {
       type: String,
       default: ''

+ 14 - 0
src/packages/__VUE/numberkeyboard/test/index.spec.ts

@@ -94,6 +94,20 @@ test('should render title and close button correctly', () => {
   let title = wrapper.find('.tit');
   expect(title.html()).toContain('默认键盘');
 });
+
+test('should render finish button correctly', () => {
+  const wrapper = mount(NumberKeyboard, {
+    props: {
+      visible: true,
+      isWrapTeleport: false,
+      type: 'rightColumn',
+      confirmText: '支付'
+    }
+  });
+  let title = wrapper.find('.finish');
+  expect(title.html()).toContain('支付');
+});
+
 test('should emit "update:modelValue" event after clicking key', () => {
   const wrapper = mount(NumberKeyboard, {
     props: {

+ 2 - 0
src/packages/__VUE/radio/doc.md

@@ -207,6 +207,8 @@ app.use(Radio).use(RadioGroup);
 | icon-size        | [图标尺寸](#/icon)                                           | String、Number          | `18`              |
 | icon-name        | [图标名称](#/icon),选中前(建议和`icon-active-name`一起修改) | String                  | `'check-normal'`  |
 | icon-active-name | [图标名称](#/icon),选中后(建议和`icon-name`一起修改)        | String                  | `'check-checked'` |
+| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
+| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label            | 单选框标识                                                   | String、Number、Boolean | -                 |
 | shape            | 形状,可选值为 button、round                                 | String                  | round             |
 

+ 12 - 2
src/packages/__VUE/radio/index.taro.vue

@@ -29,6 +29,14 @@ export default create({
     iconSize: {
       type: [String, Number],
       default: ''
+    },
+    iconClassPrefix: {
+      type: String,
+      default: 'nut-icon'
+    },
+    iconFontClassName: {
+      type: String,
+      default: 'nutui-iconfont'
     }
   },
   setup(props, { emit, slots }) {
@@ -51,11 +59,13 @@ export default create({
     });
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName } = props;
+      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
       return h(nutIcon, {
         name: isCurValue.value ? iconActiveName : iconName,
         size: iconSize,
-        class: color.value
+        class: color.value,
+        classPrefix: iconClassPrefix,
+        fontClassName: iconFontClassName
       });
     };
 

+ 12 - 2
src/packages/__VUE/radio/index.vue

@@ -29,6 +29,14 @@ export default create({
     iconSize: {
       type: [String, Number],
       default: ''
+    },
+    iconClassPrefix: {
+      type: String,
+      default: 'nut-icon'
+    },
+    iconFontClassName: {
+      type: String,
+      default: 'nutui-iconfont'
     }
   },
   setup(props, { emit, slots }) {
@@ -51,11 +59,13 @@ export default create({
     });
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName } = props;
+      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
       return h(nutIcon, {
         name: isCurValue.value ? iconActiveName : iconName,
         size: iconSize,
-        class: color.value
+        class: color.value,
+        classPrefix: iconClassPrefix,
+        fontClassName: iconFontClassName
       });
     };
 

+ 90 - 95
src/sites/mobile-taro/vue/src/app.config.ts

@@ -1,100 +1,95 @@
-let subpackages = [
-  {
-    root: 'layout',
-    pages: ['pages/layout/index', 'pages/divider/index', 'pages/sticky/index', 'pages/grid/index']
-  },
-  {
-    root: 'feedback',
-    pages: [
-      'pages/swipe/index',
-      'pages/backtop/index',
-      'pages/actionsheet/index',
-      'pages/dialog/index',
-      'pages/toast/index',
-      'pages/notify/index',
-      'pages/switch/index',
-      'pages/drag/index',
-      'pages/infiniteloading/index'
-    ]
-  },
-  {
-    root: 'base',
-    pages: ['pages/cell/index', 'pages/icon/index', 'pages/button/index', 'pages/overlay/index', 'pages/popup/index']
-  },
-  {
-    root: 'nav',
-    pages: [
-      'pages/navbar/index',
-      'pages/tabbar/index',
-      'pages/tabs/index',
-      'pages/fixednav/index',
-      'pages/elevator/index',
-      'pages/menu/index',
-      'pages/pagination/index',
-      'pages/indicator/index',
-      'pages/sidenavbar/index'
-    ]
-  },
-  {
-    root: 'dentry',
-    pages: [
-      'pages/range/index',
-      'pages/inputnumber/index',
-      'pages/checkbox/index',
-      'pages/input/index',
-      'pages/uploader/index',
-      'pages/rate/index',
-      'pages/radio/index',
-      'pages/calendar/index',
-      'pages/form/index',
-      'pages/shortpassword/index',
-      'pages/picker/index',
-      'pages/datepicker/index',
-      'pages/textarea/index',
-      'pages/numberkeyboard/index',
-      'pages/cascader/index',
-      'pages/oldpicker/index',
-      'pages/searchbar/index'
-    ]
-  },
-  {
-    root: 'exhibition',
-    pages: [
-      'pages/avatar/index',
-      'pages/price/index',
-      'pages/imagepreview/index',
-      'pages/collapse/index',
-      'pages/empty/index',
-      'pages/noticebar/index',
-      'pages/steps/index',
-      'pages/progress/index',
-      'pages/circleprogress/index',
-      'pages/list/index',
-      'pages/countdown/index',
-      'pages/countup/index',
-      'pages/badge/index',
-      'pages/tag/index',
-      'pages/popover/index',
-      'pages/skeleton/index',
-      'pages/table/index',
-      'pages/swiper/index'
-    ]
-  },
-  {
-    root: 'business',
-    pages: [
-      'pages/address/index',
-      'pages/signature/index',
-      'pages/barrage/index',
-      'pages/timeselect/index',
-      'pages/sku/index',
-      'pages/card/index'
-    ]
-  }
-];
 export default {
   pages: ['pages/index/index'],
-  subpackages,
+  subpackages: [
+    {
+      root: 'base',
+      pages: ['pages/button/index', 'pages/cell/index', 'pages/icon/index', 'pages/overlay/index', 'pages/popup/index']
+    },
+    { root: 'layout', pages: ['pages/layout/index', 'pages/sticky/index', 'pages/divider/index', 'pages/grid/index'] },
+    {
+      root: 'nav',
+      pages: [
+        'pages/navbar/index',
+        'pages/fixednav/index',
+        'pages/menu/index',
+        'pages/tabbar/index',
+        'pages/elevator/index',
+        'pages/pagination/index',
+        'pages/tabs/index',
+        'pages/indicator/index',
+        'pages/sidenavbar/index'
+      ]
+    },
+    {
+      root: 'dentry',
+      pages: [
+        'pages/range/index',
+        'pages/searchbar/index',
+        'pages/cascader/index',
+        'pages/calendar/index',
+        'pages/checkbox/index',
+        'pages/datepicker/index',
+        'pages/inputnumber/index',
+        'pages/input/index',
+        'pages/radio/index',
+        'pages/rate/index',
+        'pages/picker/index',
+        'pages/shortpassword/index',
+        'pages/textarea/index',
+        'pages/uploader/index',
+        'pages/numberkeyboard/index',
+        'pages/form/index'
+      ]
+    },
+    {
+      root: 'feedback',
+      pages: [
+        'pages/swipe/index',
+        'pages/actionsheet/index',
+        'pages/backtop/index',
+        'pages/drag/index',
+        'pages/dialog/index',
+        'pages/infiniteloading/index',
+        'pages/notify/index',
+        'pages/switch/index',
+        'pages/toast/index'
+      ]
+    },
+    {
+      root: 'exhibition',
+      pages: [
+        'pages/list/index',
+        'pages/progress/index',
+        'pages/circleprogress/index',
+        'pages/noticebar/index',
+        'pages/empty/index',
+        'pages/steps/index',
+        'pages/swiper/index',
+        'pages/avatar/index',
+        'pages/price/index',
+        'pages/imagepreview/index',
+        'pages/countup/index',
+        'pages/countdown/index',
+        'pages/badge/index',
+        'pages/tag/index',
+        'pages/popover/index',
+        'pages/skeleton/index',
+        'pages/collapse/index',
+        'pages/table/index'
+      ]
+    },
+    {
+      root: 'business',
+      pages: [
+        'pages/address/index',
+        'pages/barrage/index',
+        'pages/signature/index',
+        'pages/timeselect/index',
+        'pages/sku/index',
+        'pages/card/index'
+      ]
+    }
+  ],
   window: {
     backgroundTextStyle: 'light',
     navigationBarBackgroundColor: '#fff',

+ 1 - 1
src/sites/mobile-taro/vue/src/pages/index/index.vue

@@ -16,7 +16,7 @@
         <li>{{ _nav.name }}</li>
         <ul>
           <template v-for="_package in reorder(_nav.packages)" :key="_package">
-            <li v-if="_package.show">
+            <li v-if="_package.show && _package.exportEmpty !== false">
               <a @click="navigateTo(_package.name.toLowerCase(), _nav.enName)">
                 {{ _package.name }}
                 &nbsp;&nbsp;

+ 35 - 1
vite.config.build.disperse.ts

@@ -1,4 +1,5 @@
 import { defineConfig } from 'vite';
+import dts from 'vite-plugin-dts';
 import vue from '@vitejs/plugin-vue';
 import path from 'path';
 import config from './package.json';
@@ -23,7 +24,40 @@ export default defineConfig({
   resolve: {
     alias: [{ find: '@', replacement: path.resolve(__dirname, './src') }]
   },
-  plugins: [vue()],
+  plugins: [
+    vue(),
+    dts({
+      insertTypesEntry: true,
+      copyDtsFiles: false,
+      cleanVueFileName: true,
+      outputDir: path.resolve(__dirname, './dist/types'),
+      include: path.resolve(__dirname, './src/packages/__VUE'),
+      beforeWriteFile: (filePath: string, content: string) => {
+        const fileContent = `import { App } from 'vue';
+declare type Install<T> = T & {
+  install(app: App): void;
+};
+`;
+        const start = 'declare const _default:';
+        const end = ';\nexport default _default;\n';
+        const remain = `
+declare module 'vue' {
+  interface GlobalComponents {
+      Nut${Object.keys(input).find(
+        (item: string) => item.toLowerCase() === filePath.split('/').slice(-2)[0]
+      )}: typeof _default;
+  }
+}     
+      `;
+        const inputs = content.match(RegExp(`${start}([\\s\\S]*?)${end}`));
+        const changeContent = inputs && inputs.length ? `${start} Install<${inputs[1]}>${end}${remain}` : content;
+        return {
+          filePath,
+          content: fileContent + changeContent
+        };
+      }
+    })
+  ],
   build: {
     minify: false,
     terserOptions: {

+ 35 - 1
vite.config.build.taro.vue.disperse.ts

@@ -1,4 +1,5 @@
 import { defineConfig } from 'vite';
+import dts from 'vite-plugin-dts';
 import vue from '@vitejs/plugin-vue';
 import path from 'path';
 const fs = require('fs-extra');
@@ -25,7 +26,40 @@ export default defineConfig({
   resolve: {
     alias: [{ find: '@', replacement: path.resolve(__dirname, './src') }]
   },
-  plugins: [vue()],
+  plugins: [
+    vue(),
+    dts({
+      insertTypesEntry: true,
+      copyDtsFiles: false,
+      cleanVueFileName: true,
+      outputDir: path.resolve(__dirname, './dist/types'),
+      include: path.resolve(__dirname, './src/packages/__VUE'),
+      beforeWriteFile: (filePath: string, content: string) => {
+        const fileContent = `import { App } from 'vue';
+declare type Install<T> = T & {
+  install(app: App): void;
+};
+`;
+        const start = 'declare const _default:';
+        const end = ';\nexport default _default;\n';
+        const remain = `
+declare module 'vue' {
+  interface GlobalComponents {
+      Nut${Object.keys(input).find(
+        (item: string) => item.toLowerCase() === filePath.split('/').slice(-2)[0]
+      )}: typeof _default;
+  }
+}     
+      `;
+        const inputs = content.match(RegExp(`${start}([\\s\\S]*?)${end}`));
+        const changeContent = inputs && inputs.length ? `${start} Install<${inputs[1]}>${end}${remain}` : content;
+        return {
+          filePath,
+          content: fileContent + changeContent
+        };
+      }
+    })
+  ],
   build: {
     minify: false,
     terserOptions: {

+ 1 - 0
vite.config.build.ts

@@ -1,4 +1,5 @@
 import { defineConfig } from 'vite';
+import dts from 'vite-plugin-dts';
 import vue from '@vitejs/plugin-vue';
 import path from 'path';
 import config from './package.json';