From 1b6bae671dad6ecd34548a97905ab14afcc08428 Mon Sep 17 00:00:00 2001
From: neverland <chenjiahan@youzan.com>
Date: Sun, 14 Nov 2021 16:57:12 +0800
Subject: [PATCH] chore(AddressEdit): using Form component (#9858)

---
 packages/vant/package.json                    |   1 +
 .../vant/src/address-edit/AddressEdit.tsx     | 163 +++++++-----------
 .../src/address-edit/AddressEditDetail.tsx    |  14 +-
 .../test/__snapshots__/demo.spec.ts.snap      |   6 +-
 .../test/__snapshots__/index.spec.js.snap     | 110 +-----------
 .../vant/src/address-edit/test/index.spec.js  |  44 ++---
 pnpm-lock.yaml                                |  10 ++
 7 files changed, 107 insertions(+), 241 deletions(-)

diff --git a/packages/vant/package.json b/packages/vant/package.json
index 840e3ab03..69b7aa5ba 100644
--- a/packages/vant/package.json
+++ b/packages/vant/package.json
@@ -56,6 +56,7 @@
     "@vant/cli": "^4.0.0-beta.5",
     "@vue/compiler-sfc": "^3.2.20",
     "@vue/runtime-core": "^3.2.20",
+    "@vue/test-utils": "^2.0.0-rc.16",
     "typescript": "4.x",
     "vue": "^3.2.20",
     "vue-router": "^4.0.12"
diff --git a/packages/vant/src/address-edit/AddressEdit.tsx b/packages/vant/src/address-edit/AddressEdit.tsx
index d6dcc3cac..69229bfb2 100644
--- a/packages/vant/src/address-edit/AddressEdit.tsx
+++ b/packages/vant/src/address-edit/AddressEdit.tsx
@@ -27,7 +27,8 @@ import { useExpose } from '../composables/use-expose';
 // Components
 import { Area, AreaList, AreaColumnOption, AreaInstance } from '../area';
 import { Cell } from '../cell';
-import { Field } from '../field';
+import { Form } from '../form';
+import { Field, FieldRule } from '../field';
 import { Popup } from '../popup';
 import { Toast } from '../toast';
 import { Button } from '../button';
@@ -111,25 +112,16 @@ export default defineComponent({
   setup(props, { emit, slots }) {
     const areaRef = ref<AreaInstance>();
 
-    const state = reactive({
-      data: {} as AddressEditInfo,
-      showAreaPopup: false,
-      detailFocused: false,
-      errorInfo: {
-        tel: '',
-        name: '',
-        areaCode: '',
-        postalCode: '',
-        addressDetail: '',
-      } as Record<string, string>,
-    });
+    const data = reactive({} as AddressEditInfo);
+    const showAreaPopup = ref(false);
+    const detailFocused = ref(false);
 
     const areaListLoaded = computed(
       () => isObject(props.areaList) && Object.keys(props.areaList).length
     );
 
     const areaText = computed(() => {
-      const { country, province, city, county, areaCode } = state.data;
+      const { country, province, city, county, areaCode } = data;
       if (areaCode) {
         const arr = [country, province, city, county];
         if (province && province === city) {
@@ -142,7 +134,7 @@ export default defineComponent({
 
     // hide bottom field when use search && detail get focused
     const hideBottomFields = computed(
-      () => props.searchResult?.length && state.detailFocused
+      () => props.searchResult?.length && detailFocused.value
     );
 
     const assignAreaValues = () => {
@@ -150,70 +142,52 @@ export default defineComponent({
         const detail: Record<string, string> = areaRef.value.getArea();
         detail.areaCode = detail.code;
         delete detail.code;
-        extend(state.data, detail);
+        extend(data, detail);
       }
     };
 
     const onFocus = (key: string) => {
-      state.errorInfo[key] = '';
-      state.detailFocused = key === 'addressDetail';
+      detailFocused.value = key === 'addressDetail';
       emit('focus', key);
     };
 
-    const getErrorMessage = (key: string) => {
-      const value = String((state.data as any)[key] || '').trim();
+    const rules = computed<Record<string, FieldRule[]>>(() => {
+      const { validator, telValidator, postalValidator } = props;
 
-      if (props.validator) {
-        const message = props.validator(key, value);
-        if (message) {
-          return message;
-        }
-      }
-
-      switch (key) {
-        case 'name':
-          return value ? '' : t('nameEmpty');
-        case 'tel':
-          return props.telValidator(value) ? '' : t('telInvalid');
-        case 'areaCode':
-          return value ? '' : t('areaEmpty');
-        case 'addressDetail':
-          return value ? '' : t('addressEmpty');
-        case 'postalCode':
-          return value && !props.postalValidator(value) ? t('postalEmpty') : '';
-      }
-    };
-
-    const onSave = () => {
-      const items = ['name', 'tel'];
-
-      if (props.showArea) {
-        items.push('areaCode');
-      }
-
-      if (props.showDetail) {
-        items.push('addressDetail');
-      }
-
-      if (props.showPostal) {
-        items.push('postalCode');
-      }
-
-      const isValid = items.every((item) => {
-        const msg = getErrorMessage(item);
-        if (msg) {
-          state.errorInfo[item] = msg;
-        }
-        return !msg;
+      const makeRule = (name: string, emptyMessage: string): FieldRule => ({
+        validator: (value) => {
+          if (validator) {
+            const message = validator(name, value);
+            if (message) {
+              return message;
+            }
+          }
+          if (!value) {
+            return emptyMessage;
+          }
+          return true;
+        },
       });
 
-      if (isValid && !props.isSaving) {
-        emit('save', state.data);
-      }
-    };
+      return {
+        name: [makeRule('name', t('nameEmpty'))],
+        tel: [
+          makeRule('tel', t('telInvalid')),
+          { validator: telValidator, message: t('telInvalid') },
+        ],
+        areaCode: [makeRule('areaCode', t('areaEmpty'))],
+        addressDetail: [makeRule('addressDetail', t('addressEmpty'))],
+        postalCode: [
+          makeRule('addressDetail', t('postalEmpty')),
+          { validator: postalValidator, message: t('postalEmpty') },
+        ],
+      };
+    });
+
+    const onSave = () => emit('save', data);
 
     const onChangeDetail = (val: string) => {
-      state.data.addressDetail = val;
+      data.addressDetail = val;
       emit('change-detail', val);
     };
 
@@ -222,22 +196,21 @@ export default defineComponent({
 
       if (values.some((value) => !value.code)) {
         Toast(t('areaEmpty'));
-        return;
+      } else {
+        showAreaPopup.value = false;
+        assignAreaValues();
+        emit('change-area', values);
       }
-
-      state.showAreaPopup = false;
-      assignAreaValues();
-      emit('change-area', values);
     };
 
-    const onDelete = () => emit('delete', state.data);
+    const onDelete = () => emit('delete', data);
 
     // get values of area component
-    const getArea = () => (areaRef.value ? areaRef.value.getValues() : []);
+    const getArea = () => areaRef.value?.getValues() || [];
 
     // set area code to area component
     const setAreaCode = (code?: string) => {
-      state.data.areaCode = code || '';
+      data.areaCode = code || '';
 
       if (code) {
         nextTick(assignAreaValues);
@@ -247,12 +220,12 @@ export default defineComponent({
     const onDetailBlur = () => {
       // await for click search event
       setTimeout(() => {
-        state.detailFocused = false;
+        detailFocused.value = false;
       });
     };
 
     const setAddressDetail = (value: string) => {
-      state.data.addressDetail = value;
+      data.addressDetail = value;
     };
 
     const renderSetDefaultCell = () => {
@@ -260,7 +233,7 @@ export default defineComponent({
         const slots = {
           'right-icon': () => (
             <Switch
-              v-model={state.data.isDefault}
+              v-model={data.isDefault}
               size="24"
               onChange={(event) => emit('change-default', event)}
             />
@@ -277,8 +250,6 @@ export default defineComponent({
           />
         );
       }
-
-      return null;
     };
 
     useExpose({
@@ -289,13 +260,13 @@ export default defineComponent({
 
     watch(
       () => props.areaList,
-      () => setAreaCode(state.data.areaCode)
+      () => setAreaCode(data.areaCode)
     );
 
     watch(
       () => props.addressInfo,
       (value) => {
-        state.data = extend({}, DEFAULT_DATA, value);
+        extend(data, DEFAULT_DATA, value);
         setAreaCode(value.areaCode);
       },
       {
@@ -305,18 +276,17 @@ export default defineComponent({
     );
 
     return () => {
-      const { data, errorInfo } = state;
       const { disableArea } = props;
 
       return (
-        <div class={bem()}>
+        <Form class={bem()} onSubmit={onSave}>
           <div class={bem('fields')}>
             <Field
               v-model={data.name}
               clearable
               label={t('name')}
+              rules={rules.value.name}
               placeholder={t('name')}
-              errorMessage={errorInfo.name}
               onFocus={() => onFocus('name')}
             />
             <Field
@@ -324,9 +294,9 @@ export default defineComponent({
               clearable
               type="tel"
               label={t('tel')}
+              rules={rules.value.tel}
               maxlength={props.telMaxlength}
               placeholder={t('tel')}
-              errorMessage={errorInfo.tel}
               onFocus={() => onFocus('tel')}
             />
             <Field
@@ -335,22 +305,22 @@ export default defineComponent({
               label={t('area')}
               is-link={!disableArea}
               modelValue={areaText.value}
+              rules={rules.value.areaCode}
               placeholder={props.areaPlaceholder || t('area')}
-              errorMessage={errorInfo.areaCode}
               onFocus={() => onFocus('areaCode')}
               onClick={() => {
                 emit('click-area');
-                state.showAreaPopup = !disableArea;
+                showAreaPopup.value = !disableArea;
               }}
             />
             <AddressEditDetail
               show={props.showDetail}
+              rows={props.detailRows}
+              rules={rules.value.addressDetail}
               value={data.addressDetail}
-              focused={state.detailFocused}
-              detailRows={props.detailRows}
-              errorMessage={errorInfo.addressDetail}
+              focused={detailFocused.value}
+              maxlength={props.detailMaxlength}
               searchResult={props.searchResult}
-              detailMaxlength={props.detailMaxlength}
               showSearchResult={props.showSearchResult}
               onBlur={onDetailBlur}
               onFocus={() => onFocus('addressDetail')}
@@ -362,10 +332,10 @@ export default defineComponent({
                 v-show={!hideBottomFields.value}
                 v-model={data.postalCode}
                 type="tel"
+                rules={rules.value.postalCode}
                 label={t('postal')}
                 maxlength="6"
                 placeholder={t('postal')}
-                errorMessage={errorInfo.postalCode}
                 onFocus={() => onFocus('postalCode')}
               />
             )}
@@ -380,6 +350,7 @@ export default defineComponent({
               text={props.saveButtonText || t('save')}
               class={bem('button')}
               loading={props.isSaving}
+              nativeType="submit"
               onClick={onSave}
             />
             {props.showDelete && (
@@ -394,7 +365,7 @@ export default defineComponent({
             )}
           </div>
           <Popup
-            v-model:show={state.showAreaPopup}
+            v-model:show={showAreaPopup.value}
             round
             teleport="body"
             position="bottom"
@@ -408,11 +379,11 @@ export default defineComponent({
               columnsPlaceholder={props.areaColumnsPlaceholder}
               onConfirm={onAreaConfirm}
               onCancel={() => {
-                state.showAreaPopup = false;
+                showAreaPopup.value = false;
               }}
             />
           </Popup>
-        </div>
+        </Form>
       );
     };
   },
diff --git a/packages/vant/src/address-edit/AddressEditDetail.tsx b/packages/vant/src/address-edit/AddressEditDetail.tsx
index 3401e5d1b..f048ed0b5 100644
--- a/packages/vant/src/address-edit/AddressEditDetail.tsx
+++ b/packages/vant/src/address-edit/AddressEditDetail.tsx
@@ -9,7 +9,7 @@ import { Field } from '../field';
 
 // Types
 import type { AddressEditSearchItem } from './types';
-import type { FieldInstance } from '../field/types';
+import type { FieldRule, FieldInstance } from '../field/types';
 
 const [name, bem, t] = createNamespace('address-edit-detail');
 
@@ -18,12 +18,12 @@ export default defineComponent({
 
   props: {
     show: Boolean,
+    rows: numericProp,
     value: String,
+    rules: Array as PropType<FieldRule[]>,
     focused: Boolean,
-    detailRows: numericProp,
+    maxlength: numericProp,
     searchResult: Array as PropType<AddressEditSearchItem[]>,
-    errorMessage: String,
-    detailMaxlength: numericProp,
     showSearchResult: Boolean,
   },
 
@@ -86,14 +86,14 @@ export default defineComponent({
               clearable
               ref={field}
               class={bem()}
-              rows={props.detailRows}
+              rows={props.rows}
               type="textarea"
+              rules={props.rules}
               label={t('label')}
               border={!showSearchResult()}
-              maxlength={props.detailMaxlength}
+              maxlength={props.maxlength}
               modelValue={props.value}
               placeholder={t('placeholder')}
-              errorMessage={props.errorMessage}
               onBlur={onBlur}
               onFocus={onFocus}
               onUpdate:modelValue={onInput}
diff --git a/packages/vant/src/address-edit/test/__snapshots__/demo.spec.ts.snap b/packages/vant/src/address-edit/test/__snapshots__/demo.spec.ts.snap
index 3a44405ce..aabd05ff7 100644
--- a/packages/vant/src/address-edit/test/__snapshots__/demo.spec.ts.snap
+++ b/packages/vant/src/address-edit/test/__snapshots__/demo.spec.ts.snap
@@ -2,7 +2,7 @@
 
 exports[`should render demo and match snapshot 1`] = `
 <div>
-  <div class="van-address-edit">
+  <form class="van-form van-address-edit">
     <div class="van-address-edit__fields">
       <div class="van-cell van-field">
         <div class="van-cell__title van-field__label">
@@ -104,7 +104,7 @@ exports[`should render demo and match snapshot 1`] = `
       </div>
     </div>
     <div class="van-address-edit__buttons">
-      <button type="button"
+      <button type="submit"
               class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
       >
         <div class="van-button__content">
@@ -123,6 +123,6 @@ exports[`should render demo and match snapshot 1`] = `
         </div>
       </button>
     </div>
-  </div>
+  </form>
 </div>
 `;
diff --git a/packages/vant/src/address-edit/test/__snapshots__/index.spec.js.snap b/packages/vant/src/address-edit/test/__snapshots__/index.spec.js.snap
index ef5b38f22..279729d12 100644
--- a/packages/vant/src/address-edit/test/__snapshots__/index.spec.js.snap
+++ b/packages/vant/src/address-edit/test/__snapshots__/index.spec.js.snap
@@ -7,7 +7,7 @@ exports[`should allow to custom validator with validator prop 1`] = `
 `;
 
 exports[`should render AddressEdit correctly 1`] = `
-<div class="van-address-edit">
+<form class="van-form van-address-edit">
   <div class="van-address-edit__fields">
     <div class="van-cell van-field">
       <div class="van-cell__title van-field__label">
@@ -78,7 +78,7 @@ exports[`should render AddressEdit correctly 1`] = `
     </div>
   </div>
   <div class="van-address-edit__buttons">
-    <button type="button"
+    <button type="submit"
             class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
     >
       <div class="van-button__content">
@@ -88,11 +88,11 @@ exports[`should render AddressEdit correctly 1`] = `
       </div>
     </button>
   </div>
-</div>
+</form>
 `;
 
 exports[`should render AddressEdit with props correctly 1`] = `
-<div class="van-address-edit">
+<form class="van-form van-address-edit">
   <div class="van-address-edit__fields">
     <div class="van-cell van-field">
       <div class="van-cell__title van-field__label">
@@ -193,7 +193,7 @@ exports[`should render AddressEdit with props correctly 1`] = `
     </div>
   </div>
   <div class="van-address-edit__buttons">
-    <button type="button"
+    <button type="submit"
             class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
     >
       <div class="van-button__content">
@@ -203,7 +203,7 @@ exports[`should render AddressEdit with props correctly 1`] = `
       </div>
     </button>
   </div>
-</div>
+</form>
 `;
 
 exports[`should valid address detail and render error message correctly 1`] = `
@@ -229,26 +229,6 @@ exports[`should valid address detail and render error message correctly 1`] = `
 </div>
 `;
 
-exports[`should valid address detail and render error message correctly 2`] = `
-<div class="van-cell van-field van-address-edit-detail">
-  <div class="van-cell__title van-field__label">
-    <label>
-      Address
-    </label>
-  </div>
-  <div class="van-cell__value van-field__value">
-    <div class="van-field__body">
-      <textarea rows="1"
-                class="van-field__control"
-                placeholder="Address"
-                style="height: auto;"
-      >
-      </textarea>
-    </div>
-  </div>
-</div>
-`;
-
 exports[`should valid area code and render error message correctly 1`] = `
 <div class="van-cell van-cell--clickable van-field"
      role="button"
@@ -276,30 +256,6 @@ exports[`should valid area code and render error message correctly 1`] = `
 </div>
 `;
 
-exports[`should valid area code and render error message correctly 2`] = `
-<div class="van-cell van-cell--clickable van-field"
-     role="button"
-     tabindex="0"
->
-  <div class="van-cell__title van-field__label">
-    <label>
-      Area
-    </label>
-  </div>
-  <div class="van-cell__value van-field__value">
-    <div class="van-field__body">
-      <input type="text"
-             class="van-field__control"
-             readonly
-             placeholder="Area"
-      >
-    </div>
-  </div>
-  <i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
-  </i>
-</div>
-`;
-
 exports[`should valid name and render error message correctly 1`] = `
 <div class="van-cell van-field">
   <div class="van-cell__title van-field__label">
@@ -321,24 +277,6 @@ exports[`should valid name and render error message correctly 1`] = `
 </div>
 `;
 
-exports[`should valid name and render error message correctly 2`] = `
-<div class="van-cell van-field">
-  <div class="van-cell__title van-field__label">
-    <label>
-      Name
-    </label>
-  </div>
-  <div class="van-cell__value van-field__value">
-    <div class="van-field__body">
-      <input type="text"
-             class="van-field__control"
-             placeholder="Name"
-      >
-    </div>
-  </div>
-</div>
-`;
-
 exports[`should valid postal code and render error message correctly 1`] = `
 <div class="van-cell van-field">
   <div class="van-cell__title van-field__label">
@@ -360,24 +298,6 @@ exports[`should valid postal code and render error message correctly 1`] = `
 </div>
 `;
 
-exports[`should valid postal code and render error message correctly 2`] = `
-<div class="van-cell van-field">
-  <div class="van-cell__title van-field__label">
-    <label>
-      Postal
-    </label>
-  </div>
-  <div class="van-cell__value van-field__value">
-    <div class="van-field__body">
-      <input type="tel"
-             class="van-field__control"
-             placeholder="Postal"
-      >
-    </div>
-  </div>
-</div>
-`;
-
 exports[`should valid tel and render error message correctly 1`] = `
 <div class="van-cell van-field">
   <div class="van-cell__title van-field__label">
@@ -398,21 +318,3 @@ exports[`should valid tel and render error message correctly 1`] = `
   </div>
 </div>
 `;
-
-exports[`should valid tel and render error message correctly 2`] = `
-<div class="van-cell van-field">
-  <div class="van-cell__title van-field__label">
-    <label>
-      Phone
-    </label>
-  </div>
-  <div class="van-cell__value van-field__value">
-    <div class="van-field__body">
-      <input type="tel"
-             class="van-field__control"
-             placeholder="Phone"
-      >
-    </div>
-  </div>
-</div>
-`;
diff --git a/packages/vant/src/address-edit/test/index.spec.js b/packages/vant/src/address-edit/test/index.spec.js
index 21d42db66..492718977 100644
--- a/packages/vant/src/address-edit/test/index.spec.js
+++ b/packages/vant/src/address-edit/test/index.spec.js
@@ -1,6 +1,7 @@
 import { AddressEdit } from '..';
 import { areaList } from '../../area/demo/area-simple';
 import { mount, later, trigger } from '../../../test';
+import { submitForm } from '../../form/test/shared';
 
 const defaultAddressInfo = {
   name: '测试',
@@ -27,12 +28,10 @@ const createComponent = (addressInfo = {}) => {
     },
   });
 
-  const button = wrapper.find('.van-button');
   const fields = wrapper.findAll('.van-field');
   return {
     vm: wrapper.vm,
     fields,
-    button,
     wrapper,
   };
 };
@@ -55,13 +54,6 @@ test('should render AddressEdit with props correctly', () => {
   expect(wrapper.html()).toMatchSnapshot();
 });
 
-// test('set-default', () => {
-//   const { wrapper } = createComponent();
-//   wrapper.find('.van-switch').trigger('click');
-
-//   expect(wrapper.html()).toMatchSnapshot();
-// });
-
 test('should allow to custom validator with validator prop', async () => {
   const wrapper = mount(AddressEdit, {
     props: {
@@ -70,63 +62,53 @@ test('should allow to custom validator with validator prop', async () => {
     },
   });
 
-  const button = wrapper.find('.van-button');
-  await button.trigger('click');
+  await submitForm(wrapper);
   expect(wrapper.find('.van-field__error-message').html()).toMatchSnapshot();
 });
 
 test('should valid name and render error message correctly', async () => {
-  const { fields, button } = createComponent({
+  const { fields, wrapper } = createComponent({
     name: '',
   });
 
-  await button.trigger('click');
-  expect(fields[0].html()).toMatchSnapshot();
-  await fields[0].find('input').trigger('focus');
+  await submitForm(wrapper);
   expect(fields[0].html()).toMatchSnapshot();
 });
 
 test('should valid tel and render error message correctly', async () => {
-  const { fields, button } = createComponent({
+  const { fields, wrapper } = createComponent({
     tel: '',
   });
 
-  await button.trigger('click');
-  expect(fields[1].html()).toMatchSnapshot();
-  await fields[1].find('input').trigger('focus');
+  await submitForm(wrapper);
   expect(fields[1].html()).toMatchSnapshot();
 });
 
 test('should valid area code and render error message correctly', async () => {
-  const { fields, button } = createComponent({
+  const { fields, wrapper } = createComponent({
     areaCode: '',
   });
 
-  await button.trigger('click');
-  expect(fields[2].html()).toMatchSnapshot();
-  await fields[2].find('input').trigger('focus');
+  await submitForm(wrapper);
   expect(fields[2].html()).toMatchSnapshot();
 });
 
 test('should valid address detail and render error message correctly', async () => {
-  const { fields, button } = createComponent({
+  const { fields, wrapper } = createComponent({
     addressDetail: '',
   });
 
-  await button.trigger('click');
-  expect(fields[3].html()).toMatchSnapshot();
-  await fields[3].find('textarea').trigger('focus');
+  await submitForm(wrapper);
+  await later();
   expect(fields[3].html()).toMatchSnapshot();
 });
 
 test('should valid postal code and render error message correctly', async () => {
-  const { fields, button } = createComponent({
+  const { fields, wrapper } = createComponent({
     postalCode: '123',
   });
 
-  await button.trigger('click');
-  expect(fields[4].html()).toMatchSnapshot();
-  await fields[4].find('input').trigger('focus');
+  await submitForm(wrapper);
   expect(fields[4].html()).toMatchSnapshot();
 });
 
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3e8a7c749..8767d7c8b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -56,6 +56,7 @@ importers:
       '@vant/use': ^1.3.3
       '@vue/compiler-sfc': ^3.2.20
       '@vue/runtime-core': ^3.2.20
+      '@vue/test-utils': ^2.0.0-rc.16
       typescript: 4.x
       vue: ^3.2.20
       vue-router: ^4.0.12
@@ -68,6 +69,7 @@ importers:
       '@vant/cli': link:../vant-cli
       '@vue/compiler-sfc': 3.2.21
       '@vue/runtime-core': 3.2.21
+      '@vue/test-utils': 2.0.0-rc.16_vue@3.2.21
       typescript: 4.4.4
       vue: 3.2.21
       vue-router: 4.0.12_vue@3.2.21
@@ -2477,6 +2479,14 @@ packages:
       vue: 3.2.21
     dev: false
 
+  /@vue/test-utils/2.0.0-rc.16_vue@3.2.21:
+    resolution: {integrity: sha1-WTgPAocPhWrAAqKcAmgdPz/Lr+s=, tarball: '@vue/test-utils/download/@vue/test-utils-2.0.0-rc.16.tgz'}
+    peerDependencies:
+      vue: ^3.0.1
+    dependencies:
+      vue: 3.2.21
+    dev: true
+
   /JSONStream/1.3.5:
     resolution: {integrity: sha1-MgjB8I06TZkmGrZPkjArwV4RHKA=, tarball: JSONStream/download/JSONStream-1.3.5.tgz}
     hasBin: true