Browse Source

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

Drjnigfubo 3 years ago
parent
commit
c6dbec39b9
53 changed files with 1274 additions and 415 deletions
  1. 3 0
      .gitignore
  2. 49 0
      CHANGELOG.md
  3. 105 0
      jd/createAttributes.js
  4. 9 4
      package.json
  5. 6 1
      src/config.json
  6. 0 2
      src/packages/__VUE/actionsheet/doc.md
  7. 0 4
      src/packages/__VUE/actionsheet/index.scss
  8. 1 5
      src/packages/__VUE/actionsheet/index.taro.vue
  9. 1 5
      src/packages/__VUE/actionsheet/index.vue
  10. 1 25
      src/packages/__VUE/cascader/__tests__/cascader.spec.ts
  11. 2 0
      src/packages/__VUE/cascader/demo.vue
  12. 4 0
      src/packages/__VUE/cascader/doc.md
  13. 6 2
      src/packages/__VUE/cascader/index.taro.vue
  14. 6 2
      src/packages/__VUE/cascader/index.vue
  15. 14 17
      src/packages/__VUE/cascader/tree.ts
  16. 4 4
      src/packages/__VUE/category/index.scss
  17. 1 1
      src/packages/__VUE/circleprogress/doc.md
  18. 4 4
      src/packages/__VUE/circleprogress/index.scss
  19. 5 5
      src/packages/__VUE/comment/index.scss
  20. 1 0
      src/packages/__VUE/popup/doc.md
  21. 4 0
      src/packages/__VUE/popup/index.scss
  22. 5 0
      src/packages/__VUE/popup/index.taro.vue
  23. 5 0
      src/packages/__VUE/popup/index.vue
  24. 0 1
      src/packages/__VUE/swiperitem/index.taro.vue
  25. 0 1
      src/packages/__VUE/swiperitem/index.vue
  26. 2 2
      src/packages/__VUE/table/common.ts
  27. 12 1
      src/packages/__VUE/table/demo.vue
  28. 298 287
      src/packages/__VUE/table/doc.md
  29. 9 3
      src/packages/__VUE/table/index.taro.vue
  30. 9 3
      src/packages/__VUE/table/index.vue
  31. 4 3
      src/packages/__VUE/table/renderColumn.ts
  32. 2 2
      src/packages/__VUE/table/types.ts
  33. 14 9
      src/packages/styles/variables-jdt.scss
  34. 12 13
      src/packages/styles/variables.scss
  35. 24 0
      src/packages/vscode-extension/.eslintrc.json
  36. 6 0
      src/packages/vscode-extension/.gitignore
  37. 11 0
      src/packages/vscode-extension/.vscodeignore
  38. 1 0
      src/packages/vscode-extension/.yarnrc
  39. 6 0
      src/packages/vscode-extension/CHANGELOG.md
  40. 21 0
      src/packages/vscode-extension/LICENSE
  41. 1 0
      src/packages/vscode-extension/README.md
  42. 55 0
      src/packages/vscode-extension/package.json
  43. 58 0
      src/packages/vscode-extension/scripts/createComponentMap.js
  44. 4 0
      src/packages/vscode-extension/src/componentDesc.ts
  45. 324 0
      src/packages/vscode-extension/src/componentMap.ts
  46. 80 0
      src/packages/vscode-extension/src/extension.ts
  47. BIN
      src/packages/vscode-extension/src/nutui.png
  48. 12 0
      src/packages/vscode-extension/src/utils.ts
  49. 16 0
      src/packages/vscode-extension/tsconfig.json
  50. 48 0
      src/packages/vscode-extension/webpack.config.js
  51. 1 1
      src/sites/doc/components/demo-block/demoCodePackage.json
  52. 4 4
      vite.config.build.disperse.ts
  53. 4 4
      vite.config.build.taro.vue.disperse.ts

+ 3 - 0
.gitignore

@@ -11,6 +11,9 @@ package-lock.json
 /src/packages/nutui.vue.build.ts
 /src/packages/nutui.taro.vue.ts
 /src/packages/nutui.taro.vue.build.ts
+src/packages/vscode-extension/node_modules
+src/packages/vscode-extension/*.vsix
+src/packages/vscode-extension/yarn.lock
 /.nyc_output
 /coverage
 /tsc/test

+ 49 - 0
CHANGELOG.md

@@ -1,3 +1,52 @@
+## v3.1.19
+
+`2022-04-25` 此版本依赖 Taro 3.4.x
+
+NutUI 非常感谢您对开源事业做出的贡献!🌷🌷🌷
+本次社区贡献者 @Sun79 @SpringHgui @rocwong-cn @wlchn @Tnon
+
+* :zap: feat: [所有组件国际化支持](https://nutui.jd.com/#/international) @richard1015
+* :zap: feat: tsx 类型支持、[vscode 插件支持](https://marketplace.visualstudio.com/items?itemName=nutui.nutui-vscode-extension) @szg2008
+* :zap: feat: 新增 Comment、Ecard 特色组件 @yangxiaolu1993
+* :zap: feat: 新增 Category、AddressList 特色组件 @ailululu
+* :zap: feat: 根据config.json自动生成taroConfig.ts (#1181)  @yangxiaolu1993
+* :zap: feat: 单选框和复选框支持外部自定义图标 (#1182) @rocwong-cn
+* :zap: feat(numberkeyboard): add custom btn desc (#1176) @SpringHgui
+* :zap: feat(tabbar): tabbar-item add slot (#1173) @Drjingfubo
+* :zap: feat(actionsheet): add new props (#1194) @Drjingfubo
+* :zap: feat(progress): add custom slot (#1196) @Drjingfubo
+* :zap: refactor(circleprogress): add features (#1204) @Drjingfubo
+* :zap: refactor(CountDown): 新增重置、毫秒级展示、自定义格式等功能 @yangxiaolu1993
+* :zap: feat: avatar能力补齐、input doc文档更新 (#1195) @ailululu
+* :zap: feat: build internationalization config @richard1015
+* :zap: feat: Picker与DatePIcker新增插槽 (#1213) @yangxiaolu1993
+* :zap: feat(notify): 增加组件模板调用方式 (#1220) @Ymm0008
+* :zap: feat: 新增collapse组件自定义内容(不折叠)功能 @Ymm0008
+* :zap: feat(list): 虚拟列表增加列表高度可配置(#1199) @szg2008
+* :zap: feat(card): add new props #1198 (#1237) @Drjingfubo
+* :zap: feat(Cascader): 功能补齐 (#1238)  @yangxiaolu1993
+* :zap: feat(popup): 增加底部iphonex适配(#1009) @szg2008
+* :zap: feat(table): tableData customrender by Columns.render (#1234) @Tnon
+* :bug: fix(Cascader): 传入tree 数据 末级数据有重复时 父路径查询错误 #1233 @dongj0316
+* :bug: fix(datePicker): 组件平铺展示不展示问题修改 (#1229) @yangxiaolu1993
+* :bug: fix(elevator): navbar not working in taro h5 (#1175) @Sun79
+* :bug: fix(input): taro的问题+增加demo的三个icon功能 (#1223) @ailululu
+* :bug: fix(uploader): event success、failure add responseText #1212 @richard1015
+* :bug: fix(tabs): init tabs__content index calc error @richard1015
+* :bug: fix(imagepreview): 单元测试调整 (#1163) @JackieScorpio
+* :bug: fix(popup): 修复popup在Taro转H5下的渲染问题 @szg2008
+* :bug: fix(input): show-word-limit default false (#1203) @wlchn
+* :bug: fix(textarea): demo textarea 自适应 (#1201) @Ymm0008
+* :bug: fix(textarea): add rows defaults (#1216) @Ymm0008
+* :bug: fix: taro 3.4.6 sass calc error #1200 @richard1015
+* :bug: fix(uploader): taro h5 env upload error #1096 @richard1015
+* :bug: fix(formitem): class and style cannot be set on the formitem (#1174) @Sun79
+* :bug: fix(input): maxNum 改为 maxLength,文档修改等 (#1188) @Ymm0008
+* :bug: fix(uploader): taro3.4.x android demo style @richard1015
+* :bug: fix(tag): wrong event handler (#1167) @Sun79
+* :bug: fix(numberkeyboard): resolve issues #1091 (#1168) @Drjingfubo
+* :bug: docs: 组件分类顺序排序修改 @yangxiaolu1993
+
 ## v3.1.18
 
 `2022-03-25` 此版本依赖 Taro 3.4.x

+ 105 - 0
jd/createAttributes.js

@@ -0,0 +1,105 @@
+const path = require('path');
+const fs = require('fs');
+const MarkdownIt = require('markdown-it')();
+
+const basePath = path.resolve(__dirname, './../src/packages/__VUE');
+const componentDirs = fs.readdirSync(basePath, 'utf8');
+const TYPE_IDENTIFY_OPEN = 'tbody_open';
+const TYPE_IDENTIFY_CLOSE = 'tbody_close';
+const TR_TYPE_IDENTIFY_OPEN = 'tr_open';
+const TR_TYPE_IDENTIFY_CLOSE = 'tr_close';
+
+const getSubSources = (sources) => {
+  let sourcesMap = [];
+  const startIndex = sources.findIndex((source) => source.type === TYPE_IDENTIFY_OPEN);
+  const endIndex = sources.findIndex((source) => source.type === TYPE_IDENTIFY_CLOSE);
+  sources = sources.slice(startIndex, endIndex + 1);
+  while (sources.filter((source) => source.type === TR_TYPE_IDENTIFY_OPEN).length) {
+    let trStartIndex = sources.findIndex((source) => source.type === TR_TYPE_IDENTIFY_OPEN);
+    let trEndIndex = sources.findIndex((source) => source.type === TR_TYPE_IDENTIFY_CLOSE);
+    sourcesMap.push(sources.slice(trStartIndex, trEndIndex + 1));
+    sources.splice(trStartIndex, trEndIndex - trStartIndex + 1);
+  }
+  return sourcesMap;
+};
+
+const genaratorTags = () => {
+  let componentTags = {};
+  if (!componentDirs.length) return;
+
+  for (let componentDir of componentDirs) {
+    let stat = fs.lstatSync(`${basePath}/${componentDir}`);
+    if (stat.isDirectory()) {
+      const absolutePath = path.join(`${basePath}/${componentDir}`, 'doc.md');
+      if (!fs.existsSync(absolutePath)) continue;
+      const data = fs.readFileSync(absolutePath, 'utf8');
+      let sources = MarkdownIt.parse(data, {});
+      let sourcesMap = getSubSources(sources);
+      componentTags[`nut-${componentDir}`] = { attributes: [] };
+      for (let sourceMap of sourcesMap) {
+        let propItem = sourceMap.filter((source) => source.type === 'inline').length
+          ? `${sourceMap.filter((source) => source.type === 'inline')[0].content}`
+          : '';
+        componentTags[`nut-${componentDir}`]['attributes'].push(propItem);
+      }
+    }
+  }
+
+  return componentTags;
+};
+
+const genaratorAttributes = () => {
+  let componentTags = {};
+  if (!componentDirs.length) return;
+  for (let componentDir of componentDirs) {
+    let stat = fs.lstatSync(`${basePath}/${componentDir}`);
+    if (stat.isDirectory()) {
+      const absolutePath = path.join(`${basePath}/${componentDir}`, 'doc.md');
+      if (!fs.existsSync(absolutePath)) continue;
+      const data = fs.readFileSync(absolutePath, 'utf8');
+      let sources = MarkdownIt.parse(data, {});
+      let sourcesMap = getSubSources(sources);
+      for (let sourceMap of sourcesMap) {
+        const inlineItem = sourceMap.filter((source) => source.type === 'inline').length
+          ? sourceMap.filter((source) => source.type === 'inline')
+          : [];
+        const propItem = inlineItem.length ? `${inlineItem[0].content}` : '';
+        const infoItem = inlineItem.length ? `${inlineItem[1].content}` : '';
+        const typeItem = inlineItem.length ? `${inlineItem[2].content.toLowerCase()}` : '';
+        const defaultItem = inlineItem.length ? `${inlineItem[3].content}` : '';
+        componentTags[`nut-${componentDir}/${propItem}`] = {
+          type: `${typeItem}`,
+          description: `属性说明:${infoItem},默认值:${defaultItem}`
+        };
+      }
+    }
+  }
+
+  return componentTags;
+};
+
+const writeTags = () => {
+  const componentTags = genaratorTags();
+  let innerText = `${JSON.stringify(componentTags, null, 2)}`;
+  const distPath = path.resolve(__dirname, './../dist');
+  const componentTagsPath = path.resolve(__dirname, './../dist/smartips/tags.json');
+  if (!fs.existsSync(path.join(distPath + '/smartips'))) {
+    fs.mkdirSync(path.join(distPath + '/smartips'));
+  }
+
+  fs.writeFileSync(componentTagsPath, innerText);
+};
+
+const writeAttributes = () => {
+  const componentAttributes = genaratorAttributes();
+  let innerText = `${JSON.stringify(componentAttributes, null, 2)}`;
+  const distPath = path.resolve(__dirname, './../dist');
+  const componentAttributespPath = path.resolve(__dirname, './../dist/smartips/attributes.json');
+  if (!fs.existsSync(path.join(distPath + '/smartips'))) {
+    fs.mkdirSync(path.join(distPath + '/smartips'));
+  }
+  fs.writeFileSync(componentAttributespPath, innerText);
+};
+
+writeTags();
+writeAttributes();

+ 9 - 4
package.json

@@ -1,11 +1,15 @@
 {
   "name": "@nutui/nutui",
-  "version": "3.1.18",
+  "version": "3.1.20",
   "description": "京东风格的轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)",
   "main": "dist/nutui.umd.js",
   "module": "dist/nutui.es.js",
   "style": "dist/style.css",
   "typings": "dist/types/index.d.ts",
+  "vetur": {
+    "tags": "dist/smartips/tags.json",
+    "attributes": "dist/smartips/attributes.json"
+  },
   "keywords": [
     "nutui",
     "nutui2",
@@ -40,8 +44,8 @@
     "dev:taro:h5": "npm run createTaroConfig && 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 && vite build --config vite.config.build.locale.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 && vite build --config vite.config.build.locale.ts",
+    "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 && vite build --config vite.config.build.locale.ts && npm run attrs",
+    "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 && vite build --config vite.config.build.locale.ts && npm run attrs",
     "serve": "vite preview",
     "upload": "yarn build:site:oss && node ./jd/upload.js",
     "add": "node jd/createComponentMode.js",
@@ -57,7 +61,8 @@
     "release": "standard-version -a",
     "codeformat": "prettier --write .",
     "copydocs": "node ./jd/copymd.js",
-    "createTaroConfig": "node ./jd/generate-taro-route.js"
+    "createTaroConfig": "node ./jd/generate-taro-route.js",
+    "attrs": "node ./jd/createAttributes.js"
   },
   "standard-version": {
     "scripts": {

+ 6 - 1
src/config.json

@@ -28,6 +28,11 @@
         "show": true
       },
       {
+        "name": "ide",
+        "cName": "开发工具支持",
+        "show": true
+      },
+      {
         "name": "resource",
         "cName": "资源",
         "show": true
@@ -407,7 +412,7 @@
         {
           "name": "Cascader",
           "type": "component",
-          "cName": "级联选择",
+          "cName": "级联选择",
           "desc": "级联选择,用于多层级数据的选择,典型场景为省市区选择.",
           "sort": 23,
           "show": true,

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

@@ -1,6 +1,5 @@
 # ActionSheet 动作面板
 
-
 ### 介绍
 从底部弹出的动作菜单面板。
 
@@ -275,7 +274,6 @@ export default {
 | description      | 设置列表项副标题/描述                  | String  | ''        |
 | cancel-txt       | 取消文案                               | String  | '取消'   |
 | close-abled      | 遮罩层是否可关闭                       | Boolean | true      |
-|safe-area-inset-bottom	|是否开启iphone系列全面屏底部安全区适配|	Boolean	|false
 
 ## menu-items数据结构
 

+ 0 - 4
src/packages/__VUE/actionsheet/index.scss

@@ -1,9 +1,5 @@
 .nut-actionsheet-panel {
   display: block;
-  &.nut-actionsheet-safebottom {
-    margin-bottom: constant(safe-area-inset-bottom);
-    margin-bottom: env(safe-area-inset-bottom);
-  }
   .nut-actionsheet-title {
     display: block;
     padding: 10px;

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

@@ -1,7 +1,7 @@
 <template>
   <view :class="classes">
     <nut-popup pop-class="popclass" :visible="visible" position="bottom" round @click-overlay="close">
-      <view class="nut-actionsheet-panel" :class="{ 'nut-actionsheet-safebottom': safeAreaInsetBottom }">
+      <view class="nut-actionsheet-panel">
         <view v-if="title" class="nut-actionsheet-title">{{ title }}</view>
         <slot></slot>
         <view v-if="!slotDefault">
@@ -67,10 +67,6 @@ export default create({
     menuItems: {
       type: Array,
       default: () => []
-    },
-    safeAreaInsetBottom: {
-      type: Boolean,
-      default: false
     }
   },
   emits: ['cancel', 'choose', 'update:visible', 'close'],

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

@@ -8,7 +8,7 @@
       round
       @click-overlay="close"
     >
-      <view class="nut-actionsheet-panel" :class="{ 'nut-actionsheet-safebottom': safeAreaInsetBottom }">
+      <view class="nut-actionsheet-panel">
         <view v-if="title" class="nut-actionsheet-title">{{ title }}</view>
         <slot></slot>
         <view v-if="!slotDefault">
@@ -78,10 +78,6 @@ export default create({
     isWrapTeleport: {
       type: Boolean,
       default: true
-    },
-    safeAreaInsetBottom: {
-      type: Boolean,
-      default: false
     }
   },
   emits: ['cancel', 'close', 'choose', 'update:visible'],

+ 1 - 25
src/packages/__VUE/cascader/__tests__/cascader.spec.ts

@@ -193,32 +193,8 @@ describe('Tree', () => {
 
   const tree = new Tree(mockOptions);
 
-  test('getNodeByValue', () => {
-    const node = tree.getNodeByValue('西湖区');
-    expect(node).toBeTruthy();
-    expect(node).toMatchObject({ text: '西湖区', value: '西湖区' });
-  });
-
-  test('getPathNodesByNode', () => {
-    const node = tree.getNodeByValue('西湖区') as CascaderOption;
-    expect(node).toBeTruthy();
-    expect(node.value).toBe('西湖区');
-
-    const pathNodes = tree.getPathNodesByNode(node as CascaderOption);
-    const mappedPathNodes = pathNodes.map(({ text, value }) => ({
-      text,
-      value
-    }));
-
-    expect(mappedPathNodes).toMatchObject([
-      { text: '浙江', value: '浙江' },
-      { text: '杭州', value: '杭州' },
-      { text: '西湖区', value: '西湖区' }
-    ]);
-  });
-
   test('getPathNodesByValue', () => {
-    const pathNodes = tree.getPathNodesByValue(['杭州', '杭州', '西湖区']);
+    const pathNodes = tree.getPathNodesByValue(['浙江', '杭州', '西湖区']);
     const mappedPathNodes = pathNodes.map(({ text, value }) => ({
       text,
       value

+ 2 - 0
src/packages/__VUE/cascader/demo.vue

@@ -19,6 +19,8 @@
           @change="events.change"
           @path-change="events.pathChange"
           :options="demo1.options"
+          close-icon="heart"
+          close-icon-position="top-left"
         ></nut-cascader>
       </nut-form-item>
     </nut-form>

+ 4 - 0
src/packages/__VUE/cascader/doc.md

@@ -429,6 +429,10 @@ export default {
 | text-key       | 自定义`options`结构中`text`的字段                     | String   | -      |
 | children-key   | 自定义`options`结构中`children`的字段                 | String   | -      |
 | convert-config | 当options为可转换为树形结构的扁平结构时,配置转换规则 | Object   | -      |
+| title | 标题 | String   | ''      |
+| close-icon-position | 取消按钮位置,继承 Popup 组件 | String   | "top-right"      |
+| close-icon | 自定义关闭按钮,继承 Popup 组件 | String   | "close"     |
+| closeable | 是否显示关闭按钮,继承 Popup 组件 | Boolean   | true     |
 
 ### Events
 

+ 6 - 2
src/packages/__VUE/cascader/index.taro.vue

@@ -4,11 +4,13 @@
     position="bottom"
     pop-class="nut-cascader__popup"
     round
-    :closeable="true"
+    :closeable="!closeable"
+    :close-icon="closeIcon"
     :destroy-on-close="false"
+    :close-icon-position="closeIconPosition"
   >
     <template v-if="title">
-      <view class="nut-cascader__bar">{{ title }}</view>
+      <view class="nut-cascader__bar" v-html="title"></view>
     </template>
 
     <nut-cascader-item
@@ -30,6 +32,7 @@
 import { watch, ref, Ref, computed } from 'vue';
 import { CascaderValue, CascaderOption } from './types';
 import { createComponent } from '@/packages/utils/create';
+import { popupProps } from '../popup/index.vue';
 const { create } = createComponent('cascader');
 import CascaderItem from './cascader-item.vue';
 
@@ -38,6 +41,7 @@ export default create({
     [CascaderItem.name]: CascaderItem
   },
   props: {
+    ...popupProps,
     modelValue: Array,
     visible: Boolean,
     title: String,

+ 6 - 2
src/packages/__VUE/cascader/index.vue

@@ -4,11 +4,13 @@
     position="bottom"
     pop-class="nut-cascader__popup"
     round
-    :closeable="true"
+    :closeable="!closeable"
+    :close-icon="closeIcon"
     :destroy-on-close="false"
+    :close-icon-position="closeIconPosition"
   >
     <template v-if="title">
-      <view class="nut-cascader__bar">{{ title }}</view>
+      <view class="nut-cascader__bar" v-html="title"></view>
     </template>
 
     <nut-cascader-item
@@ -29,6 +31,7 @@
 <script lang="ts">
 import { watch, ref, Ref, computed } from 'vue';
 import { CascaderValue, CascaderOption } from './types';
+import { popupProps } from '../popup/index.vue';
 import { createComponent } from '@/packages/utils/create';
 const { create } = createComponent('cascader');
 import CascaderItem from './cascader-item.vue';
@@ -38,6 +41,7 @@ export default create({
     [CascaderItem.name]: CascaderItem
   },
   props: {
+    ...popupProps,
     modelValue: Array,
     visible: Boolean,
     title: String,

+ 14 - 17
src/packages/__VUE/cascader/tree.ts

@@ -23,6 +23,7 @@ class Tree {
     }
   }
 
+  // for test
   getNodeByValue(value: CascaderOption['value']): CascaderOption | void {
     let foundNode;
     eachTree(this.nodes, (node: CascaderOption) => {
@@ -35,30 +36,26 @@ class Tree {
     return foundNode;
   }
 
-  getPathNodesByNode(node: CascaderOption): CascaderOption[] {
-    const nodes = [];
-
-    while (node) {
-      nodes.unshift(node);
-      node = node._parent;
-    }
-
-    return nodes;
-  }
-
   getPathNodesByValue(value: CascaderValue): CascaderOption[] {
-    if (Array.isArray(value) && !value.length) {
+    if (!value.length) {
       return [];
     }
 
-    const tail = Array.isArray(value) ? value[value.length - 1] : value;
+    const pathNodes = [];
+    let currentNodes: CascaderOption[] | void = this.nodes;
 
-    const node = this.getNodeByValue(tail);
-    if (!node) {
-      return [];
+    while (currentNodes && currentNodes.length) {
+      const foundNode: CascaderOption | void = currentNodes.find((node) => node.value === value[node.level as number]);
+
+      if (!foundNode) {
+        break;
+      }
+
+      pathNodes.push(foundNode);
+      currentNodes = foundNode.children;
     }
 
-    return this.getPathNodesByNode(node);
+    return pathNodes;
   }
 
   isLeaf(node: CascaderOption, lazy: boolean): boolean {

+ 4 - 4
src/packages/__VUE/category/index.scss

@@ -5,7 +5,7 @@
   }
 
   &__cateListLeft {
-    background: $cateListLeft-bg-color;
+    background: $category-ListLeft-bg-color;
   }
 
   &__cateListItemChecked,
@@ -15,14 +15,14 @@
     font-size: 13px;
     font-family: PingFangSC;
     font-weight: normal;
-    color: $cateListItem-color;
+    color: $category-ListItem-color;
     display: flex;
     justify-content: center;
     align-items: center;
     transition: all 0.3s;
   }
   &__cateListItemChecked {
-    background: $cateListItemChecked-color;
+    background: $category-ListItemChecked-color;
     font-weight: 500;
     transition: all 0.3s;
     position: relative;
@@ -32,7 +32,7 @@
       left: 0;
       width: 5px;
       height: 18px;
-      background: $cateListItemChecked-img-bg-color;
+      background: $category-ListItemChecked-img-bg-color;
     }
   }
 }

+ 1 - 1
src/packages/__VUE/circleprogress/doc.md

@@ -1,4 +1,4 @@
-# CircleProgress 进度条
+# CircleProgress 环形进度条
 
 ### 介绍
 

+ 4 - 4
src/packages/__VUE/circleprogress/index.scss

@@ -2,12 +2,12 @@
   position: relative;
 
   &-hover {
-    stroke: $circle-progress-primary-color;
+    stroke: $circleprogress-primary-color;
     transition: stroke-dasharray 0.6s ease 0s, stroke 0.6s ease 0s;
   }
 
   &-path {
-    stroke: $circle-progress-path-color;
+    stroke: $circleprogress-path-color;
   }
 
   &-text {
@@ -18,7 +18,7 @@
     width: 100%;
     transform: translateY(-50%);
     text-align: center;
-    color: $circle-progress-text-color;
-    font-size: $circle-progress-text-size;
+    color: $circleprogress-text-color;
+    font-size: $circleprogress-text-size;
   }
 }

+ 5 - 5
src/packages/__VUE/comment/index.scss

@@ -29,7 +29,7 @@
         @include oneline-ellipsis();
         margin-right: 5px;
         font-size: 12px;
-        color: $cmt-header-user-name-color;
+        color: $comment-header-user-name-color;
         width: auto;
         max-width: 80px;
       }
@@ -43,7 +43,7 @@
 
           @include oneline-ellipsis();
           font-size: 12px;
-          color: $cmt-header-user-name-color;
+          color: $comment-header-user-name-color;
 
           > span {
             margin-right: 8px;
@@ -79,7 +79,7 @@
       width: 100px;
       text-align: right;
       font-size: 12px;
-      color: $cmt-header-time-color;
+      color: $comment-header-time-color;
     }
 
     &__complex-score {
@@ -248,7 +248,7 @@
   &-bottom {
     display: flex;
     justify-content: space-between;
-    color: $cmt-bottom-label-color;
+    color: $comment-bottom-label-color;
     margin-right: 5px;
 
     &__lable {
@@ -347,7 +347,7 @@
     border-top: 1px solid rgba(0, 0, 0, 0.1);
     @include moreline-ellipsis(6);
     span {
-      color: $cmt-shop-color;
+      color: $comment-shop-color;
     }
   }
 }

+ 1 - 0
src/packages/__VUE/popup/doc.md

@@ -186,6 +186,7 @@ app.use(Popup).use(OverLay)
 | destroy-on-close       | 弹层关闭后 `slot`内容会不会清空                                          | Boolean        | `true`        |
 | round                  | 是否显示圆角                                                | Boolean        | `false`       |
 | teleport               | 指定挂载节点(`小程序不支持`)                                                | String         | `"body"`      |
+| safe-area-inset-bottom `v3.1.19`	| 是否开启 iphone 系列全面屏底部安全区适配,仅当 `position` 为 `bottom` 时有效 |	Boolean	|`false`     |
 
 ### Events
 

+ 4 - 0
src/packages/__VUE/popup/index.scss

@@ -46,6 +46,10 @@
   &.round {
     border-radius: $popup-border-radius $popup-border-radius 0 0;
   }
+  &--safebottom {
+    padding-bottom: constant(safe-area-inset-bottom);
+    padding-bottom: env(safe-area-inset-bottom);
+  }
 }
 
 .popup-right {

+ 5 - 0
src/packages/__VUE/popup/index.taro.vue

@@ -89,6 +89,10 @@ export const popupProps = {
   round: {
     type: Boolean,
     default: false
+  },
+  safeAreaInsetBottom: {
+    type: Boolean,
+    default: false
   }
 };
 export default create({
@@ -117,6 +121,7 @@ export default create({
         [prefixCls]: true,
         ['round']: props.round,
         [`popup-${props.position}`]: true,
+        [`popup-${props.position}--safebottom`]: props.position === 'bottom' && props.safeAreaInsetBottom,
         [props.popClass]: true
       };
     });

+ 5 - 0
src/packages/__VUE/popup/index.vue

@@ -131,6 +131,10 @@ export const popupProps = {
   isWrapTeleport: {
     type: Boolean,
     default: true
+  },
+  safeAreaInsetBottom: {
+    type: Boolean,
+    default: false
   }
 };
 export default create({
@@ -161,6 +165,7 @@ export default create({
         [prefixCls]: true,
         ['round']: props.round,
         [`popup-${props.position}`]: true,
+        [`popup-${props.position}--safebottom`]: props.position === 'bottom' && props.safeAreaInsetBottom,
         [props.popClass]: true
       };
     });

+ 0 - 1
src/packages/__VUE/swiperitem/index.taro.vue

@@ -15,7 +15,6 @@ interface IStyle {
   transform?: string;
 }
 export default create({
-  props: {},
   setup(props, { slots }) {
     const parent = inject('parent') as any;
     parent['relation'](getCurrentInstance());

+ 0 - 1
src/packages/__VUE/swiperitem/index.vue

@@ -15,7 +15,6 @@ interface IStyle {
   transform?: string;
 }
 export default create({
-  props: {},
   setup(props, { slots }) {
     const parent = inject('parent') as any;
     parent['relation'](getCurrentInstance());

+ 2 - 2
src/packages/__VUE/table/common.ts

@@ -69,8 +69,8 @@ export const component = (componentName: string, translate: Function) => {
       };
 
       const sortDataItem = () => {
-        return props.columns.map((value: any) => {
-          return value.key;
+        return props.columns.map((columns: TableColumnProps) => {
+          return [columns.key, columns.render];
         });
       };
 

+ 12 - 1
src/packages/__VUE/table/demo.vue

@@ -50,7 +50,18 @@ export default createDemo({
         },
         {
           title: '性别',
-          key: 'sex'
+          key: 'sex',
+          render: ({ sex }) => {
+            return h(
+              'span',
+              {
+                style: {
+                  color: sex === '女' ? 'blue' : 'green'
+                }
+              },
+              sex
+            );
+          }
         },
         {
           title: '学历',

+ 298 - 287
src/packages/__VUE/table/doc.md

@@ -6,7 +6,7 @@
 
 ### 安装
 
-``` javascript
+```javascript
 import { createApp } from 'vue';
 // vue
 import { Table } from '@nutui/nutui';
@@ -32,42 +32,53 @@ app.use(Table);
   export default {
     props: {},
     setup() {
-        const state = reactive({
-            columns: [
-            {
-              title: '姓名',
-              key: 'name'
-            },
-            {
-              title: '性别',
-              key: 'sex'
-            },
-            {
-              title: '学历',
-              key: 'record'
-            }
-          ],
-          data: [
-            {
-              name: 'Tom',
-              sex: '男',
-              record: '小学'
-            },
-            {
-              name: 'Lucy',
-              sex: '女',
-              record: '本科'
-            },
-            {
-              name: 'Jack',
-              sex: '男',
-              record: '高中'
+      const state = reactive({
+        columns: [
+          {
+            title: '姓名',
+            key: 'name'
+          },
+          {
+            title: '性别',
+            key: 'sex',
+            render: (record) => {
+              return h(
+                'span',
+                {
+                  style: {
+                    color: record.sex === '女' ? 'blue' : 'green'
+                  }
+                },
+                record.sex
+              );
             }
-          ],
-        });
-        return {
-            ...toRefs(state),
-        };
+          },
+          {
+            title: '学历',
+            key: 'record'
+          }
+        ],
+        data: [
+          {
+            name: 'Tom',
+            sex: '男',
+            record: '小学'
+          },
+          {
+            name: 'Lucy',
+            sex: '女',
+            record: '本科'
+          },
+          {
+            name: 'Jack',
+            sex: '男',
+            record: '高中'
+          }
+        ]
+      });
+      return {
+        ...toRefs(state)
+      };
     }
   };
 </script>
@@ -88,44 +99,44 @@ app.use(Table);
   export default {
     props: {},
     setup() {
-        const state = reactive({
-            bordered: false,
-            columns: [
-            {
-              title: '姓名',
-              key: 'name',
-              align: 'center'
-            },
-            {
-              title: '性别',
-              key: 'sex'
-            },
-            {
-              title: '学历',
-              key: 'record'
-            }
-          ],
-          data: [
-            {
-              name: 'Tom',
-              sex: '男',
-              record: '小学'
-            },
-            {
-              name: 'Lucy',
-              sex: '女',
-              record: '本科'
-            },
-            {
-              name: 'Jack',
-              sex: '男',
-              record: '高中'
-            }
-          ],
-        });
-        return {
-            ...toRefs(state),
-        };
+      const state = reactive({
+        bordered: false,
+        columns: [
+          {
+            title: '姓名',
+            key: 'name',
+            align: 'center'
+          },
+          {
+            title: '性别',
+            key: 'sex'
+          },
+          {
+            title: '学历',
+            key: 'record'
+          }
+        ],
+        data: [
+          {
+            name: 'Tom',
+            sex: '男',
+            record: '小学'
+          },
+          {
+            name: 'Lucy',
+            sex: '女',
+            record: '本科'
+          },
+          {
+            name: 'Jack',
+            sex: '男',
+            record: '高中'
+          }
+        ]
+      });
+      return {
+        ...toRefs(state)
+      };
     }
   };
 </script>
@@ -146,62 +157,62 @@ app.use(Table);
   export default {
     props: {},
     setup() {
-        const state = reactive({
-            columns: [
-            {
-              title: '姓名',
-              key: 'name'
-            },
-            {
-              title: '性别',
-              key: 'sex'
-            },
-            {
-              title: '学历',
-              key: 'record'
-            },
-            {
-              title: '年龄',
-              key: 'age'
-            },
-            {
-              title: '地址',
-              key: 'address'
-            }
-          ],
-          data: [
-            {
-              name: 'Tom',
-              sex: '男',
-              record: '小学',
-              age: 13,
-              address: '北京'
-            },
-            {
-              name: 'Lucy',
-              sex: '女',
-              record: '本科',
-              age: 34,
-              address: '上海'
-            },
-            {
-              name: 'Jack',
-              sex: '男',
-              record: '高中',
-              age: 4,
-              address: '杭州'
-            }
-          ],
-          summary: () => {
-            return {
-              value: '这是总结栏',
-              colspan: 5
-            }
+      const state = reactive({
+        columns: [
+          {
+            title: '姓名',
+            key: 'name'
+          },
+          {
+            title: '性别',
+            key: 'sex'
+          },
+          {
+            title: '学历',
+            key: 'record'
+          },
+          {
+            title: '年龄',
+            key: 'age'
+          },
+          {
+            title: '地址',
+            key: 'address'
+          }
+        ],
+        data: [
+          {
+            name: 'Tom',
+            sex: '男',
+            record: '小学',
+            age: 13,
+            address: '北京'
+          },
+          {
+            name: 'Lucy',
+            sex: '女',
+            record: '本科',
+            age: 34,
+            address: '上海'
+          },
+          {
+            name: 'Jack',
+            sex: '男',
+            record: '高中',
+            age: 4,
+            address: '杭州'
           }
-        });
-        return {
-            ...toRefs(state),
-        };
+        ],
+        summary: () => {
+          return {
+            value: '这是总结栏',
+            colspan: 5
+          };
+        }
+      });
+      return {
+        ...toRefs(state)
+      };
     }
   };
 </script>
@@ -222,57 +233,57 @@ app.use(Table);
   export default {
     props: {},
     setup() {
-        const state = reactive({
-          striped: true,
-          columns3: [
-            {
-              title: '姓名',
-              key: 'name'
-            },
-            {
-              title: '性别',
-              key: 'sex'
-            },
-            {
-              title: '学历',
-              key: 'record'
-            },
-            {
-              title: '年龄',
-              key: 'age'
-            },
-            {
-              title: '地址',
-              key: 'address'
-            }
-          ],
-          data2: [
-            {
-              name: 'Tom',
-              sex: '男',
-              record: '小学',
-              age: 13,
-              address: '北京'
-            },
-            {
-              name: 'Lucy',
-              sex: '女',
-              record: '本科',
-              age: 34,
-              address: '上海'
-            },
-            {
-              name: 'Jack',
-              sex: '男',
-              record: '高中',
-              age: 4,
-              address: '杭州'
-            }
-          ]
-        });
-        return {
-            ...toRefs(state),
-        };
+      const state = reactive({
+        striped: true,
+        columns3: [
+          {
+            title: '姓名',
+            key: 'name'
+          },
+          {
+            title: '性别',
+            key: 'sex'
+          },
+          {
+            title: '学历',
+            key: 'record'
+          },
+          {
+            title: '年龄',
+            key: 'age'
+          },
+          {
+            title: '地址',
+            key: 'address'
+          }
+        ],
+        data2: [
+          {
+            name: 'Tom',
+            sex: '男',
+            record: '小学',
+            age: 13,
+            address: '北京'
+          },
+          {
+            name: 'Lucy',
+            sex: '女',
+            record: '本科',
+            age: 34,
+            address: '上海'
+          },
+          {
+            name: 'Jack',
+            sex: '男',
+            record: '高中',
+            age: 4,
+            address: '杭州'
+          }
+        ]
+      });
+      return {
+        ...toRefs(state)
+      };
     }
   };
 </script>
@@ -288,11 +299,9 @@ app.use(Table);
 <template>
   <nut-table :columns="columns" :data="data"></nut-table>
   <nut-table :columns="columns3" :data="data3">
-      <template #nodata>
-      <div class="no-data">
-          这里是自定义展示
-      </div>
-      </template>
+    <template #nodata>
+      <div class="no-data"> 这里是自定义展示 </div>
+    </template>
   </nut-table>
 </template>
 <script lang="ts">
@@ -345,13 +354,13 @@ app.use(Table);
             key: 'address'
           }
         ],
-        data3: [],
+        data3: []
       });
       return {
-          ...toRefs(state),
+        ...toRefs(state)
       };
     }
-  }
+  };
 </script>
 ```
 
@@ -370,78 +379,78 @@ app.use(Table);
   import { Button, Icon } from '@nutui/nutui';
   export default {
     setup() {
-        const state = reactive({
-          columns: [
-            {
-              title: '姓名',
-              key: 'name',
-              align: 'center'
-            },
-            {
-              title: '性别',
-              key: 'sex'
-            },
-            {
-              title: '学历',
-              key: 'record'
-            },
-            {
-              title: '操作',
-              key: 'render'
-            }
-          ],
-          data: [
-              {
-              name: 'Tom',
-              sex: '男',
-              record: '小学',
-              render: () => {
-                return h(
-                  Button,
-                  {
-                    onClick: () => {
-                      (Toast as any).text('hello');
-                    },
-                    size: 'small',
-                    type: 'primary'
-                  },
-                  'Hello'
-                );
-              }
-            },
-            {
-              name: 'Lucy',
-              sex: '女',
-              record: '本科',
-              render: () => {
-                return h(Icon, { name: 'dongdong', size: '14px' });
-              }
-            },
-            {
-              name: 'Jack',
-              sex: '男',
-              record: '高中',
-              render: () => {
-                return h(
-                  Button,
-                  {
-                    type: 'success',
-                    size: 'small',
-                    onClick: () => {
-                      window.open('https://www.jd.com');
-                    }
+      const state = reactive({
+        columns: [
+          {
+            title: '姓名',
+            key: 'name',
+            align: 'center'
+          },
+          {
+            title: '性别',
+            key: 'sex'
+          },
+          {
+            title: '学历',
+            key: 'record'
+          },
+          {
+            title: '操作',
+            key: 'render'
+          }
+        ],
+        data: [
+          {
+            name: 'Tom',
+            sex: '男',
+            record: '小学',
+            render: () => {
+              return h(
+                Button,
+                {
+                  onClick: () => {
+                    (Toast as any).text('hello');
                   },
-                  '跳转到京东'
-                );
-              }
+                  size: 'small',
+                  type: 'primary'
+                },
+                'Hello'
+              );
             }
-          ]
-        });
-        return {
-            ...toRefs(state),
-        };
+          },
+          {
+            name: 'Lucy',
+            sex: '女',
+            record: '本科',
+            render: () => {
+              return h(Icon, { name: 'dongdong', size: '14px' });
+            }
+          },
+          {
+            name: 'Jack',
+            sex: '男',
+            record: '高中',
+            render: () => {
+              return h(
+                Button,
+                {
+                  type: 'success',
+                  size: 'small',
+                  onClick: () => {
+                    window.open('https://www.jd.com');
+                  }
+                },
+                '跳转到京东'
+              );
+            }
+          }
+        ]
+      });
+      return {
+        ...toRefs(state)
+      };
     }
-  }
+  };
 </script>
 ```
 
@@ -510,15 +519,15 @@ app.use(Table);
         ]
       });
       onMounted(() => {
-          setTimeout(() => {
-              state.data = state.data1.slice();
-          }, 5000);
+        setTimeout(() => {
+          state.data = state.data1.slice();
+        }, 5000);
       });
       return {
-          ...toRefs(state),
+        ...toRefs(state)
       };
     }
-  }
+  };
 </script>
 ```
 
@@ -547,7 +556,7 @@ app.use(Table);
           },
           {
             title: '性别',
-            key: 'sex',
+            key: 'sex'
           },
           {
             title: '学历',
@@ -556,7 +565,9 @@ app.use(Table);
           {
             title: '年龄',
             key: 'age',
-            sorter: (row1: any, row2: any) => { return row1.age - row2.age }
+            sorter: (row1: any, row2: any) => {
+              return row1.age - row2.age;
+            }
           }
         ],
         data: [
@@ -580,17 +591,17 @@ app.use(Table);
           }
         ]
       });
-      
+
       const handleSorter = (item: TableColumnProps) => {
         (Toast as any).text(`${JSON.stringify(item)}`);
-      }
+      };
 
       return {
-          ...toRefs(state),
-          handleSorter
+        ...toRefs(state),
+        handleSorter
       };
-  }
-  }
+    }
+  };
 </script>
 ```
 
@@ -600,26 +611,26 @@ app.use(Table);
 
 ### Props
 
-| 参数         | 说明                             | 类型   | 默认值           |
-|--------------|----------------------------------|--------|------------------|
-| bordered         | 是否显示边框 | Boolean |`true`         |
-| columns         | 表头数据 | TableColumnProps[] |`[]`         |
-| data         | 表格数据 | Object[] |`[]`         |
-| summary         | 是否显示简介 | Function | -         |
-| striped         | 条纹是否明暗交替 | Boolean |`false` |
+| 参数     | 说明             | 类型               | 默认值  |
+| -------- | ---------------- | ------------------ | ------- |
+| bordered | 是否显示边框     | Boolean            | `true`  |
+| columns  | 表头数据         | TableColumnProps[] | `[]`    |
+| data     | 表格数据         | Object[]           | `[]`    |
+| summary  | 是否显示简介     | Function           | -       |
+| striped  | 条纹是否明暗交替 | Boolean            | `false` |
 
 ### TableColumnProps
 
-| 参数         | 说明                             | 类型   | 默认值           |
-|--------------|----------------------------------|--------|------------------|
-| key         | 列的唯一标识 | String |``  |
-| title         | 表头标题 | String |``         |
-| align         | 列的对齐方式,可选值`left`,`center`,`right` | String |`left`         |
-| sorter         | 排序,可选值有 `true`,`function`, `default`, 其中 `default`表示点击之后可能会依赖接口, `function`可以返回具体的排序函数, `default`表示采用默认的排序算法 | Boolean、Function、String |-|
+| 参数   | 说明                                                                                                                                                     | 类型                      | 默认值 |
+| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ------ |
+| key    | 列的唯一标识                                                                                                                                             | String                    | ``     |
+| title  | 表头标题                                                                                                                                                 | String                    | ``     |
+| align  | 列的对齐方式,可选值`left`,`center`,`right`                                                                                                              | String                    | `left` |
+| sorter | 排序,可选值有 `true`,`function`, `default`, 其中 `default`表示点击之后可能会依赖接口, `function`可以返回具体的排序函数, `default`表示采用默认的排序算法 | Boolean、Function、String | -      |
+| render | 自定义渲染列数据,优先级高                                                                                                                               | Function(record)          | -      |
 
 ### Events
 
-| 事件名 | 说明           | 回调参数     |
-|--------|----------------|--------------|
-| sorter  | 点击排序按钮触发 | item: 当前点击的表头的数据 |
-
+| 事件名 | 说明             | 回调参数                   |
+| ------ | ---------------- | -------------------------- |
+| sorter | 点击排序按钮触发 | item: 当前点击的表头的数据 |

+ 9 - 3
src/packages/__VUE/table/index.taro.vue

@@ -21,11 +21,17 @@
           <span
             class="nut-table__main__body__tr__td"
             :class="cellClasses(getColumnItem(value))"
-            v-for="value in sortDataItem()"
+            v-for="[value, render] in sortDataItem()"
             :key="value"
           >
-            <RenderColumn :slots="item[value]" v-if="typeof item[value] === 'function'"></RenderColumn>
-            <view v-else> {{ item[value] }} </view>
+            <RenderColumn
+              :slots="[render, item[value]]"
+              :record="item"
+              v-if="typeof item[value] === 'function' || typeof render === 'function'"
+            ></RenderColumn>
+            <view v-else>
+              {{ item[value] }}
+            </view>
           </span>
         </view>
       </view>

+ 9 - 3
src/packages/__VUE/table/index.vue

@@ -21,11 +21,17 @@
           <span
             class="nut-table__main__body__tr__td"
             :class="cellClasses(getColumnItem(value))"
-            v-for="value in sortDataItem()"
+            v-for="[value, render] in sortDataItem()"
             :key="value"
           >
-            {{ typeof item[value] !== 'function' ? item[value] : '' }}
-            <RenderColumn :slots="item[value]" v-if="typeof item[value] === 'function'"></RenderColumn>
+            <RenderColumn
+              :slots="[render, item[value]]"
+              :record="item"
+              v-if="typeof item[value] === 'function' || typeof render === 'function'"
+            ></RenderColumn>
+            <view v-else>
+              {{ item[value] }}
+            </view>
           </span>
         </view>
       </view>

+ 4 - 3
src/packages/__VUE/table/renderColumn.ts

@@ -1,9 +1,10 @@
-import { h } from 'vue';
+import { h, PropType } from 'vue';
 export default {
   setup(props: any) {
-    return () => h(`view`, {}, props.slots());
+    return () => h(`view`, {}, props.slots[0] ? props.slots[0](props.record) : props.slots[1](props.record));
   },
   props: {
-    slots: Function
+    slots: Array as PropType<Array<Function | undefined>>,
+    record: Object
   }
 };

+ 2 - 2
src/packages/__VUE/table/types.ts

@@ -1,10 +1,10 @@
-import { VNodeChild } from 'vue';
+import { VNode, VNodeChild } from 'vue';
 export interface TableColumnProps {
   key?: string;
   title?: string;
   align?: string;
   sorter?: Function;
-  render?: (rowData: object, rowIndex: number) => VNodeChild | string;
+  render?: (rowData?: object, rowIndex?: number) => VNodeChild | string | VNode;
 }
 
 export interface TableProps {

+ 14 - 9
src/packages/styles/variables-jdt.scss

@@ -729,17 +729,22 @@ $ecard-bg-color: #f0f2f5 !default;
 
 //category
 $category-bg-color: rgba(255, 255, 255, 1) !default;
-$cateListLeft-bg-color: rgba(246, 247, 249, 1) !default;
-$cateListItem-color: rgba(51, 51, 51, 1) !default;
-$cateListItemChecked-color: rgba(255, 255, 255, 1) !default;
-$cateListItem-color: rgba(51, 51, 51, 1) !default;
-$cateListItemChecked-img-bg-color: rgba(240, 37, 15, 1) !default;
+$category-ListLeft-bg-color: rgba(246, 247, 249, 1) !default;
+$category-ListItem-color: rgba(51, 51, 51, 1) !default;
+$category-ListItemChecked-color: rgba(255, 255, 255, 1) !default;
+$category-ListItemChecked-img-bg-color: rgba(240, 37, 15, 1) !default;
 
 // circleProgress
-$circle-progress-primary-color: $primary-color !default;
-$circle-progress-path-color: #e5e9f2 !default;
-$circle-progress-text-color: #000000 !default;
-$circle-progress-text-size: $font-size-3 !default;
+$circleprogress-primary-color: $primary-color !default;
+$circleprogress-path-color: #e5e9f2 !default;
+$circleprogress-text-color: #000000 !default;
+$circleprogress-text-size: $font-size-3 !default;
+
+// Comment
+$comment-header-user-name-color: rgba(51, 51, 51, 1) !default;
+$comment-header-time-color: rgba(153, 153, 153, 1) !default;
+$comment-bottom-label-color: rgba(153, 153, 153, 1) !default;
+$comment-shop-color: $primary-color !default;
 
 @import './mixins/index';
 @import './animation/index';

+ 12 - 13
src/packages/styles/variables.scss

@@ -753,23 +753,22 @@ $ecard-bg-color: #f0f2f5 !default;
 
 //category
 $category-bg-color: rgba(255, 255, 255, 1) !default;
-$cateListLeft-bg-color: rgba(246, 247, 249, 1) !default;
-$cateListItem-color: rgba(51, 51, 51, 1) !default;
-$cateListItemChecked-color: rgba(255, 255, 255, 1) !default;
-$cateListItem-color: rgba(51, 51, 51, 1) !default;
-$cateListItemChecked-img-bg-color: rgba(240, 37, 15, 1) !default;
+$category-ListLeft-bg-color: rgba(246, 247, 249, 1) !default;
+$category-ListItem-color: rgba(51, 51, 51, 1) !default;
+$category-ListItemChecked-color: rgba(255, 255, 255, 1) !default;
+$category-ListItemChecked-img-bg-color: rgba(240, 37, 15, 1) !default;
 
 // circleProgress
-$circle-progress-primary-color: $primary-color !default;
-$circle-progress-path-color: #e5e9f2 !default;
-$circle-progress-text-color: #000000 !default;
-$circle-progress-text-size: $font-size-3 !default;
+$circleprogress-primary-color: $primary-color !default;
+$circleprogress-path-color: #e5e9f2 !default;
+$circleprogress-text-color: #000000 !default;
+$circleprogress-text-size: $font-size-3 !default;
 
 // Comment
-$cmt-header-user-name-color: rgba(51, 51, 51, 1) !default;
-$cmt-header-time-color: rgba(153, 153, 153, 1) !default;
-$cmt-bottom-label-color: rgba(153, 153, 153, 1) !default;
-$cmt-shop-color: $primary-color !default;
+$comment-header-user-name-color: rgba(51, 51, 51, 1) !default;
+$comment-header-time-color: rgba(153, 153, 153, 1) !default;
+$comment-bottom-label-color: rgba(153, 153, 153, 1) !default;
+$comment-shop-color: $primary-color !default;
 
 @import './mixins/index';
 @import './animation/index';

+ 24 - 0
src/packages/vscode-extension/.eslintrc.json

@@ -0,0 +1,24 @@
+{
+    "root": true,
+    "parser": "@typescript-eslint/parser",
+    "parserOptions": {
+        "ecmaVersion": 6,
+        "sourceType": "module"
+    },
+    "plugins": [
+        "@typescript-eslint"
+    ],
+    "rules": {
+        "@typescript-eslint/naming-convention": "warn",
+        "@typescript-eslint/semi": "warn",
+        "curly": "warn",
+        "eqeqeq": "warn",
+        "no-throw-literal": "warn",
+        "semi": "off"
+    },
+    "ignorePatterns": [
+        "out",
+        "dist",
+        "**/*.d.ts"
+    ]
+}

+ 6 - 0
src/packages/vscode-extension/.gitignore

@@ -0,0 +1,6 @@
+out
+dist
+node_modules
+.vscode-test/
+*.vsix
+yarn.lock

+ 11 - 0
src/packages/vscode-extension/.vscodeignore

@@ -0,0 +1,11 @@
+.vscode/**
+.vscode-test/**
+out/**
+node_modules/**
+.gitignore
+.yarnrc
+vsc-extension-quickstart.md
+**/tsconfig.json
+**/.eslintrc.json
+**/*.map
+**/*.ts

+ 1 - 0
src/packages/vscode-extension/.yarnrc

@@ -0,0 +1 @@
+--ignore-engines true

+ 6 - 0
src/packages/vscode-extension/CHANGELOG.md

@@ -0,0 +1,6 @@
+# Change Log
+
+## v0.0.1
+
+* 支持快速查看组件文档
+* 支持自动补全功能

+ 21 - 0
src/packages/vscode-extension/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 京东前端
+
+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.

+ 1 - 0
src/packages/vscode-extension/README.md

@@ -0,0 +1 @@
+# NutUI组件库vscode插件

+ 55 - 0
src/packages/vscode-extension/package.json

@@ -0,0 +1,55 @@
+{
+	"name": "nutui-vscode-extension",
+	"private": true,
+	"displayName": "nutui-vscode-extension",
+	"description": "nutui extension for vscode",
+	"version": "0.0.1",
+	"icon": "src/nutui.png",
+	"engines": {
+		"vscode": "^1.66.0"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/jdf2e/nutui.git"
+	},
+	"categories": [
+		"Other"
+	],
+	"publisher": "nutui",
+	"activationEvents": [
+		"onLanguage:vue",
+		"onLanguage:javascript",
+		"onLanguage:typescript"
+	],
+	"main": "./dist/extension.js",
+	"contributes": {
+		"commands": []
+	},
+	"scripts": {
+		"build": "webpack --mode production --devtool hidden-source-map",
+		"package": "yarn gen && yarn build && vsce package",
+		"publish": "vsce publish",
+		"unpublish": "vsce unpublish nutui.nutui-vscode-extension",
+		"gen": "node ./scripts/createComponentMap.js"
+	},
+	"devDependencies": {
+		"@types/glob": "^7.2.0",
+		"@types/mocha": "^9.0.0",
+		"@types/node": "14.x",
+		"@types/vscode": "^1.65.0",
+		"@typescript-eslint/eslint-plugin": "^5.9.1",
+		"@typescript-eslint/parser": "^5.9.1",
+		"@vscode/test-electron": "^2.0.3",
+		"eslint": "^8.6.0",
+		"glob": "^7.2.0",
+		"markdown-it": "^12.3.2",
+		"mocha": "^9.1.3",
+		"ts-loader": "^9.2.6",
+		"typescript": "^4.5.4",
+		"webpack": "^5.66.0",
+		"webpack-cli": "^4.9.1"
+	},
+	"dependencies": {
+		"vsce": "^2.7.0"
+	}
+}

+ 58 - 0
src/packages/vscode-extension/scripts/createComponentMap.js

@@ -0,0 +1,58 @@
+const path = require('path');
+const fs = require('fs');
+const MarkdownIt = require('markdown-it')();
+
+const basePath = path.resolve(__dirname, './../../__VUE');
+const componentDirs = fs.readdirSync(basePath, 'utf8');
+const TYPE_IDENTIFY_OPEN = 'tbody_open';
+const TYPE_IDENTIFY_CLOSE = 'tbody_close';
+const TR_TYPE_IDENTIFY_OPEN = 'tr_open';
+const TR_TYPE_IDENTIFY_CLOSE = 'tr_close';
+
+const getSubSources = (sources) => {
+  const startIndex = sources.findIndex((source) => source.type === TYPE_IDENTIFY_OPEN);
+  const endIndex = sources.findIndex((source) => source.type === TYPE_IDENTIFY_CLOSE);
+  sources = sources.slice(startIndex, endIndex + 1);
+  const trStartIndex = sources.findIndex((source) => source.type === TR_TYPE_IDENTIFY_OPEN);
+  const trEndIndex = sources.findIndex((source) => source.type === TR_TYPE_IDENTIFY_CLOSE);
+  return sources.slice(trStartIndex, trEndIndex + 1);
+};
+
+const genaratorComponentMap = () => {
+  let componentMap = {};
+  if (!componentDirs.length) return;
+
+  for (let componentDir of componentDirs) {
+    let stat = fs.lstatSync(`${basePath}/${componentDir}`);
+    if (stat.isDirectory()) {
+      const absolutePath = path.join(`${basePath}/${componentDir}`, 'doc.md');
+      if (!fs.existsSync(absolutePath)) continue;
+      const data = fs.readFileSync(absolutePath, 'utf8');
+      let sources = MarkdownIt.parse(data, {});
+      sources = getSubSources(sources);
+      componentMap[componentDir] = {
+        site: `/${componentDir}`,
+        props: sources.filter((source) => source.type === 'inline').length
+          ? [`${sources.filter((source) => source.type === 'inline')[0].content}=''`]
+          : ['']
+      };
+    }
+  }
+
+  return componentMap;
+};
+
+const writeFileInComponentMap = () => {
+  const componentMap = genaratorComponentMap();
+  let innerText = `
+import { ComponentDesc } from './componentDesc';
+
+export const componentMap: Record<string, ComponentDesc> = ${JSON.stringify(componentMap, null, 2)}
+`;
+
+  const componentMapPath = path.resolve(__dirname, './../src/componentMap.ts');
+
+  fs.writeFileSync(componentMapPath, innerText);
+};
+
+writeFileInComponentMap();

+ 4 - 0
src/packages/vscode-extension/src/componentDesc.ts

@@ -0,0 +1,4 @@
+export interface ComponentDesc {
+  site: string;
+  props?: string[];
+}

+ 324 - 0
src/packages/vscode-extension/src/componentMap.ts

@@ -0,0 +1,324 @@
+import { ComponentDesc } from './componentDesc';
+
+export const componentMap: Record<string, ComponentDesc> = {
+  actionsheet: {
+    site: '/actionsheet',
+    props: ["v-model:visible=''"]
+  },
+  address: {
+    site: '/address',
+    props: ["v-model:visible=''"]
+  },
+  addresslist: {
+    site: '/addresslist',
+    props: ["data=''"]
+  },
+  audio: {
+    site: '/audio',
+    props: ["url=''"]
+  },
+  audiooperate: {
+    site: '/audiooperate',
+    props: ['']
+  },
+  avatar: {
+    site: '/avatar',
+    props: ["size=''"]
+  },
+  backtop: {
+    site: '/backtop',
+    props: ["el-id=''"]
+  },
+  badge: {
+    site: '/badge',
+    props: ["value=''"]
+  },
+  barrage: {
+    site: '/barrage',
+    props: ["danmu=''"]
+  },
+  button: {
+    site: '/button',
+    props: ["type=''"]
+  },
+  calendar: {
+    site: '/calendar',
+    props: ["v-model:visible=''"]
+  },
+  card: {
+    site: '/card',
+    props: ["img-url=''"]
+  },
+  cascader: {
+    site: '/cascader',
+    props: ["v-model=''"]
+  },
+  category: {
+    site: '/category',
+    props: ["type=''"]
+  },
+  cell: {
+    site: '/cell',
+    props: ["title=''"]
+  },
+  checkbox: {
+    site: '/checkbox',
+    props: ["v-model=''"]
+  },
+  circleprogress: {
+    site: '/circleprogress',
+    props: ["progress=''"]
+  },
+  collapse: {
+    site: '/collapse',
+    props: ["v-model=''"]
+  },
+  comment: {
+    site: '/comment',
+    props: ["headerType=''"]
+  },
+  countdown: {
+    site: '/countdown',
+    props: ["v-model=''"]
+  },
+  countup: {
+    site: '/countup',
+    props: ["init-num=''"]
+  },
+  datepicker: {
+    site: '/datepicker',
+    props: ["v-model=''"]
+  },
+  dialog: {
+    site: '/dialog',
+    props: ["title=''"]
+  },
+  divider: {
+    site: '/divider',
+    props: ["dashed=''"]
+  },
+  drag: {
+    site: '/drag',
+    props: ["attract=''"]
+  },
+  ecard: {
+    site: '/ecard',
+    props: ["modelValue=''"]
+  },
+  elevator: {
+    site: '/elevator',
+    props: ["height=''"]
+  },
+  empty: {
+    site: '/empty',
+    props: ["image=''"]
+  },
+  fixednav: {
+    site: '/fixednav',
+    props: ["visible=''"]
+  },
+  form: {
+    site: '/form',
+    props: ["model-value=''"]
+  },
+  grid: {
+    site: '/grid',
+    props: ["column-num=''"]
+  },
+  icon: {
+    site: '/icon',
+    props: ["name=''"]
+  },
+  imagepreview: {
+    site: '/imagepreview',
+    props: ["show=''"]
+  },
+  indicator: {
+    site: '/indicator',
+    props: ["current=''"]
+  },
+  infiniteloading: {
+    site: '/infiniteloading',
+    props: ["has-more=''"]
+  },
+  input: {
+    site: '/input',
+    props: ["v-model=''"]
+  },
+  inputnumber: {
+    site: '/inputnumber',
+    props: ["v-model=''"]
+  },
+  layout: {
+    site: '/layout',
+    props: ["type=''"]
+  },
+  list: {
+    site: '/list',
+    props: ["height=''"]
+  },
+  menu: {
+    site: '/menu',
+    props: ["active-color=''"]
+  },
+  navbar: {
+    site: '/navbar',
+    props: ["title=''"]
+  },
+  noticebar: {
+    site: '/noticebar',
+    props: ["direction=''"]
+  },
+  notify: {
+    site: '/notify',
+    props: ["type=''"]
+  },
+  numberkeyboard: {
+    site: '/numberkeyboard',
+    props: ["v-model:visible=''"]
+  },
+  oldpicker: {
+    site: '/oldpicker',
+    props: ["v-model:visible=''"]
+  },
+  overlay: {
+    site: '/overlay',
+    props: ["v-model:visible=''"]
+  },
+  pagination: {
+    site: '/pagination',
+    props: ["v-model=''"]
+  },
+  picker: {
+    site: '/picker',
+    props: ["v-model:value=''"]
+  },
+  popover: {
+    site: '/popover',
+    props: ["list=''"]
+  },
+  popup: {
+    site: '/popup',
+    props: ["v-model:visible=''"]
+  },
+  price: {
+    site: '/price',
+    props: ["price=''"]
+  },
+  progress: {
+    site: '/progress',
+    props: ["percentage=''"]
+  },
+  pullrefresh: {
+    site: '/pullrefresh',
+    props: ["useWindow=''"]
+  },
+  radio: {
+    site: '/radio',
+    props: ["disabled=''"]
+  },
+  range: {
+    site: '/range',
+    props: ["v-model=''"]
+  },
+  rate: {
+    site: '/rate',
+    props: ["v-model=''"]
+  },
+  searchbar: {
+    site: '/searchbar',
+    props: ["max-length=''"]
+  },
+  shortpassword: {
+    site: '/shortpassword',
+    props: ["v-model=''"]
+  },
+  sidenavbar: {
+    site: '/sidenavbar',
+    props: ["offset=''"]
+  },
+  signature: {
+    site: '/signature',
+    props: ["custom-class=''"]
+  },
+  skeleton: {
+    site: '/skeleton',
+    props: ["loading=''"]
+  },
+  sku: {
+    site: '/sku',
+    props: ["v-model:visible=''"]
+  },
+  steps: {
+    site: '/steps',
+    props: ["direction=''"]
+  },
+  sticky: {
+    site: '/sticky',
+    props: ["position=''"]
+  },
+  swipe: {
+    site: '/swipe',
+    props: ["name=''"]
+  },
+  swiper: {
+    site: '/swiper',
+    props: ["width=''"]
+  },
+  swiperitem: {
+    site: '/swiperitem',
+    props: ['']
+  },
+  switch: {
+    site: '/switch',
+    props: ["v-model=''"]
+  },
+  tabbar: {
+    site: '/tabbar',
+    props: ["v-model:visible=''"]
+  },
+  table: {
+    site: '/table',
+    props: ["bordered=''"]
+  },
+  tabs: {
+    site: '/tabs',
+    props: ["v-model=''"]
+  },
+  tag: {
+    site: '/tag',
+    props: ["type=''"]
+  },
+  temp: {
+    site: '/temp',
+    props: ["name=''"]
+  },
+  textarea: {
+    site: '/textarea',
+    props: ["v-model=''"]
+  },
+  timedetail: {
+    site: '/timedetail',
+    props: ["height=''"]
+  },
+  timepannel: {
+    site: '/timepannel',
+    props: ["height=''"]
+  },
+  timeselect: {
+    site: '/timeselect',
+    props: ["visible=''"]
+  },
+  toast: {
+    site: '/toast',
+    props: ["Toast.text=''"]
+  },
+  uploader: {
+    site: '/uploader',
+    props: ["auto-upload=''"]
+  },
+  video: {
+    site: '/video',
+    props: ["source=''"]
+  }
+};

+ 80 - 0
src/packages/vscode-extension/src/extension.ts

@@ -0,0 +1,80 @@
+import * as vscode from 'vscode';
+import { kebabCase, bigCamelize } from './utils';
+import { componentMap } from './componentMap';
+import { ComponentDesc } from './componentDesc';
+
+const DOC = 'https://nutui.jd.com/#';
+
+const LINK_REG = /(?<=<nut-)([\w-]+)/g;
+const BIG_LINK_REG = /(?<=<Nut-)([\w-])+/g;
+const files = ['vue', 'typescript', 'javascript', 'react'];
+
+const provideHover = (document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) => {
+  const line = document.lineAt(position);
+  const componentLink = line.text.match(LINK_REG) ?? [];
+  const componentBigLink = line.text.match(BIG_LINK_REG) ?? [];
+  const components = [...new Set([...componentLink, ...componentBigLink.map(kebabCase)])];
+
+  if (components.length) {
+    const text = components
+      .filter((item: string) => componentMap[item])
+      .map((item: string) => {
+        const { site } = componentMap[item];
+
+        return new vscode.MarkdownString(
+          `[NutUI -> $(references) 请查看 ${bigCamelize(item)} 组件官方文档](${DOC}${site})\n`,
+          true
+        );
+      });
+
+    return new vscode.Hover(text);
+  }
+};
+
+const provideCompletionItems = () => {
+  const completionItems: vscode.CompletionItem[] = [];
+  Object.keys(componentMap).forEach((key: string) => {
+    completionItems.push(
+      new vscode.CompletionItem(`nut-${key}`, vscode.CompletionItemKind.Field),
+      new vscode.CompletionItem(bigCamelize(`nut-${key}`), vscode.CompletionItemKind.Field)
+    );
+  });
+  return completionItems;
+};
+
+const resolveCompletionItem = (item: vscode.CompletionItem) => {
+  const name = kebabCase(<string>item.label).slice(4);
+  const descriptor: ComponentDesc = componentMap[name];
+
+  const propsText = descriptor.props ? descriptor.props : '';
+  const tagSuffix = `</${item.label}>`;
+  item.insertText = `<${item.label} ${propsText}>${tagSuffix}`;
+
+  item.command = {
+    title: 'nutui-move-cursor',
+    command: 'nutui-move-cursor',
+    arguments: [-tagSuffix.length - 2]
+  };
+  return item;
+};
+
+const moveCursor = (characterDelta: number) => {
+  const active = vscode.window.activeTextEditor!.selection.active!;
+  const position = active.translate({ characterDelta });
+  vscode.window.activeTextEditor!.selection = new vscode.Selection(position, position);
+};
+
+export function activate(context: vscode.ExtensionContext) {
+  vscode.commands.registerCommand('nutui-move-cursor', moveCursor);
+  context.subscriptions.push(
+    vscode.languages.registerHoverProvider(files, {
+      provideHover
+    }),
+    vscode.languages.registerCompletionItemProvider(files, {
+      provideCompletionItems,
+      resolveCompletionItem
+    })
+  );
+}
+
+export function deactivate() {}

BIN
src/packages/vscode-extension/src/nutui.png


+ 12 - 0
src/packages/vscode-extension/src/utils.ts

@@ -0,0 +1,12 @@
+export const kebabCase = (str: string): string => {
+  str = str.replace(str.charAt(0), str.charAt(0).toLocaleLowerCase());
+  return str.replace(/([a-z])([A-Z])/g, (_, p1, p2) => p1 + '-' + p2.toLowerCase());
+};
+
+export const camelize = (str: string): string => {
+  return str.replace(/-(\w)/g, (_: any, p: string) => p.toUpperCase());
+};
+
+export const bigCamelize = (str: string): string => {
+  return camelize(str).replace(str.charAt(0), str.charAt(0).toUpperCase());
+};

+ 16 - 0
src/packages/vscode-extension/tsconfig.json

@@ -0,0 +1,16 @@
+{
+	"compilerOptions": {
+		"module": "commonjs",
+		"target": "ES2020",
+		"lib": [
+			"ES2020"
+		],
+		"sourceMap": true,
+		"rootDir": "src",
+		"strict": true   /* enable all strict type-checking options */
+		/* Additional Checks */
+		// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+		// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+		// "noUnusedParameters": true,  /* Report errors on unused parameters. */
+	}
+}

+ 48 - 0
src/packages/vscode-extension/webpack.config.js

@@ -0,0 +1,48 @@
+//@ts-check
+
+'use strict';
+
+const path = require('path');
+
+//@ts-check
+/** @typedef {import('webpack').Configuration} WebpackConfig **/
+
+/** @type WebpackConfig */
+const extensionConfig = {
+  target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
+  mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
+
+  entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
+  output: {
+    // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
+    path: path.resolve(__dirname, 'dist'),
+    filename: 'extension.js',
+    libraryTarget: 'commonjs2'
+  },
+  externals: {
+    vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
+    // modules added here also need to be added in the .vscodeignore file
+  },
+  resolve: {
+    // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
+    extensions: ['.ts', '.js']
+  },
+  module: {
+    rules: [
+      {
+        test: /\.ts$/,
+        exclude: /node_modules/,
+        use: [
+          {
+            loader: 'ts-loader'
+          }
+        ]
+      }
+    ]
+  },
+  devtool: 'nosources-source-map',
+  infrastructureLogging: {
+    level: 'log' // enables logging required for problem matchers
+  }
+};
+module.exports = [extensionConfig];

+ 1 - 1
src/sites/doc/components/demo-block/demoCodePackage.json

@@ -8,7 +8,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
-    "@nutui/nutui": "^3.1.16",
+    "@nutui/nutui": "^3.1.20",
     "vue": "^3.2.25"
   },
   "devDependencies": {

+ 4 - 4
vite.config.build.disperse.ts

@@ -33,19 +33,19 @@ export default defineConfig({
       outputDir: path.resolve(__dirname, './dist/types'),
       include: path.resolve(__dirname, './src/packages/__VUE'),
       beforeWriteFile: (filePath: string, content: string) => {
-        const fileContent = `import { App } from 'vue';
+        const fileContent = `import { App, PropType, CSSProperties } from 'vue';
 declare type Install<T> = T & {
   install(app: App): void;
 };
 `;
-        const start = 'declare const _default:';
-        const end = ';\nexport default _default;\n';
+        const start = 'declare const _sfc_main:';
+        const end = ';\nexport default _sfc_main;\n';
         const remain = `
 declare module 'vue' {
   interface GlobalComponents {
       Nut${Object.keys(input).find(
         (item: string) => item.toLowerCase() === filePath.split('/').slice(-2)[0]
-      )}: typeof _default;
+      )}: typeof _sfc_main;
   }
 }     
       `;

+ 4 - 4
vite.config.build.taro.vue.disperse.ts

@@ -35,19 +35,19 @@ export default defineConfig({
       outputDir: path.resolve(__dirname, './dist/types'),
       include: path.resolve(__dirname, './src/packages/__VUE'),
       beforeWriteFile: (filePath: string, content: string) => {
-        const fileContent = `import { App } from 'vue';
+        const fileContent = `import { App, PropType, CSSProperties } from 'vue';
 declare type Install<T> = T & {
   install(app: App): void;
 };
 `;
-        const start = 'declare const _default:';
-        const end = ';\nexport default _default;\n';
+        const start = 'declare const _sfc_main:';
+        const end = ';\nexport default _sfc_main;\n';
         const remain = `
 declare module 'vue' {
   interface GlobalComponents {
       Nut${Object.keys(input).find(
         (item: string) => item.toLowerCase() === filePath.split('/').slice(-2)[0]
-      )}: typeof _default;
+      )}: typeof _sfc_main;
   }
 }     
       `;