From 4ff1c408dc1acfc49e0adc61dc2e539c0c198158 Mon Sep 17 00:00:00 2001
From: vben <anncwb@126.com>
Date: 星期五, 25 十二月 2020 01:09:44 +0800
Subject: [PATCH] wip(form): perf form

---
 src/components/Form/src/components/RadioButtonGroup.vue     |   43 
 src/directives/ripple/index.ts                              |    8 
 src/hooks/event/useKeyPress.ts                              |    6 
 src/utils/helper/persistent.ts                              |    4 
 src/components/Table/src/BasicTable.vue                     |    2 
 src/components/Form/src/props.ts                            |   91 +-
 src/components/Form/src/hooks/useAdvanced.ts                |   50 -
 src/types/global.d.ts                                       |   10 
 src/components/util.tsx                                     |    6 
 src/components/Container/src/collapse/CollapseContainer.vue |    3 
 src/components/Form/src/helper.ts                           |   11 
 src/components/Scrollbar/src/util.ts                        |    2 
 src/components/Form/src/hooks/useFormValues.ts              |   17 
 src/components/Form/src/types/form.ts                       |   34 
 src/settings/colorSetting.ts                                |    2 
 src/components/Table/src/components/renderEditable.tsx      |    2 
 src/router/guard/permissionGuard.ts                         |    2 
 src/components/Form/src/componentMap.ts                     |    5 
 src/components/VirtualScroll/src/index.tsx                  |    2 
 src/components/Form/src/components/FormItem.tsx             |  132 ++--
 src/hooks/web/useI18n.ts                                    |    2 
 src/utils/helper/tsxHelper.tsx                              |    2 
 src/components/Form/src/components/FormAction.vue           |  139 ++++
 src/hooks/component/useFormItem.ts                          |   35 +
 src/router/types.ts                                         |    2 
 src/components/Form/src/hooks/useComponentRegister.ts       |    4 
 src/components/Form/src/hooks/useLabelWidth.ts              |   19 
 src/utils/helper/vueHelper.ts                               |    3 
 src/components/Modal/src/useModalContext.ts                 |    6 
 src/hooks/core/useAttrs.ts                                  |   39 +
 src/components/Form/src/hooks/useForm.ts                    |   91 ++
 src/components/Form/src/BasicForm.vue                       |  102 +-
 src/utils/log.ts                                            |    4 
 /dev/null                                                   |  141 ----
 src/utils/http/axios/types.ts                               |    2 
 src/utils/index.ts                                          |    2 
 src/components/Basic/index.ts                               |    5 
 src/components/Transition/src/CreateTransition.tsx          |    2 
 yarn.lock                                                   |  599 +++++++++----------
 src/views/demo/form/RuleForm.vue                            |    5 
 package.json                                                |    6 
 src/components/Table/src/types/column.ts                    |    2 
 src/components/Form/src/hooks/useFormContext.ts             |   17 
 src/layouts/page/index.tsx                                  |    2 
 src/components/Form/src/hooks/useFormEvents.ts              |  100 +-
 45 files changed, 901 insertions(+), 862 deletions(-)

diff --git a/package.json b/package.json
index e86aa54..7af8cb7 100644
--- a/package.json
+++ b/package.json
@@ -48,11 +48,11 @@
   "devDependencies": {
     "@commitlint/cli": "^11.0.0",
     "@commitlint/config-conventional": "^11.0.0",
-    "@iconify/json": "^1.1.275",
+    "@iconify/json": "^1.1.276",
     "@ls-lint/ls-lint": "^1.9.2",
     "@purge-icons/generated": "^0.4.1",
     "@types/echarts": "^4.9.3",
-    "@types/fs-extra": "^9.0.5",
+    "@types/fs-extra": "^9.0.6",
     "@types/globrex": "^0.1.0",
     "@types/koa-static": "^4.0.1",
     "@types/lodash-es": "^4.17.4",
@@ -102,7 +102,7 @@
     "vite-plugin-html": "^1.0.0-beta.2",
     "vite-plugin-mock": "^1.0.9",
     "vite-plugin-purge-icons": "^0.4.5",
-    "vite-plugin-pwa": "^0.1.7",
+    "vite-plugin-pwa": "^0.2.0",
     "vue-eslint-parser": "^7.3.0",
     "yargs": "^16.2.0"
   },
diff --git a/src/components/Basic/index.ts b/src/components/Basic/index.ts
index 73fed74..5c86c28 100644
--- a/src/components/Basic/index.ts
+++ b/src/components/Basic/index.ts
@@ -1,5 +1,8 @@
 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+import BasicArrow from './src/BasicArrow.vue';
 
-export const BasicArrow = createAsyncComponent(() => import('./src/BasicArrow.vue'));
+export { BasicArrow };
+
+// export const BasicArrow = createAsyncComponent(() => import('./src/BasicArrow.vue'));
 export const BasicHelp = createAsyncComponent(() => import('./src/BasicHelp.vue'));
 export const BasicTitle = createAsyncComponent(() => import('./src/BasicTitle.vue'));
diff --git a/src/components/Container/src/collapse/CollapseContainer.vue b/src/components/Container/src/collapse/CollapseContainer.vue
index a064214..bf20cc1 100644
--- a/src/components/Container/src/collapse/CollapseContainer.vue
+++ b/src/components/Container/src/collapse/CollapseContainer.vue
@@ -101,7 +101,10 @@
 
     &__action {
       display: flex;
+      text-align: right;
+      flex: 1;
       align-items: center;
+      justify-content: flex-end;
     }
   }
 </style>
diff --git a/src/components/Form/src/BasicForm.vue b/src/components/Form/src/BasicForm.vue
index d1fd566..fd2f697 100644
--- a/src/components/Form/src/BasicForm.vue
+++ b/src/components/Form/src/BasicForm.vue
@@ -1,6 +1,6 @@
 <template>
   <Form v-bind="{ ...$attrs, ...$props }" ref="formElRef" :model="formModel">
-    <Row :class="getProps.compact ? 'compact-form-row' : ''" :style="getRowWrapStyleRef">
+    <Row :class="getProps.compact ? 'compact-form-row' : ''" :style="getRowWrapStyle">
       <slot name="formHeader" />
       <template v-for="schema in getSchema" :key="schema.field">
         <FormItem
@@ -10,6 +10,7 @@
           :formProps="getProps"
           :allDefaultValues="defaultValueRef"
           :formModel="formModel"
+          :setFormModel="setFormModel"
         >
           <template #[item]="data" v-for="item in Object.keys($slots)">
             <slot :name="item" v-bind="data" />
@@ -17,8 +18,9 @@
         </FormItem>
       </template>
 
+      <!--  -->
       <FormAction
-        v-bind="{ ...getActionPropsRef, ...advanceState }"
+        v-bind="{ ...getProps, ...advanceState }"
         @toggle-advanced="handleToggleAdvanced"
       />
       <slot name="formFooter" />
@@ -28,14 +30,12 @@
 <script lang="ts">
   import type { FormActionType, FormProps, FormSchema } from './types/form';
   import type { AdvanceState } from './types/hooks';
-  import type { Ref, WatchStopHandle } from 'vue';
-  import type { ValidateFields } from 'ant-design-vue/lib/form/interface';
+  import type { CSSProperties, Ref, WatchStopHandle } from 'vue';
 
   import { defineComponent, reactive, ref, computed, unref, onMounted, watch, toRefs } from 'vue';
   import { Form, Row } from 'ant-design-vue';
-  import FormItem from './FormItem';
-  import { basicProps } from './props';
-  import FormAction from './FormAction';
+  import FormItem from './components/FormItem';
+  import FormAction from './components/FormAction.vue';
 
   import { dateItemType } from './helper';
   import moment from 'moment';
@@ -44,7 +44,11 @@
 
   import { useFormValues } from './hooks/useFormValues';
   import useAdvanced from './hooks/useAdvanced';
-  import { useFormAction } from './hooks/useFormAction';
+  import { useFormEvents } from './hooks/useFormEvents';
+  import { createFormContext } from './hooks/useFormContext';
+
+  import { basicProps } from './props';
+
   export default defineComponent({
     name: 'BasicForm',
     components: { FormItem, Form, Row, FormAction },
@@ -52,12 +56,7 @@
     props: basicProps,
     emits: ['advanced-change', 'reset', 'submit', 'register'],
     setup(props, { emit }) {
-      const formModel = reactive({});
-
-      const actionState = reactive({
-        resetAction: {},
-        submitAction: {},
-      });
+      const formModel = reactive<Recordable>({});
 
       const advanceState = reactive<AdvanceState>({
         isAdvanced: true,
@@ -66,37 +65,24 @@
         actionSpan: 6,
       });
 
-      const defaultValueRef = ref<any>({});
+      const defaultValueRef = ref<Recordable>({});
       const isInitedDefaultRef = ref(false);
       const propsRef = ref<Partial<FormProps>>({});
       const schemaRef = ref<Nullable<FormSchema[]>>(null);
       const formElRef = ref<Nullable<FormActionType>>(null);
 
-      const getMergePropsRef = computed(
+      // Get the basic configuration of the form
+      const getProps = computed(
         (): FormProps => {
           return deepMerge(cloneDeep(props), unref(propsRef));
         }
       );
 
-      const getRowWrapStyleRef = computed((): any => {
-        const { baseRowStyle } = unref(getMergePropsRef);
-        return baseRowStyle || {};
-      });
-
-      // 鑾峰彇琛ㄥ崟鍩烘湰閰嶇疆
-      const getProps = computed(
-        (): FormProps => {
-          return {
-            ...unref(getMergePropsRef),
-            resetButtonOptions: deepMerge(
-              actionState.resetAction,
-              unref(getMergePropsRef).resetButtonOptions || {}
-            ),
-            submitButtonOptions: deepMerge(
-              actionState.submitAction,
-              unref(getMergePropsRef).submitButtonOptions || {}
-            ),
-          };
+      // Get uniform row style
+      const getRowWrapStyle = computed(
+        (): CSSProperties => {
+          const { baseRowStyle = {} } = unref(getProps);
+          return baseRowStyle;
         }
       );
 
@@ -120,18 +106,19 @@
         return schemas as FormSchema[];
       });
 
-      const { getActionPropsRef, handleToggleAdvanced } = useAdvanced({
+      const { handleToggleAdvanced } = useAdvanced({
         advanceState,
         emit,
-        getMergePropsRef,
         getProps,
         getSchema,
         formModel,
         defaultValueRef,
       });
+
       const { transformDateFunc, fieldMapToTime } = toRefs(props);
+
       const { handleFormValues, initDefault } = useFormValues({
-        transformDateFuncRef: transformDateFunc as Ref<Fn<any>>,
+        transformDateFuncRef: transformDateFunc,
         fieldMapToTimeRef: fieldMapToTime,
         defaultValueRef,
         getSchema,
@@ -139,7 +126,7 @@
       });
 
       const {
-        // handleSubmit,
+        handleSubmit,
         setFieldsValue,
         clearValidate,
         validate,
@@ -149,7 +136,8 @@
         appendSchemaByField,
         removeSchemaByFiled,
         resetFields,
-      } = useFormAction({
+        scrollToField,
+      } = useFormEvents({
         emit,
         getProps,
         formModel,
@@ -158,14 +146,19 @@
         formElRef: formElRef as Ref<FormActionType>,
         schemaRef: schemaRef as Ref<FormSchema[]>,
         handleFormValues,
-        actionState,
+      });
+
+      createFormContext({
+        resetAction: resetFields,
+        submitAction: handleSubmit,
       });
 
       watch(
-        () => unref(getMergePropsRef).model,
+        () => unref(getProps).model,
         () => {
-          if (!unref(getMergePropsRef).model) return;
-          setFieldsValue(unref(getMergePropsRef).model);
+          const { model } = unref(getProps);
+          if (!model) return;
+          setFieldsValue(model);
         },
         {
           immediate: true,
@@ -178,16 +171,19 @@
           if (unref(isInitedDefaultRef)) {
             return stopWatch();
           }
-          if (schema && schema.length) {
+          if (schema?.length) {
             initDefault();
             isInitedDefaultRef.value = true;
           }
         }
       );
 
-      function setProps(formProps: Partial<FormProps>): void {
-        const mergeProps = deepMerge(unref(propsRef) || {}, formProps);
-        propsRef.value = mergeProps;
+      async function setProps(formProps: Partial<FormProps>): Promise<void> {
+        propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
+      }
+
+      function setFormModel(key: string, value: any) {
+        formModel[key] = value;
       }
 
       const formActionType: Partial<FormActionType> = {
@@ -199,8 +195,10 @@
         removeSchemaByFiled,
         appendSchemaByField,
         clearValidate,
-        validateFields: validateFields as ValidateFields,
-        validate: validate as ValidateFields,
+        validateFields,
+        validate,
+        submit: handleSubmit,
+        scrollToField: scrollToField,
       };
 
       onMounted(() => {
@@ -211,14 +209,14 @@
       return {
         handleToggleAdvanced,
         formModel,
-        getActionPropsRef,
         defaultValueRef,
         advanceState,
-        getRowWrapStyleRef,
+        getRowWrapStyle,
         getProps,
         formElRef,
         getSchema,
         formActionType,
+        setFormModel,
         ...formActionType,
       };
     },
diff --git a/src/components/Form/src/FormAction.tsx b/src/components/Form/src/FormAction.tsx
deleted file mode 100644
index 2d2fb89..0000000
--- a/src/components/Form/src/FormAction.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import type { ColEx } from './types/index';
-
-import { defineComponent, unref, computed, PropType } from 'vue';
-import { Form, Col } from 'ant-design-vue';
-import { Button } from '/@/components/Button';
-import { BasicArrow } from '/@/components/Basic/index';
-
-import { getSlot } from '/@/utils/helper/tsxHelper';
-import { useI18n } from '/@/hooks/web/useI18n';
-import { propTypes } from '/@/utils/propTypes';
-
-const { t } = useI18n();
-
-export default defineComponent({
-  name: 'BasicFormAction',
-  props: {
-    show: propTypes.bool.def(true),
-    showResetButton: propTypes.bool.def(true),
-    showSubmitButton: propTypes.bool.def(true),
-    showAdvancedButton: propTypes.bool.def(true),
-    resetButtonOptions: {
-      type: Object as PropType<any>,
-      default: {},
-    },
-    submitButtonOptions: {
-      type: Object as PropType<any>,
-      default: {},
-    },
-    actionColOptions: {
-      type: Object as PropType<any>,
-      default: {},
-    },
-    actionSpan: propTypes.number.def(6),
-    isAdvanced: propTypes.bool,
-    hideAdvanceBtn: propTypes.bool,
-  },
-  emits: ['toggle-advanced'],
-  setup(props, { slots, emit }) {
-    const getResetBtnOptionsRef = computed(() => {
-      return {
-        text: t('component.form.resetButton'),
-        ...props.resetButtonOptions,
-      };
-    });
-
-    const getSubmitBtnOptionsRef = computed(() => {
-      return {
-        text: t('component.form.submitButton'),
-        // htmlType: 'submit',
-        ...props.submitButtonOptions,
-      };
-    });
-
-    const actionColOpt = computed(() => {
-      const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
-      const actionSpan = 24 - span;
-      const advancedSpanObj = showAdvancedButton ? { span: actionSpan < 6 ? 24 : actionSpan } : {};
-      const actionColOpt: Partial<ColEx> = {
-        span: showAdvancedButton ? 6 : 4,
-        ...advancedSpanObj,
-        ...actionColOptions,
-      };
-      return actionColOpt;
-    });
-
-    function toggleAdvanced() {
-      emit('toggle-advanced');
-    }
-
-    function renderAdvanceButton() {
-      const { showAdvancedButton, hideAdvanceBtn, isAdvanced } = props;
-
-      if (!showAdvancedButton || !!hideAdvanceBtn) {
-        return null;
-      }
-      return (
-        <Button type="default" class="mr-2" onClick={toggleAdvanced}>
-          {() => (
-            <>
-              {isAdvanced ? t('component.form.putAway') : t('component.form.unfold')}
-              <BasicArrow expand={!isAdvanced} top />
-            </>
-          )}
-        </Button>
-      );
-    }
-
-    function renderResetButton() {
-      const { showResetButton } = props;
-      if (!showResetButton) {
-        return null;
-      }
-      return (
-        <Button type="default" class="mr-2" {...unref(getResetBtnOptionsRef)}>
-          {() => unref(getResetBtnOptionsRef).text}
-        </Button>
-      );
-    }
-
-    function renderSubmitButton() {
-      const { showSubmitButton } = props;
-      if (!showSubmitButton) {
-        return null;
-      }
-      return (
-        <Button type="primary" {...unref(getSubmitBtnOptionsRef)}>
-          {() => unref(getSubmitBtnOptionsRef).text}
-        </Button>
-      );
-    }
-
-    return () => {
-      if (!props.show) {
-        return null;
-      }
-
-      return (
-        <Col {...unref(actionColOpt)} style={{ textAlign: 'right' }}>
-          {() => (
-            <Form.Item>
-              {() => (
-                <>
-                  {getSlot(slots, 'advanceBefore')}
-                  {renderAdvanceButton()}
-
-                  {getSlot(slots, 'resetBefore')}
-                  {renderResetButton()}
-
-                  {getSlot(slots, 'submitBefore')}
-                  {renderSubmitButton()}
-
-                  {getSlot(slots, 'submitAfter')}
-                </>
-              )}
-            </Form.Item>
-          )}
-        </Col>
-      );
-    };
-  },
-});
diff --git a/src/components/Form/src/componentMap.ts b/src/components/Form/src/componentMap.ts
index b86e7b3..bf63b4d 100644
--- a/src/components/Form/src/componentMap.ts
+++ b/src/components/Form/src/componentMap.ts
@@ -1,4 +1,4 @@
-import { Component } from 'vue';
+import type { Component } from 'vue';
 import type { ComponentType } from './types/index';
 
 /**
@@ -17,10 +17,11 @@
   TimePicker,
   TreeSelect,
 } from 'ant-design-vue';
+
 import RadioButtonGroup from './components/RadioButtonGroup.vue';
 import { BasicUpload } from '/@/components/Upload';
 
-const componentMap = new Map<ComponentType, any>();
+const componentMap = new Map<ComponentType, Component>();
 
 componentMap.set('Input', Input);
 componentMap.set('InputGroup', Input.Group);
diff --git a/src/components/Form/src/components/FormAction.vue b/src/components/Form/src/components/FormAction.vue
new file mode 100644
index 0000000..4c47ea8
--- /dev/null
+++ b/src/components/Form/src/components/FormAction.vue
@@ -0,0 +1,139 @@
+<template>
+  <a-col
+    v-bind="actionColOpt"
+    class="mb-2"
+    :style="{ textAlign: 'right' }"
+    v-if="showActionButtonGroup"
+  >
+    <FormItem>
+      <slot name="resetBefore" />
+      <Button
+        type="default"
+        class="mr-2"
+        v-bind="getResetBtnOptions"
+        @click="resetAction"
+        v-if="showResetButton"
+      >
+        {{ getResetBtnOptions.text }}
+      </Button>
+      <slot name="submitBefore" />
+
+      <Button
+        type="primary"
+        class="mr-2"
+        v-bind="getSubmitBtnOptions"
+        @click="submitAction"
+        v-if="showSubmitButton"
+      >
+        {{ getSubmitBtnOptions.text }}
+      </Button>
+
+      <slot name="advanceBefore" />
+      <Button
+        type="link"
+        size="small"
+        @click="toggleAdvanced"
+        v-if="showAdvancedButton && !hideAdvanceBtn"
+      >
+        {{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}
+        <BasicArrow class="ml-1" :expand="!isAdvanced" top />
+      </Button>
+      <slot name="advanceAfter" />
+    </FormItem>
+  </a-col>
+</template>
+<script lang="ts">
+  import type { ColEx } from '../types/index';
+  import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
+
+  import { defineComponent, computed, PropType } from 'vue';
+  import { Form } from 'ant-design-vue';
+  import { Button } from '/@/components/Button';
+  import { BasicArrow } from '/@/components/Basic/index';
+  import { useFormContext } from '../hooks/useFormContext';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { propTypes } from '/@/utils/propTypes';
+
+  type ButtonOptions = Partial<ButtonProps> & { text: string };
+
+  export default defineComponent({
+    name: 'BasicFormAction',
+    components: {
+      FormItem: Form,
+      Button,
+      BasicArrow,
+    },
+    props: {
+      showActionButtonGroup: propTypes.bool.def(true),
+      showResetButton: propTypes.bool.def(true),
+      showSubmitButton: propTypes.bool.def(true),
+      showAdvancedButton: propTypes.bool.def(true),
+      resetButtonOptions: {
+        type: Object as PropType<ButtonOptions>,
+        default: {},
+      },
+      submitButtonOptions: {
+        type: Object as PropType<ButtonOptions>,
+        default: {},
+      },
+      actionColOptions: {
+        type: Object as PropType<Partial<ColEx>>,
+        default: {},
+      },
+      actionSpan: propTypes.number.def(6),
+      isAdvanced: propTypes.bool,
+      hideAdvanceBtn: propTypes.bool,
+    },
+    setup(props, { emit }) {
+      const { t } = useI18n();
+
+      const actionColOpt = computed(() => {
+        const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
+        const actionSpan = 24 - span;
+        const advancedSpanObj = showAdvancedButton
+          ? { span: actionSpan < 6 ? 24 : actionSpan }
+          : {};
+        const actionColOpt: Partial<ColEx> = {
+          span: showAdvancedButton ? 6 : 4,
+          ...advancedSpanObj,
+          ...actionColOptions,
+        };
+        return actionColOpt;
+      });
+
+      const getResetBtnOptions = computed(
+        (): ButtonOptions => {
+          return Object.assign(
+            {
+              text: t('component.form.resetButton'),
+            },
+            props.resetButtonOptions
+          );
+        }
+      );
+
+      const getSubmitBtnOptions = computed(() => {
+        return Object.assign(
+          {
+            text: t('component.form.submitButton'),
+          },
+          props.submitButtonOptions
+        );
+      });
+
+      function toggleAdvanced() {
+        emit('toggle-advanced');
+      }
+
+      return {
+        t,
+        actionColOpt,
+        getResetBtnOptions,
+        getSubmitBtnOptions,
+        toggleAdvanced,
+        ...useFormContext(),
+      };
+    },
+  });
+</script>
diff --git a/src/components/Form/src/FormItem.tsx b/src/components/Form/src/components/FormItem.tsx
similarity index 74%
rename from src/components/Form/src/FormItem.tsx
rename to src/components/Form/src/components/FormItem.tsx
index 50eab6f..e952f27 100644
--- a/src/components/Form/src/FormItem.tsx
+++ b/src/components/Form/src/components/FormItem.tsx
@@ -1,21 +1,21 @@
-import type { PropType } from 'vue';
-import type { FormActionType, FormProps } from './types/form';
-import type { FormSchema } from './types/form';
+import type { PropType, Ref } from 'vue';
+import type { FormActionType, FormProps } from '../types/form';
+import type { FormSchema } from '../types/form';
 import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
 import type { TableActionType } from '/@/components/Table';
+import type { ComponentType } from '../types';
 
-import { defineComponent, computed, unref, toRef } from 'vue';
+import { defineComponent, computed, unref, toRefs } from 'vue';
 import { Form, Col } from 'ant-design-vue';
-import { componentMap } from './componentMap';
+import { componentMap } from '../componentMap';
 import { BasicHelp } from '/@/components/Basic';
 
 import { isBoolean, isFunction } from '/@/utils/is';
 import { getSlot } from '/@/utils/helper/tsxHelper';
-import { createPlaceholderMessage } from './helper';
+import { createPlaceholderMessage, setComponentRuleType } from '../helper';
 import { upperFirst, cloneDeep } from 'lodash-es';
 
-import { useItemLabelWidth } from './hooks/useLabelWidth';
-import { ComponentType } from './types';
+import { useItemLabelWidth } from '../hooks/useLabelWidth';
 import { isNumber } from '/@/utils/is';
 import { useI18n } from '/@/hooks/web/useI18n';
 
@@ -32,12 +32,16 @@
       default: {},
     },
     allDefaultValues: {
-      type: Object as PropType<any>,
+      type: Object as PropType<Recordable>,
       default: {},
     },
     formModel: {
-      type: Object as PropType<any>,
+      type: Object as PropType<Recordable>,
       default: {},
+    },
+    setFormModel: {
+      type: Function as PropType<(key: string, value: any) => void>,
+      default: null,
     },
     tableAction: {
       type: Object as PropType<TableActionType>,
@@ -48,10 +52,15 @@
   },
   setup(props, { slots }) {
     const { t } = useI18n();
-    // @ts-ignore
-    const itemLabelWidthRef = useItemLabelWidth(toRef(props, 'schema'), toRef(props, 'formProps'));
 
-    const getValuesRef = computed(() => {
+    const { schema, formProps } = toRefs(props) as {
+      schema: Ref<FormSchema>;
+      formProps: Ref<FormProps>;
+    };
+
+    const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
+
+    const getValues = computed(() => {
       const { allDefaultValues, formModel, schema } = props;
       const { mergeDynamicData } = props.formProps;
       return {
@@ -61,12 +70,12 @@
           ...mergeDynamicData,
           ...allDefaultValues,
           ...formModel,
-        },
+        } as Recordable,
         schema: schema,
       };
     });
 
-    const getComponentsPropsRef = computed(() => {
+    const getComponentsProps = computed(() => {
       const { schema, tableAction, formModel, formActionType } = props;
       const { componentProps = {} } = schema;
       if (!isFunction(componentProps)) {
@@ -75,19 +84,18 @@
       return componentProps({ schema, tableAction, formModel, formActionType }) || {};
     });
 
-    const getDisableRef = computed(() => {
+    const getDisable = computed(() => {
       const { disabled: globDisabled } = props.formProps;
       const { dynamicDisabled } = props.schema;
-      const { disabled: itemDisabled = false } = unref(getComponentsPropsRef);
+      const { disabled: itemDisabled = false } = unref(getComponentsProps);
       let disabled = !!globDisabled || itemDisabled;
       if (isBoolean(dynamicDisabled)) {
         disabled = dynamicDisabled;
       }
 
       if (isFunction(dynamicDisabled)) {
-        disabled = dynamicDisabled(unref(getValuesRef));
+        disabled = dynamicDisabled(unref(getValues));
       }
-
       return disabled;
     });
 
@@ -109,10 +117,10 @@
         isIfShow = ifShow;
       }
       if (isFunction(show)) {
-        isShow = show(unref(getValuesRef));
+        isShow = show(unref(getValues));
       }
       if (isFunction(ifShow)) {
-        isIfShow = ifShow(unref(getValuesRef));
+        isIfShow = ifShow(unref(getValues));
       }
       isShow = isShow && itemIsAdvanced;
       return { isShow, isIfShow };
@@ -129,7 +137,7 @@
       } = props.schema;
 
       if (isFunction(dynamicRules)) {
-        return dynamicRules(unref(getValuesRef)) as ValidationRule[];
+        return dynamicRules(unref(getValues)) as ValidationRule[];
       }
 
       let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
@@ -151,23 +159,15 @@
           const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
             ? rulesMessageJoinLabel
             : globalRulesMessageJoinLabel;
+
           rule.message =
             rule.message || createPlaceholderMessage(component) + `${joinLabel ? label : ''}`;
+
           if (component.includes('Input') || component.includes('Textarea')) {
             rule.whitespace = true;
           }
-          if (
-            component.includes('DatePicker') ||
-            component.includes('MonthPicker') ||
-            component.includes('WeekPicker') ||
-            component.includes('TimePicker')
-          ) {
-            rule.type = 'object';
-          } else if (component.includes('RangePicker') || component.includes('Upload')) {
-            rule.type = 'array';
-          } else if (component.includes('InputNumber')) {
-            rule.type = 'number';
-          }
+
+          setComponentRuleType(rule, component);
         }
       }
 
@@ -181,10 +181,12 @@
     }
 
     function handleValue(component: ComponentType, field: string) {
-      const val = (props.formModel as any)[field];
+      const val = props.formModel[field];
       if (['Input', 'InputPassword', 'InputSearch', 'InputTextArea'].includes(component)) {
         if (val && isNumber(val)) {
-          (props.formModel as any)[field] = `${val}`;
+          props.setFormModel(field, `${val}`);
+
+          // props.formModel[field] = `${val}`;
           return `${val}`;
         }
         return val;
@@ -206,56 +208,59 @@
       const eventKey = `on${upperFirst(changeEvent)}`;
 
       const on = {
-        [eventKey]: (e: any) => {
+        [eventKey]: (e: Nullable<Recordable>) => {
           if (propsData[eventKey]) {
             propsData[eventKey](e);
           }
 
           const target = e ? e.target : null;
+
           const value = target ? (isCheck ? target.checked : target.value) : e;
-          (props.formModel as any)[field] = value;
+          props.setFormModel(field, value);
+          // props.formModel[field] = value;
         },
       };
-      const Comp = componentMap.get(component);
+      const Comp = componentMap.get(component) as typeof defineComponent;
 
       const { autoSetPlaceHolder, size } = props.formProps;
-      const propsData: any = {
+      const propsData: Recordable = {
         allowClear: true,
         getPopupContainer: (trigger: Element) => trigger.parentNode,
         size,
-        ...unref(getComponentsPropsRef),
-        disabled: unref(getDisableRef),
+        ...unref(getComponentsProps),
+        disabled: unref(getDisable),
       };
 
       const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
       let placeholder;
       // RangePicker place涓烘暟缁�
       if (isCreatePlaceholder && component !== 'RangePicker' && component) {
-        placeholder =
-          (unref(getComponentsPropsRef) && unref(getComponentsPropsRef).placeholder) ||
-          createPlaceholderMessage(component);
+        placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component);
       }
       propsData.placeholder = placeholder;
       propsData.codeField = field;
-      propsData.formValues = unref(getValuesRef);
-      const bindValue = {
+      propsData.formValues = unref(getValues);
+
+      const bindValue: Recordable = {
         [valueField || (isCheck ? 'checked' : 'value')]: handleValue(component, field),
       };
 
+      const compAttr: Recordable = {
+        ...propsData,
+        ...on,
+        ...bindValue,
+      };
+
       if (!renderComponentContent) {
-        return <Comp {...propsData} {...on} {...bindValue} />;
+        return <Comp {...compAttr} />;
       }
       const compSlot = isFunction(renderComponentContent)
-        ? { ...renderComponentContent(unref(getValuesRef)) }
+        ? { ...renderComponentContent(unref(getValues)) }
         : {
             default: () => renderComponentContent,
           };
 
-      return (
-        <Comp {...propsData} {...on} {...bindValue}>
-          {compSlot}
-        </Comp>
-      );
+      return <Comp {...compAttr}>{compSlot}</Comp>;
     }
 
     function renderLabelHelpMessage() {
@@ -280,20 +285,22 @@
 
     function renderItem() {
       const { itemProps, slot, render, field } = props.schema;
-      const { labelCol, wrapperCol } = unref(itemLabelWidthRef);
+      const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
       const { colon } = props.formProps;
+
       const getContent = () => {
         return slot
-          ? getSlot(slots, slot, unref(getValuesRef))
+          ? getSlot(slots, slot, unref(getValues))
           : render
-          ? render(unref(getValuesRef))
+          ? render(unref(getValues))
           : renderComponent();
       };
+
       return (
         <Form.Item
           name={field}
           colon={colon}
-          {...(itemProps as any)}
+          {...(itemProps as Recordable)}
           label={renderLabelHelpMessage()}
           rules={handleRules()}
           labelCol={labelCol}
@@ -306,20 +313,23 @@
     return () => {
       const { colProps = {}, colSlot, renderColContent, component } = props.schema;
       if (!componentMap.has(component)) return null;
+
       const { baseColProps = {} } = props.formProps;
 
       const realColProps = { ...baseColProps, ...colProps };
       const { isIfShow, isShow } = getShow();
+
       const getContent = () => {
         return colSlot
-          ? getSlot(slots, colSlot, unref(getValuesRef))
+          ? getSlot(slots, colSlot, unref(getValues))
           : renderColContent
-          ? renderColContent(unref(getValuesRef))
+          ? renderColContent(unref(getValues))
           : renderItem();
       };
+
       return (
         isIfShow && (
-          <Col {...realColProps} class={!isShow ? 'hidden' : ''}>
+          <Col {...realColProps} class={{ hidden: !isShow }}>
             {() => getContent()}
           </Col>
         )
diff --git a/src/components/Form/src/components/RadioButtonGroup.vue b/src/components/Form/src/components/RadioButtonGroup.vue
index 5585a62..a6bb774 100644
--- a/src/components/Form/src/components/RadioButtonGroup.vue
+++ b/src/components/Form/src/components/RadioButtonGroup.vue
@@ -1,18 +1,23 @@
+<!--
+ * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
+-->
+
 <template>
-  <RadioGroup v-bind="$attrs" v-model:value="valueRef" button-style="solid">
+  <RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
     <template v-for="item in getOptions" :key="`${item.value}`">
       <RadioButton :value="item.value"> {{ item.label }} </RadioButton>
     </template>
   </RadioGroup>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, PropType, watch, unref, computed } from 'vue';
+  import { defineComponent, PropType, computed } from 'vue';
   import { Radio } from 'ant-design-vue';
-  import {} from 'ant-design-vue/es/radio/Group';
   import { isString } from '/@/utils/is';
-
+  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { useAttrs } from '/@/hooks/core/useAttrs';
   type OptionsItem = { label: string; value: string; disabled?: boolean };
   type RadioItem = string | OptionsItem;
+
   export default defineComponent({
     name: 'RadioButtonGroup',
     components: {
@@ -28,34 +33,22 @@
         default: () => [],
       },
     },
-    setup(props, { emit }) {
-      const valueRef = ref('');
-
-      watch(
-        () => props.value,
-        (v = '') => {
-          valueRef.value = v;
-        },
-        { immediate: true }
-      );
-
-      watch(
-        () => unref(valueRef),
-        () => {
-          emit('change', valueRef.value);
-        },
-        { immediate: true }
-      );
-
+    setup(props) {
+      const attrs = useAttrs();
+      // Embedded in the form, just use the hook binding to perform form verification
+      const [state] = useRuleFormItem(props);
+      // Processing options value
       const getOptions = computed((): OptionsItem[] => {
         const { options } = props;
-        if (!options || options.length === 0) return [];
+        if (!options || options?.length === 0) return [];
+
         const isStringArr = options.some((item) => isString(item));
         if (!isStringArr) return options as OptionsItem[];
+
         return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
       });
 
-      return { valueRef, getOptions };
+      return { state, getOptions, attrs };
     },
   });
 </script>
diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts
index e1c64c3..938101e 100644
--- a/src/components/Form/src/helper.ts
+++ b/src/components/Form/src/helper.ts
@@ -1,3 +1,4 @@
+import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
 import type { ComponentType } from './types/index';
 import { useI18n } from '/@/hooks/web/useI18n';
 
@@ -30,6 +31,16 @@
   return ['DatePicker', 'MonthPicker', 'RangePicker', 'WeekPicker', 'TimePicker'];
 }
 
+export function setComponentRuleType(rule: ValidationRule, component: ComponentType) {
+  if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) {
+    rule.type = 'object';
+  } else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component)) {
+    rule.type = 'array';
+  } else if (['InputNumber'].includes(component)) {
+    rule.type = 'number';
+  }
+}
+
 /**
  * 鏃堕棿瀛楁
  */
diff --git a/src/components/Form/src/hooks/useAdvanced.ts b/src/components/Form/src/hooks/useAdvanced.ts
index 560751d..dee5c12 100644
--- a/src/components/Form/src/hooks/useAdvanced.ts
+++ b/src/components/Form/src/hooks/useAdvanced.ts
@@ -13,28 +13,28 @@
 interface UseAdvancedContext {
   advanceState: AdvanceState;
   emit: EmitType;
-  getMergePropsRef: ComputedRef<FormProps>;
   getProps: ComputedRef<FormProps>;
   getSchema: ComputedRef<FormSchema[]>;
-  formModel: any;
-  defaultValueRef: Ref<any>;
+  formModel: Recordable;
+  defaultValueRef: Ref<Recordable>;
 }
 
 export default function ({
   advanceState,
   emit,
-  getMergePropsRef,
   getProps,
   getSchema,
   formModel,
   defaultValueRef,
 }: UseAdvancedContext) {
   const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
-  const getEmptySpanRef = computed((): number => {
+
+  const getEmptySpan = computed((): number => {
     if (!advanceState.isAdvanced) {
       return 0;
     }
-    const emptySpan = unref(getMergePropsRef).emptySpan || 0;
+    // For some special cases, you need to manually specify additional blank lines
+    const emptySpan = unref(getProps).emptySpan || 0;
 
     if (isNumber(emptySpan)) {
       return emptySpan;
@@ -47,27 +47,6 @@
       return screenSpan || span || 0;
     }
     return 0;
-  });
-
-  const getActionPropsRef = computed(() => {
-    const {
-      resetButtonOptions,
-      submitButtonOptions,
-      showActionButtonGroup,
-      showResetButton,
-      showSubmitButton,
-      showAdvancedButton,
-      actionColOptions,
-    } = unref(getProps);
-    return {
-      resetButtonOptions,
-      submitButtonOptions,
-      show: showActionButtonGroup,
-      showResetButton,
-      showSubmitButton,
-      showAdvancedButton,
-      actionColOptions,
-    };
   });
 
   watch(
@@ -90,6 +69,7 @@
       parseInt(itemCol.sm as string) ||
       (itemCol.span as number) ||
       BASIC_COL_LEN;
+
     const lgWidth = parseInt(itemCol.lg as string) || mdWidth;
     const xlWidth = parseInt(itemCol.xl as string) || lgWidth;
     const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth;
@@ -102,15 +82,16 @@
     } else {
       itemColSum += xxlWidth;
     }
+
     if (isLastAction) {
       advanceState.hideAdvanceBtn = false;
       if (itemColSum <= BASIC_COL_LEN * 2) {
-        // 灏忎簬绛変簬2琛屾椂锛屼笉鏄剧ず鏀惰捣灞曞紑鎸夐挳
+        // When less than or equal to 2 lines, the collapse and expand buttons are not displayed
         advanceState.hideAdvanceBtn = true;
         advanceState.isAdvanced = true;
       } else if (
         itemColSum > BASIC_COL_LEN * 2 &&
-        itemColSum <= BASIC_COL_LEN * (unref(getMergePropsRef).autoAdvancedLine || 3)
+        itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)
       ) {
         advanceState.hideAdvanceBtn = false;
 
@@ -168,13 +149,9 @@
       }
     }
 
-    advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpanRef);
+    advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpan);
 
-    getAdvanced(
-      unref(getActionPropsRef).actionColOptions || { span: BASIC_COL_LEN },
-      itemColSum,
-      true
-    );
+    getAdvanced(unref(getProps).actionColOptions || { span: BASIC_COL_LEN }, itemColSum, true);
 
     emit('advanced-change');
   }
@@ -182,5 +159,6 @@
   function handleToggleAdvanced() {
     advanceState.isAdvanced = !advanceState.isAdvanced;
   }
-  return { getActionPropsRef, handleToggleAdvanced };
+
+  return { handleToggleAdvanced };
 }
diff --git a/src/components/Form/src/hooks/useComponentRegister.ts b/src/components/Form/src/hooks/useComponentRegister.ts
index 753e99b..d203480 100644
--- a/src/components/Form/src/hooks/useComponentRegister.ts
+++ b/src/components/Form/src/hooks/useComponentRegister.ts
@@ -1,7 +1,9 @@
 import type { ComponentType } from '../types/index';
 import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
 import { add, del } from '../componentMap';
-export function useComponentRegister(compName: ComponentType, comp: any) {
+import type { Component } from 'vue';
+
+export function useComponentRegister(compName: ComponentType, comp: Component) {
   add(compName, comp);
   tryOnUnmounted(() => {
     del(compName);
diff --git a/src/components/Form/src/hooks/useForm.ts b/src/components/Form/src/hooks/useForm.ts
index e856faf..4ba2ba9 100644
--- a/src/components/Form/src/hooks/useForm.ts
+++ b/src/components/Form/src/hooks/useForm.ts
@@ -1,23 +1,28 @@
-import { ref, onUnmounted, unref } from 'vue';
+import { ref, onUnmounted, unref, nextTick } from 'vue';
 
 import { isInSetup } from '/@/utils/helper/vueHelper';
 import { isProdMode } from '/@/utils/env';
+import { error } from '/@/utils/log';
 
 import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
 import type { NamePath } from 'ant-design-vue/lib/form/interface';
 
-export declare type ValidateFields = (nameList?: NamePath[]) => Promise<any>;
+export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
 
 export function useForm(props?: Partial<FormProps>): UseFormReturnType {
   isInSetup();
-  const formRef = ref<FormActionType | null>(null);
-  const loadedRef = ref<boolean | null>(false);
 
-  function getForm() {
+  const formRef = ref<Nullable<FormActionType>>(null);
+  const loadedRef = ref<Nullable<boolean>>(false);
+
+  async function getForm() {
     const form = unref(formRef);
     if (!form) {
-      throw new Error('formRef is Null');
+      error(
+        'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!'
+      );
     }
+    await nextTick();
     return form as FormActionType;
   }
   function register(instance: FormActionType) {
@@ -27,45 +32,73 @@
         loadedRef.value = null;
       });
     if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
+
     formRef.value = instance;
     props && instance.setProps(props);
     loadedRef.value = true;
   }
 
   const methods: FormActionType = {
-    setProps: (formProps: Partial<FormProps>) => {
-      getForm().setProps(formProps);
+    scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
+      const form = await getForm();
+      form.scrollToField(name, options);
     },
-    updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
-      getForm().updateSchema(data);
+    setProps: async (formProps: Partial<FormProps>) => {
+      const form = await getForm();
+      form.setProps(formProps);
     },
-    clearValidate: (name?: string | string[]) => {
-      getForm().clearValidate(name);
+
+    updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
+      const form = await getForm();
+      form.updateSchema(data);
     },
+
+    clearValidate: async (name?: string | string[]) => {
+      const form = await getForm();
+      form.clearValidate(name);
+    },
+
     resetFields: async () => {
-      await getForm().resetFields();
+      getForm().then(async (form) => {
+        await form.resetFields();
+      });
     },
-    removeSchemaByFiled: (field: string | string[]) => {
-      getForm().removeSchemaByFiled(field);
+
+    removeSchemaByFiled: async (field: string | string[]) => {
+      const form = await getForm();
+      form.removeSchemaByFiled(field);
     },
-    getFieldsValue: () => {
-      return getForm().getFieldsValue();
+
+    // TODO promisify
+    getFieldsValue: <T>() => {
+      return unref(formRef)?.getFieldsValue() as T;
     },
-    setFieldsValue: <T>(values: T) => {
-      getForm().setFieldsValue<T>(values);
+
+    setFieldsValue: async <T>(values: T) => {
+      const form = await getForm();
+      form.setFieldsValue<T>(values);
     },
-    appendSchemaByField: (schema: FormSchema, prefixField?: string | undefined) => {
-      getForm().appendSchemaByField(schema, prefixField);
+
+    appendSchemaByField: async (schema: FormSchema, prefixField?: string | undefined) => {
+      const form = await getForm();
+      form.appendSchemaByField(schema, prefixField);
     },
+
     submit: async (): Promise<any> => {
-      return getForm().submit();
+      const form = await getForm();
+      return form.submit();
     },
-    validate: ((async (nameList?: NamePath[]): Promise<any> => {
-      return getForm().validate(nameList);
-    }) as any) as ValidateFields,
-    validateFields: ((async (nameList?: NamePath[]): Promise<any> => {
-      return getForm().validate(nameList);
-    }) as any) as ValidateFields,
-  } as FormActionType;
+
+    validate: async (nameList?: NamePath[]): Promise<Recordable> => {
+      const form = await getForm();
+      return form.validate(nameList);
+    },
+
+    validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
+      const form = await getForm();
+      return form.validateFields(nameList);
+    },
+  };
+
   return [register, methods];
 }
diff --git a/src/components/Form/src/hooks/useFormContext.ts b/src/components/Form/src/hooks/useFormContext.ts
new file mode 100644
index 0000000..9bfc925
--- /dev/null
+++ b/src/components/Form/src/hooks/useFormContext.ts
@@ -0,0 +1,17 @@
+import { InjectionKey } from 'vue';
+import { createContext, useContext } from '/@/hooks/core/useContext';
+
+export interface FormContextProps {
+  resetAction: () => Promise<void>;
+  submitAction: () => Promise<void>;
+}
+
+const key: InjectionKey<FormContextProps> = Symbol();
+
+export function createFormContext(context: FormContextProps) {
+  return createContext<FormContextProps>(context, key);
+}
+
+export function useFormContext() {
+  return useContext<FormContextProps>(key);
+}
diff --git a/src/components/Form/src/hooks/useFormAction.ts b/src/components/Form/src/hooks/useFormEvents.ts
similarity index 70%
rename from src/components/Form/src/hooks/useFormAction.ts
rename to src/components/Form/src/hooks/useFormEvents.ts
index 1a156c4..74dc32d 100644
--- a/src/components/Form/src/hooks/useFormAction.ts
+++ b/src/components/Form/src/hooks/useFormEvents.ts
@@ -9,22 +9,19 @@
 import { dateItemType } from '../helper';
 import moment from 'moment';
 import { cloneDeep } from 'lodash-es';
+import { error } from '/@/utils/log';
 
 interface UseFormActionContext {
   emit: EmitType;
   getProps: ComputedRef<FormProps>;
   getSchema: ComputedRef<FormSchema[]>;
-  formModel: any;
-  defaultValueRef: Ref<any>;
+  formModel: Recordable;
+  defaultValueRef: Ref<Recordable>;
   formElRef: Ref<FormActionType>;
   schemaRef: Ref<FormSchema[]>;
   handleFormValues: Fn;
-  actionState: {
-    resetAction: any;
-    submitAction: any;
-  };
 }
-export function useFormAction({
+export function useFormEvents({
   emit,
   getProps,
   formModel,
@@ -33,34 +30,34 @@
   formElRef,
   schemaRef,
   handleFormValues,
-  actionState,
 }: UseFormActionContext) {
-  async function resetFields(): Promise<any> {
+  async function resetFields(): Promise<void> {
     const { resetFunc, submitOnReset } = unref(getProps);
     resetFunc && isFunction(resetFunc) && (await resetFunc());
+
     const formEl = unref(formElRef);
     if (!formEl) return;
+
     Object.keys(formModel).forEach((key) => {
-      (formModel as any)[key] = defaultValueRef.value[key];
+      formModel[key] = defaultValueRef.value[key];
     });
     clearValidate();
     emit('reset', toRaw(formModel));
-    // return values;
     submitOnReset && handleSubmit();
   }
 
   /**
-   * @description: 璁剧疆琛ㄥ崟鍊�
+   * @description: Set form value
    */
   async function setFieldsValue(values: any): Promise<void> {
     const fields = unref(getSchema)
       .map((item) => item.field)
       .filter(Boolean);
-    // const formEl = unref(formElRef);
 
     const validKeys: string[] = [];
     Object.keys(values).forEach((key) => {
       const element = values[key];
+      // 0| '' is allow
       if (element !== undefined && element !== null && fields.includes(key)) {
         // time type
         if (itemIsDateType(key)) {
@@ -69,12 +66,12 @@
             for (const ele of element) {
               arr.push(moment(ele));
             }
-            (formModel as any)[key] = arr;
+            formModel[key] = arr;
           } else {
-            (formModel as any)[key] = moment(element);
+            formModel[key] = moment(element);
           }
         } else {
-          (formModel as any)[key] = element;
+          formModel[key] = element;
         }
         validKeys.push(key);
       }
@@ -84,19 +81,18 @@
   /**
    * @description: Delete based on field name
    */
-  function removeSchemaByFiled(fields: string | string[]): void {
+  async function removeSchemaByFiled(fields: string | string[]): Promise<void> {
     const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
-    if (!fields) {
-      return;
-    }
-    let fieldList: string[] = fields as string[];
+    if (!fields) return;
+
+    let fieldList: string[] = isString(fields) ? [fields] : fields;
     if (isString(fields)) {
       fieldList = [fields];
     }
     for (const field of fieldList) {
       _removeSchemaByFiled(field, schemaList);
     }
-    schemaRef.value = schemaList as any;
+    schemaRef.value = schemaList;
   }
 
   /**
@@ -114,27 +110,26 @@
   /**
    * @description: Insert after a certain field, if not insert the last
    */
-  function appendSchemaByField(schema: FormSchema, prefixField?: string) {
+  async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
     const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
 
     const index = schemaList.findIndex((schema) => schema.field === prefixField);
-    const hasInList = schemaList.find((item) => item.field === schema.field);
+    const hasInList = schemaList.some((item) => item.field === schema.field);
 
-    if (hasInList) {
-      return;
-    }
-    if (!prefixField || index === -1) {
-      schemaList.push(schema);
-      schemaRef.value = schemaList as any;
+    if (!hasInList) return;
+
+    if (!prefixField || index === -1 || first) {
+      first ? schemaList.unshift(schema) : schemaList.push(schema);
+      schemaRef.value = schemaList;
       return;
     }
     if (index !== -1) {
       schemaList.splice(index + 1, 0, schema);
     }
-    schemaRef.value = schemaList as any;
+    schemaRef.value = schemaList;
   }
 
-  function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
+  async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
     let updateData: Partial<FormSchema>[] = [];
     if (isObject(data)) {
       updateData.push(data as FormSchema);
@@ -142,9 +137,13 @@
     if (isArray(data)) {
       updateData = [...data];
     }
+
     const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);
+
     if (!hasField) {
-      throw new Error('Must pass in the `field` field!');
+      error(
+        'All children of the form Schema array that need to be updated must contain the `field` field'
+      );
     }
     const schema: FormSchema[] = [];
     updateData.forEach((item) => {
@@ -157,12 +156,12 @@
         }
       });
     });
-    schemaRef.value = unique(schema, 'field') as any;
+    schemaRef.value = unique(schema, 'field');
   }
 
-  function getFieldsValue(): any {
+  function getFieldsValue(): Recordable {
     const formEl = unref(formElRef);
-    if (!formEl) return;
+    if (!formEl) return {};
     return handleFormValues(toRaw(unref(formModel)));
   }
 
@@ -171,23 +170,24 @@
    */
   function itemIsDateType(key: string) {
     return unref(getSchema).some((item) => {
-      return item.field === key ? dateItemType.includes(item.component!) : false;
+      return item.field === key ? dateItemType.includes(item.component) : false;
     });
   }
 
-  function validateFields(nameList?: NamePath[] | undefined) {
-    if (!formElRef.value) return;
-    return formElRef.value.validateFields(nameList);
+  async function validateFields(nameList?: NamePath[] | undefined) {
+    return await unref(formElRef)?.validateFields(nameList);
   }
 
-  function validate(nameList?: NamePath[] | undefined) {
-    if (!formElRef.value) return;
-    return formElRef.value.validate(nameList);
+  async function validate(nameList?: NamePath[] | undefined) {
+    return await unref(formElRef)?.validate(nameList);
   }
 
-  function clearValidate(name?: string | string[]) {
-    if (!formElRef.value) return;
-    formElRef.value.clearValidate(name);
+  async function clearValidate(name?: string | string[]) {
+    await unref(formElRef)?.clearValidate(name);
+  }
+
+  async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) {
+    await unref(formElRef)?.scrollToField(name, options);
   }
 
   /**
@@ -208,13 +208,6 @@
       emit('submit', res);
     } catch (error) {}
   }
-  actionState.resetAction = {
-    onClick: resetFields,
-  };
-
-  actionState.submitAction = {
-    onClick: handleSubmit,
-  };
 
   return {
     handleSubmit,
@@ -227,5 +220,6 @@
     removeSchemaByFiled,
     resetFields,
     setFieldsValue,
+    scrollToField,
   };
 }
diff --git a/src/components/Form/src/hooks/useFormValues.ts b/src/components/Form/src/hooks/useFormValues.ts
index 428f83d..2514cb2 100644
--- a/src/components/Form/src/hooks/useFormValues.ts
+++ b/src/components/Form/src/hooks/useFormValues.ts
@@ -9,7 +9,7 @@
   fieldMapToTimeRef: Ref<FieldMapToTime>;
   defaultValueRef: Ref<any>;
   getSchema: ComputedRef<FormSchema[]>;
-  formModel: any;
+  formModel: Recordable;
 }
 export function useFormValues({
   transformDateFuncRef,
@@ -19,11 +19,11 @@
   formModel,
 }: UseFormValuesContext) {
   // Processing form values
-  function handleFormValues(values: Record<string, any>) {
+  function handleFormValues(values: Recordable) {
     if (!isObject(values)) {
       return {};
     }
-    const resMap: Record<string, any> = {};
+    const res: Recordable = {};
     for (const item of Object.entries(values)) {
       let [, value] = item;
       const [key] = item;
@@ -41,15 +41,15 @@
       if (isString(value)) {
         value = value.trim();
       }
-      resMap[key] = value;
+      res[key] = value;
     }
-    return handleRangeTimeValue(resMap);
+    return handleRangeTimeValue(res);
   }
 
   /**
    * @description: Processing time interval parameters
    */
-  function handleRangeTimeValue(values: Record<string, any>) {
+  function handleRangeTimeValue(values: Recordable) {
     const fieldMapToTime = unref(fieldMapToTimeRef);
 
     if (!fieldMapToTime || !Array.isArray(fieldMapToTime)) {
@@ -65,6 +65,7 @@
 
       values[startTimeKey] = moment(startTime).format(format);
       values[endTimeKey] = moment(endTime).format(format);
+      Reflect.deleteProperty(values, field);
     }
 
     return values;
@@ -72,11 +73,11 @@
 
   function initDefault() {
     const schemas = unref(getSchema);
-    const obj: Record<string, any> = {};
+    const obj: Recordable = {};
     schemas.forEach((item) => {
       if (item.defaultValue) {
         obj[item.field] = item.defaultValue;
-        (formModel as any)[item.field] = item.defaultValue;
+        formModel[item.field] = item.defaultValue;
       }
     });
     defaultValueRef.value = obj;
diff --git a/src/components/Form/src/hooks/useLabelWidth.ts b/src/components/Form/src/hooks/useLabelWidth.ts
index 522f44d..ae4274d 100644
--- a/src/components/Form/src/hooks/useLabelWidth.ts
+++ b/src/components/Form/src/hooks/useLabelWidth.ts
@@ -4,23 +4,8 @@
 import { computed, unref } from 'vue';
 import { isNumber } from '/@/utils/is';
 
-// export function useGlobalLabelWidth(propsRef: ComputedRef<FormProps>) {
-//   return computed(() => {
-//     const { labelWidth, labelCol, wrapperCol } = unref(propsRef);
-//     if (!labelWidth) {
-//       return { labelCol, wrapperCol };
-//     }
-
-//     const width = isNumber(labelWidth) ? `${labelWidth}px` : labelWidth;
-//     return {
-//       labelCol: { style: { width }, span: 1, ...labelCol },
-//       wrapperCol: { style: { width: `calc(100% - ${width})` }, span: 23, ...wrapperCol },
-//     };
-//   });
-// }
-
 export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
-  return computed((): any => {
+  return computed(() => {
     const schemaItem = unref(schemaItemRef);
     const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {};
     const { labelWidth, disabledLabelWidth } = schemaItem;
@@ -29,7 +14,7 @@
       labelWidth: globalLabelWidth,
       labelCol: globalLabelCol,
       wrapperCol: globWrapperCol,
-    } = unref(propsRef) as any;
+    } = unref(propsRef);
 
     // If labelWidth is set globally, all items setting
     if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
diff --git a/src/components/Form/src/props.ts b/src/components/Form/src/props.ts
index 2b55070..8dc5fb9 100644
--- a/src/components/Form/src/props.ts
+++ b/src/components/Form/src/props.ts
@@ -1,11 +1,14 @@
 import type { FieldMapToTime, FormSchema } from './types/form';
-import type { PropType } from 'vue';
+import type { CSSProperties, PropType } from 'vue';
 import type { ColEx } from './types';
-import { TableActionType } from '/@/components/Table';
+import type { TableActionType } from '/@/components/Table';
+import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
+
+import { propTypes } from '/@/utils/propTypes';
 
 export const basicProps = {
   model: {
-    type: Object as PropType<Record<string, any>>,
+    type: Object as PropType<Recordable>,
     default: {},
   },
   // 鏍囩瀹藉害  鍥哄畾瀹藉害
@@ -17,7 +20,7 @@
     type: Array as PropType<FieldMapToTime>,
     default: () => [],
   },
-  compact: Boolean as PropType<boolean>,
+  compact: propTypes.bool,
   // 琛ㄥ崟閰嶇疆瑙勫垯
   schemas: {
     type: [Array] as PropType<FormSchema[]>,
@@ -25,98 +28,68 @@
     required: true,
   },
   mergeDynamicData: {
-    type: Object as PropType<any>,
+    type: Object as PropType<Recordable>,
     default: null,
   },
   baseRowStyle: {
-    type: Object as PropType<any>,
+    type: Object as PropType<CSSProperties>,
   },
   baseColProps: {
-    type: Object as PropType<any>,
+    type: Object as PropType<Partial<ColEx>>,
   },
-  autoSetPlaceHolder: {
-    type: Boolean,
-    default: true,
-  },
-  submitOnReset: {
-    type: Boolean,
-    default: false,
-  },
-  size: {
-    type: String as PropType<'default' | 'small' | 'large'>,
-    default: 'default',
-  },
+  autoSetPlaceHolder: propTypes.bool.def(true),
+  submitOnReset: propTypes.bool,
+  size: propTypes.oneOf(['default', 'small', 'large']).def('default'),
   // 绂佺敤琛ㄥ崟
-  disabled: Boolean as PropType<boolean>,
+  disabled: propTypes.bool,
   emptySpan: {
     type: [Number, Object] as PropType<number>,
     default: 0,
   },
   // 鏄惁鏄剧ず鏀惰捣灞曞紑鎸夐挳
-  showAdvancedButton: { type: Boolean as PropType<boolean>, default: false },
+  showAdvancedButton: propTypes.bool,
   // 杞寲鏃堕棿
   transformDateFunc: {
     type: Function as PropType<Fn>,
     default: (date: any) => {
-      return date._isAMomentObject ? date.format('YYYY-MM-DD HH:mm:ss') : date;
+      return date._isAMomentObject ? date?.format('YYYY-MM-DD HH:mm:ss') : date;
     },
   },
-  rulesMessageJoinLabel: {
-    type: Boolean,
-    default: true,
-  },
+  rulesMessageJoinLabel: propTypes.bool.def(true),
   // 瓒呰繃3琛岃嚜鍔ㄦ姌鍙�
-  autoAdvancedLine: {
-    type: Number as PropType<number>,
-    default: 3,
-  },
+  autoAdvancedLine: propTypes.number.def(3),
 
   // 鏄惁鏄剧ず鎿嶄綔鎸夐挳
-  showActionButtonGroup: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showActionButtonGroup: propTypes.bool.def(true),
   // 鎿嶄綔鍒桟ol閰嶇疆
-  actionColOptions: Object as PropType<ColEx>,
+  actionColOptions: Object as PropType<Partial<ColEx>>,
   // 鏄剧ず閲嶇疆鎸夐挳
-  showResetButton: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showResetButton: propTypes.bool.def(true),
   // 閲嶇疆鎸夐挳閰嶇疆
-  resetButtonOptions: Object as PropType<any>,
+  resetButtonOptions: Object as PropType<Partial<ButtonProps>>,
 
   // 鏄剧ず纭鎸夐挳
-  showSubmitButton: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showSubmitButton: propTypes.bool.def(true),
   // 纭鎸夐挳閰嶇疆
-  submitButtonOptions: Object as PropType<any>,
+  submitButtonOptions: Object as PropType<Partial<ButtonProps>>,
 
   // 鑷畾涔夐噸缃嚱鏁�
-  resetFunc: Function as PropType<Fn>,
-  submitFunc: Function as PropType<Fn>,
+  resetFunc: Function as PropType<() => Promise<void>>,
+  submitFunc: Function as PropType<() => Promise<void>>,
 
   // 浠ヤ笅涓洪粯璁rops
-  hideRequiredMark: Boolean as PropType<boolean>,
+  hideRequiredMark: propTypes.bool,
 
-  labelCol: Object as PropType<ColEx>,
+  labelCol: Object as PropType<Partial<ColEx>>,
 
-  layout: {
-    type: String as PropType<'horizontal' | 'vertical' | 'inline'>,
-    default: 'horizontal',
-  },
+  layout: propTypes.oneOf(['horizontal', 'vertical', 'inline']).def('horizontal'),
   tableAction: {
     type: Object as PropType<TableActionType>,
   },
 
-  wrapperCol: Object as PropType<any>,
+  wrapperCol: Object as PropType<Partial<ColEx>>,
 
-  colon: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
+  colon: propTypes.bool,
 
-  labelAlign: String as PropType<string>,
+  labelAlign: propTypes.string,
 };
diff --git a/src/components/Form/src/types/form.ts b/src/components/Form/src/types/form.ts
index b12713a..78c8567 100644
--- a/src/components/Form/src/types/form.ts
+++ b/src/components/Form/src/types/form.ts
@@ -5,6 +5,7 @@
 import type { FormItem } from './formItem';
 import type { ColEx, ComponentType } from './index';
 import type { TableActionType } from '/@/components/Table/src/types/table';
+import type { CSSProperties } from 'vue';
 
 export type FieldMapToTime = [string, [string, string], string?][];
 
@@ -14,8 +15,8 @@
 
 export interface RenderCallbackParams {
   schema: FormSchema;
-  values: any;
-  model: any;
+  values: Recordable;
+  model: Recordable;
   field: string;
 }
 
@@ -25,18 +26,19 @@
 
 export interface FormActionType {
   submit: () => Promise<void>;
-  setFieldsValue: <T>(values: T) => void;
-  resetFields: () => Promise<any>;
-  getFieldsValue: () => any;
-  clearValidate: (name?: string | string[]) => void;
-  updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => void;
-  setProps: (formProps: Partial<FormProps>) => void;
-  removeSchemaByFiled: (field: string | string[]) => void;
-  appendSchemaByField: (schema: FormSchema, prefixField?: string) => void;
+  setFieldsValue: <T>(values: T) => Promise<void>;
+  resetFields: () => Promise<void>;
+  getFieldsValue: () => Recordable;
+  clearValidate: (name?: string | string[]) => Promise<void>;
+  updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
+  setProps: (formProps: Partial<FormProps>) => Promise<void>;
+  removeSchemaByFiled: (field: string | string[]) => Promise<void>;
+  appendSchemaByField: (schema: FormSchema, prefixField?: string) => Promise<void>;
   validateFields: (nameList?: NamePath[]) => Promise<any>;
   validate: (nameList?: NamePath[]) => Promise<any>;
-  scrollToField: (name: NamePath, options?: ScrollOptions) => void;
+  scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
 }
+
 export type RegisterFn = (formInstance: FormActionType) => void;
 
 export type UseFormReturnType = [RegisterFn, FormActionType];
@@ -44,7 +46,7 @@
 export interface FormProps {
   // layout?: 'vertical' | 'inline' | 'horizontal';
   // Form value
-  model?: any;
+  model?: Recordable;
   // The width of all items in the entire form
   labelWidth?: number | string;
   // Submit form on reset
@@ -55,7 +57,7 @@
   wrapperCol?: Partial<ColEx>;
 
   // General row style
-  baseRowStyle?: object;
+  baseRowStyle?: CSSProperties;
 
   // General col configuration
   baseColProps?: Partial<ColEx>;
@@ -63,7 +65,7 @@
   // Form configuration rules
   schemas?: FormSchema[];
   // Function values used to merge into dynamic control form items
-  mergeDynamicData?: any;
+  mergeDynamicData?: Recordable;
   // Compact mode for search forms
   compact?: boolean;
   // Blank line span
@@ -131,8 +133,8 @@
         schema: FormSchema;
         tableAction: TableActionType;
         formActionType: FormActionType;
-        formModel: any;
-      }) => any)
+        formModel: Recordable;
+      }) => Recordable)
     | object;
   // Required
   required?: boolean;
diff --git a/src/components/Modal/src/useModalContext.ts b/src/components/Modal/src/useModalContext.ts
index 6d8c2fb..94d4c4e 100644
--- a/src/components/Modal/src/useModalContext.ts
+++ b/src/components/Modal/src/useModalContext.ts
@@ -5,12 +5,12 @@
   redoModalHeight: () => void;
 }
 
-const modalContextInjectKey: InjectionKey<ModalContextProps> = Symbol();
+const key: InjectionKey<ModalContextProps> = Symbol();
 
 export function createModalContext(context: ModalContextProps) {
-  return createContext<ModalContextProps>(context, modalContextInjectKey);
+  return createContext<ModalContextProps>(context, key);
 }
 
 export function useModalContext() {
-  return useContext<ModalContextProps>(modalContextInjectKey);
+  return useContext<ModalContextProps>(key);
 }
diff --git a/src/components/Scrollbar/src/util.ts b/src/components/Scrollbar/src/util.ts
index 3d32d30..b7c4845 100644
--- a/src/components/Scrollbar/src/util.ts
+++ b/src/components/Scrollbar/src/util.ts
@@ -39,7 +39,7 @@
   return Object.assign(to, _from);
 }
 
-export function toObject<T>(arr: Array<T>): Record<string, T> {
+export function toObject<T>(arr: Array<T>): Recordable<T> {
   const res = {};
   for (let i = 0; i < arr.length; i++) {
     if (arr[i]) {
diff --git a/src/components/Table/src/BasicTable.vue b/src/components/Table/src/BasicTable.vue
index 5554848..1b9960f 100644
--- a/src/components/Table/src/BasicTable.vue
+++ b/src/components/Table/src/BasicTable.vue
@@ -221,7 +221,7 @@
       function handleTableChange(
         pagination: PaginationProps,
         // @ts-ignore
-        filters: Partial<Record<string, string[]>>,
+        filters: Partial<Recordable<string[]>>,
         sorter: SorterResult
       ) {
         const { clearSelectOnPageChange, sortFn } = unref(getMergeProps);
diff --git a/src/components/Table/src/components/renderEditable.tsx b/src/components/Table/src/components/renderEditable.tsx
index 5e2b95b..a576152 100644
--- a/src/components/Table/src/components/renderEditable.tsx
+++ b/src/components/Table/src/components/renderEditable.tsx
@@ -232,7 +232,7 @@
   };
 }
 
-export type EditRecordRow<T = { [key: string]: any }> = {
+export type EditRecordRow<T = Hash<any>> = {
   editable: boolean;
   onCancel: Fn;
   onSubmit: Fn;
diff --git a/src/components/Table/src/types/column.ts b/src/components/Table/src/types/column.ts
index 4df61bb..785e6df 100644
--- a/src/components/Table/src/types/column.ts
+++ b/src/components/Table/src/types/column.ts
@@ -194,5 +194,5 @@
    * such as slots: { filterIcon: 'XXX'}
    * @type object
    */
-  slots?: Record<string, string>;
+  slots?: Recordable<string>;
 }
diff --git a/src/components/Transition/src/CreateTransition.tsx b/src/components/Transition/src/CreateTransition.tsx
index 24ab1c9..ba5ee13 100644
--- a/src/components/Transition/src/CreateTransition.tsx
+++ b/src/components/Transition/src/CreateTransition.tsx
@@ -40,7 +40,7 @@
 }
 export function createJavascriptTransition(
   name: string,
-  functions: Record<string, any>,
+  functions: Recordable,
   mode: Mode = 'in-out'
 ) {
   return defineComponent({
diff --git a/src/components/VirtualScroll/src/index.tsx b/src/components/VirtualScroll/src/index.tsx
index b447ff1..1e17ee6 100644
--- a/src/components/VirtualScroll/src/index.tsx
+++ b/src/components/VirtualScroll/src/index.tsx
@@ -54,7 +54,7 @@
 
     const getWrapStyleRef = computed(
       (): CSSProperties => {
-        const styles: Record<string, string> = {};
+        const styles: Recordable<string> = {};
         const height = convertToUnit(props.height);
         const minHeight = convertToUnit(props.minHeight);
         const minWidth = convertToUnit(props.minWidth);
diff --git a/src/components/util.tsx b/src/components/util.tsx
index c1d7a3c..2010d87 100644
--- a/src/components/util.tsx
+++ b/src/components/util.tsx
@@ -40,7 +40,7 @@
 } as const;
 
 function parseStyle(style: string) {
-  const styleMap: Dictionary<any> = {};
+  const styleMap: Recordable = {};
 
   for (const s of style.split(pattern.styleList)) {
     let [key, val] = s.split(pattern.styleProp);
@@ -161,8 +161,8 @@
 }
 
 export function mergeListeners(
-  target: { [key: string]: Function | Function[] } | undefined,
-  source: { [key: string]: Function | Function[] } | undefined
+  target: Indexable<Function | Function[]> | undefined,
+  source: Indexable<Function | Function[]> | undefined
 ) {
   if (!target) return source;
   if (!source) return target;
diff --git a/src/directives/ripple/index.ts b/src/directives/ripple/index.ts
index 8863b91..c8d614b 100644
--- a/src/directives/ripple/index.ts
+++ b/src/directives/ripple/index.ts
@@ -154,7 +154,7 @@
     setTimeout(() => {
       let clearPosition = true;
       for (let i = 0; i < el.childNodes.length; i++) {
-        if ((el.childNodes[i] as any).className === 'ripple-container') {
+        if ((el.childNodes[i] as Recordable).className === 'ripple-container') {
           clearPosition = false;
         }
       }
@@ -173,7 +173,7 @@
     clearRipple();
   }
 
-  (el as any).setBackground = (bgColor: string) => {
+  (el as Recordable).setBackground = (bgColor: string) => {
     if (!bgColor) {
       return;
     }
@@ -181,8 +181,8 @@
   };
 }
 
-function setProps(modifiers: { [key: string]: any }, props: Record<string, any>) {
-  modifiers.forEach((item: any) => {
+function setProps(modifiers: Hash<any>, props: Recordable) {
+  modifiers.forEach((item: Recordable) => {
     if (isNaN(Number(item))) props.event = item;
     else props.transition = item;
   });
diff --git a/src/hooks/component/useFormItem.ts b/src/hooks/component/useFormItem.ts
new file mode 100644
index 0000000..8fa3cb3
--- /dev/null
+++ b/src/hooks/component/useFormItem.ts
@@ -0,0 +1,35 @@
+import type { UnwrapRef } from 'vue';
+import { reactive, readonly, computed, getCurrentInstance } from 'vue';
+
+import { isEqual } from 'lodash-es';
+
+export function useRuleFormItem<T extends Indexable>(
+  props: T,
+  key: keyof T = 'value',
+  changeEvent = 'change'
+) {
+  const instance = getCurrentInstance();
+  const emit = instance?.emit;
+
+  const innerState = reactive({
+    value: props[key],
+  });
+
+  const defaultState = readonly(innerState);
+
+  const setState = (val: UnwrapRef<T[keyof T]>) => {
+    innerState.value = val as T[keyof T];
+  };
+  const state = computed({
+    get() {
+      return innerState.value;
+    },
+    set(value) {
+      if (isEqual(value, defaultState.value)) return;
+      innerState.value = value as T[keyof T];
+      emit?.(changeEvent, value);
+    },
+  });
+
+  return [state, setState, defaultState];
+}
diff --git a/src/hooks/core/useAttrs.ts b/src/hooks/core/useAttrs.ts
new file mode 100644
index 0000000..94665ab
--- /dev/null
+++ b/src/hooks/core/useAttrs.ts
@@ -0,0 +1,39 @@
+import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue';
+
+interface Params {
+  excludeListeners?: boolean;
+  excludeKeys?: string[];
+}
+
+const DEFAULT_EXCLUDE_KEYS = ['class', 'style'];
+const LISTENER_PREFIX = /^on[A-Z]/;
+
+export function entries<T>(obj: Hash<T>): [string, T][] {
+  return Object.keys(obj).map((key: string) => [key, obj[key]]);
+}
+
+export function useAttrs(params: Params = {}) {
+  const instance = getCurrentInstance();
+  if (!instance) return {};
+
+  const { excludeListeners = false, excludeKeys = [] } = params;
+  const attrs = shallowRef({});
+  const allExcludeKeys = excludeKeys.concat(DEFAULT_EXCLUDE_KEYS);
+
+  // Since attrs are not reactive, make it reactive instead of doing in `onUpdated` hook for better performance
+  instance.attrs = reactive(instance.attrs);
+
+  watchEffect(() => {
+    const res = entries(instance.attrs).reduce((acm, [key, val]) => {
+      if (!allExcludeKeys.includes(key) && !(excludeListeners && LISTENER_PREFIX.test(key))) {
+        acm[key] = val;
+      }
+
+      return acm;
+    }, {} as Hash<any>);
+
+    attrs.value = res;
+  });
+
+  return attrs;
+}
diff --git a/src/hooks/event/useKeyPress.ts b/src/hooks/event/useKeyPress.ts
index 72338d6..2cabbbe 100644
--- a/src/hooks/event/useKeyPress.ts
+++ b/src/hooks/event/useKeyPress.ts
@@ -23,7 +23,7 @@
 const defaultEvents: keyEvent[] = ['keydown'];
 
 // 閿洏浜嬩欢 keyCode 鍒悕
-const aliasKeyCodeMap: Record<string, number | number[]> = {
+const aliasKeyCodeMap: Recordable<number | number[]> = {
   esc: 27,
   tab: 9,
   enter: 13,
@@ -36,7 +36,7 @@
 };
 
 // 閿洏浜嬩欢 key 鍒悕
-const aliasKeyMap: Record<string, string | string[]> = {
+const aliasKeyMap: Recordable<string | string[]> = {
   esc: 'Escape',
   tab: 'Tab',
   enter: 'Enter',
@@ -50,7 +50,7 @@
 };
 
 // 淇グ閿�
-const modifierKey: Record<string, (event: KeyboardEvent) => boolean> = {
+const modifierKey: Recordable<(event: KeyboardEvent) => boolean> = {
   ctrl: (event: KeyboardEvent) => event.ctrlKey,
   shift: (event: KeyboardEvent) => event.shiftKey,
   alt: (event: KeyboardEvent) => event.altKey,
diff --git a/src/hooks/web/useI18n.ts b/src/hooks/web/useI18n.ts
index feccc2d..2b143dd 100644
--- a/src/hooks/web/useI18n.ts
+++ b/src/hooks/web/useI18n.ts
@@ -24,7 +24,7 @@
 
   return {
     ...methods,
-    t: (key: string, ...arg: any) => {
+    t: (key: string, ...arg: any): string => {
       if (!key) return '';
       return t(getKey(key), ...(arg as Parameters<typeof t>));
     },
diff --git a/src/layouts/page/index.tsx b/src/layouts/page/index.tsx
index a09bda3..d223e08 100644
--- a/src/layouts/page/index.tsx
+++ b/src/layouts/page/index.tsx
@@ -13,7 +13,7 @@
 // import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
 interface DefaultContext {
-  Component: FunctionalComponent & { type: { [key: string]: any } };
+  Component: FunctionalComponent & { type: Indexable };
   route: RouteLocation;
 }
 
diff --git a/src/router/guard/permissionGuard.ts b/src/router/guard/permissionGuard.ts
index 624c160..a8f3d4f 100644
--- a/src/router/guard/permissionGuard.ts
+++ b/src/router/guard/permissionGuard.ts
@@ -40,7 +40,7 @@
         return;
       }
       // redirect login page
-      const redirectData: { path: string; replace: boolean; query?: { [key: string]: string } } = {
+      const redirectData: { path: string; replace: boolean; query?: Indexable<string> } = {
         path: LOGIN_PATH,
         replace: true,
       };
diff --git a/src/router/types.ts b/src/router/types.ts
index 2f96e96..2bb5802 100644
--- a/src/router/types.ts
+++ b/src/router/types.ts
@@ -48,7 +48,7 @@
   component?: Component | string;
   components?: Component;
   children?: AppRouteRecordRaw[];
-  props?: Record<string, any>;
+  props?: Recordable;
   fullPath?: string;
 }
 export interface MenuTag {
diff --git a/src/settings/colorSetting.ts b/src/settings/colorSetting.ts
index be15876..0b498a3 100644
--- a/src/settings/colorSetting.ts
+++ b/src/settings/colorSetting.ts
@@ -2,7 +2,7 @@
 export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
   '#ffffff',
   '#009688',
-  '#18bc9c',
+  '#5172DC',
   '#1E9FFF',
   '#018ffb',
   '#409eff',
diff --git a/src/types/global.d.ts b/src/types/global.d.ts
index 0874781..c4ab5ae 100644
--- a/src/types/global.d.ts
+++ b/src/types/global.d.ts
@@ -15,17 +15,19 @@
 
 declare function parseFloat(string: string | number): number;
 
-declare type Dictionary<T> = Record<string, T>;
-
 declare type Nullable<T> = T | null;
+
+declare type NonNullable<T> = T extends null | undefined ? never : T;
 
 declare type RefType<T> = T | null;
 
 declare type CustomizedHTMLElement<T> = HTMLElement & T;
 
-declare type Indexable<T = any> = {
+declare type Indexable<T extends any = any> = {
   [key: string]: T;
 };
+
+declare type Recordable<T extends any = any> = Record<string, T>;
 
 declare type Hash<T> = Indexable<T>;
 
@@ -59,3 +61,5 @@
 declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null;
 
 declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;
+
+type IsSame<A, B> = A | B extends A & B ? true : false;
diff --git a/src/utils/helper/persistent.ts b/src/utils/helper/persistent.ts
index 46f99c8..bb99089 100644
--- a/src/utils/helper/persistent.ts
+++ b/src/utils/helper/persistent.ts
@@ -7,8 +7,8 @@
 const ss = createStorage();
 
 interface CacheStore {
-  local: Record<string, any>;
-  session: Record<string, any>;
+  local: Recordable;
+  session: Recordable;
 }
 
 /**
diff --git a/src/utils/helper/tsxHelper.tsx b/src/utils/helper/tsxHelper.tsx
index e4aaa00..bd41cb7 100644
--- a/src/utils/helper/tsxHelper.tsx
+++ b/src/utils/helper/tsxHelper.tsx
@@ -35,7 +35,7 @@
 }
 
 // Get events on attrs
-export function getListeners(attrs: Record<string, unknown>) {
+export function getListeners(attrs: Recordable<unknown>) {
   const listeners: any = {};
   Object.keys(attrs).forEach((key) => {
     if (/^on/.test(key)) {
diff --git a/src/utils/helper/vueHelper.ts b/src/utils/helper/vueHelper.ts
index cd04bea..8cead80 100644
--- a/src/utils/helper/vueHelper.ts
+++ b/src/utils/helper/vueHelper.ts
@@ -9,6 +9,7 @@
   reactive,
   ComponentInternalInstance,
 } from 'vue';
+import { error } from '../log';
 
 export function explicitComputed<T, S>(source: WatchSource<S>, fn: () => T) {
   const v = reactive<any>({ value: fn() });
@@ -39,6 +40,6 @@
 
 export function isInSetup() {
   if (!getCurrentInstance()) {
-    throw new Error('Please put useForm function in the setup function!');
+    error('Please put useForm function in the setup function!');
   }
 }
diff --git a/src/utils/http/axios/types.ts b/src/utils/http/axios/types.ts
index 90b1619..b151ed5 100644
--- a/src/utils/http/axios/types.ts
+++ b/src/utils/http/axios/types.ts
@@ -35,7 +35,7 @@
 // multipart/form-data锛氫笂浼犳枃浠�
 export interface UploadFileParams {
   // 鍏朵粬鍙傛暟
-  data?: { [key: string]: any };
+  data?: Indexable;
   // 鏂囦欢鍙傛暟鐨勬帴鍙e瓧娈靛悕
   name?: string;
   // 鏂囦欢
diff --git a/src/utils/index.ts b/src/utils/index.ts
index d37797e..b24685f 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -38,7 +38,7 @@
   return url;
 }
 
-export function deepMerge<T = any>(src: any, target: any): T {
+export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
   let key: string;
   for (key in target) {
     src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 81cded0..8f79800 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -3,3 +3,7 @@
 export function warn(message: string) {
   console.warn(`[${projectName} warn]:${message}`);
 }
+
+export function error(message: string) {
+  throw new Error(`[${projectName} error]:${message}`);
+}
diff --git a/src/views/demo/form/RuleForm.vue b/src/views/demo/form/RuleForm.vue
index 4851c66..6023777 100644
--- a/src/views/demo/form/RuleForm.vue
+++ b/src/views/demo/form/RuleForm.vue
@@ -84,12 +84,15 @@
           required: true,
           // @ts-ignore
           validator: async (rule, value) => {
+            if (!value) {
+              return Promise.reject('鍊间笉鑳戒负绌�');
+            }
             if (value === '1') {
               return Promise.reject('鍊间笉鑳戒负1');
             }
             return Promise.resolve();
           },
-          trigger: 'blur',
+          trigger: 'change',
         },
       ],
     },
diff --git a/yarn.lock b/yarn.lock
index ceb4b38..84693b5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -35,7 +35,7 @@
     "@types/lodash" "^4.14.165"
     lodash "^4.17.15"
 
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3":
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
   version "7.10.4"
   resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
   integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
@@ -47,7 +47,7 @@
   resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41"
   integrity sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==
 
-"@babel/core@>=7.9.0", "@babel/core@^7.8.4":
+"@babel/core@>=7.9.0", "@babel/core@^7.11.1":
   version "7.12.10"
   resolved "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd"
   integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==
@@ -167,7 +167,7 @@
   dependencies:
     "@babel/types" "^7.12.7"
 
-"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.5":
+"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.5":
   version "7.12.5"
   resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb"
   integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==
@@ -246,10 +246,20 @@
   resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
   integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
 
+"@babel/helper-validator-identifier@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
+  integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
+
 "@babel/helper-validator-option@^7.12.1":
   version "7.12.1"
   resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9"
   integrity sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==
+
+"@babel/helper-validator-option@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
+  integrity sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==
 
 "@babel/helper-wrap-function@^7.10.4":
   version "7.12.3"
@@ -498,10 +508,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.10.4"
 
-"@babel/plugin-transform-block-scoping@^7.12.1":
-  version "7.12.1"
-  resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz#f0ee727874b42a208a48a586b84c3d222c2bbef1"
-  integrity sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==
+"@babel/plugin-transform-block-scoping@^7.12.11":
+  version "7.12.12"
+  resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz#d93a567a152c22aea3b1929bb118d1d0a175cdca"
+  integrity sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==
   dependencies:
     "@babel/helper-plugin-utils" "^7.10.4"
 
@@ -724,16 +734,16 @@
     "@babel/helper-create-regexp-features-plugin" "^7.12.1"
     "@babel/helper-plugin-utils" "^7.10.4"
 
-"@babel/preset-env@^7.8.4":
-  version "7.12.10"
-  resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.10.tgz#ca981b95f641f2610531bd71948656306905e6ab"
-  integrity sha512-Gz9hnBT/tGeTE2DBNDkD7BiWRELZt+8lSysHuDwmYXUIvtwZl0zI+D6mZgXZX0u8YBlLS4tmai9ONNY9tjRgRA==
+"@babel/preset-env@^7.11.0":
+  version "7.12.11"
+  resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9"
+  integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==
   dependencies:
     "@babel/compat-data" "^7.12.7"
     "@babel/helper-compilation-targets" "^7.12.5"
     "@babel/helper-module-imports" "^7.12.5"
     "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-validator-option" "^7.12.1"
+    "@babel/helper-validator-option" "^7.12.11"
     "@babel/plugin-proposal-async-generator-functions" "^7.12.1"
     "@babel/plugin-proposal-class-properties" "^7.12.1"
     "@babel/plugin-proposal-dynamic-import" "^7.12.1"
@@ -762,7 +772,7 @@
     "@babel/plugin-transform-arrow-functions" "^7.12.1"
     "@babel/plugin-transform-async-to-generator" "^7.12.1"
     "@babel/plugin-transform-block-scoped-functions" "^7.12.1"
-    "@babel/plugin-transform-block-scoping" "^7.12.1"
+    "@babel/plugin-transform-block-scoping" "^7.12.11"
     "@babel/plugin-transform-classes" "^7.12.1"
     "@babel/plugin-transform-computed-properties" "^7.12.1"
     "@babel/plugin-transform-destructuring" "^7.12.1"
@@ -792,7 +802,7 @@
     "@babel/plugin-transform-unicode-escapes" "^7.12.1"
     "@babel/plugin-transform-unicode-regex" "^7.12.1"
     "@babel/preset-modules" "^0.1.3"
-    "@babel/types" "^7.12.10"
+    "@babel/types" "^7.12.11"
     core-js-compat "^3.8.0"
     semver "^5.5.0"
 
@@ -844,6 +854,15 @@
   integrity sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==
   dependencies:
     "@babel/helper-validator-identifier" "^7.10.4"
+    lodash "^4.17.19"
+    to-fast-properties "^2.0.0"
+
+"@babel/types@^7.12.11":
+  version "7.12.12"
+  resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299"
+  integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.12.11"
     lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
@@ -1004,32 +1023,38 @@
     minimatch "^3.0.4"
     strip-json-comments "^3.1.1"
 
-"@hapi/address@2.x.x":
+"@hapi/address@^2.1.2":
   version "2.1.4"
   resolved "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
   integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==
 
-"@hapi/bourne@1.x.x":
-  version "1.3.2"
-  resolved "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a"
-  integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==
+"@hapi/formula@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.npmjs.org/@hapi/formula/-/formula-1.2.0.tgz#994649c7fea1a90b91a0a1e6d983523f680e10cd"
+  integrity sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA==
 
-"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0":
+"@hapi/hoek@^8.2.4", "@hapi/hoek@^8.3.0":
   version "8.5.1"
   resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06"
   integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==
 
-"@hapi/joi@^15.1.0":
-  version "15.1.1"
-  resolved "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
-  integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==
+"@hapi/joi@^16.1.8":
+  version "16.1.8"
+  resolved "https://registry.npmjs.org/@hapi/joi/-/joi-16.1.8.tgz#84c1f126269489871ad4e2decc786e0adef06839"
+  integrity sha512-wAsVvTPe+FwSrsAurNt5vkg3zo+TblvC5Bb1zMVK6SJzZqw9UrJnexxR+76cpePmtUZKHAPxcQ2Bf7oVHyahhg==
   dependencies:
-    "@hapi/address" "2.x.x"
-    "@hapi/bourne" "1.x.x"
-    "@hapi/hoek" "8.x.x"
-    "@hapi/topo" "3.x.x"
+    "@hapi/address" "^2.1.2"
+    "@hapi/formula" "^1.2.0"
+    "@hapi/hoek" "^8.2.4"
+    "@hapi/pinpoint" "^1.0.2"
+    "@hapi/topo" "^3.1.3"
 
-"@hapi/topo@3.x.x":
+"@hapi/pinpoint@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-1.0.2.tgz#025b7a36dbbf4d35bf1acd071c26b20ef41e0d13"
+  integrity sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ==
+
+"@hapi/topo@^3.1.3":
   version "3.1.6"
   resolved "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29"
   integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==
@@ -1051,10 +1076,10 @@
   resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.4.tgz#46098fb544a4eb3af724219e4955c9022801835e"
   integrity sha512-YCSECbeXKFJEIVkKgKMjUzJ439ysufmL/a31B1j7dCvnHaBWsX9J4XehhJgg/aTy3yvhHaVhI6xt1kSMZP799A==
 
-"@iconify/json@^1.1.275":
-  version "1.1.275"
-  resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.275.tgz#ac9a706cdc7c9e64ab8e8bb09ae770f551f7496f"
-  integrity sha512-Nt6tXJpZFd/gFRV24BvmlIdxnbMxgshIKFPQwOWgeVjKiOKEwiBKjXUzBE74As7/Olps/ac1gEB40N9/DGOJ3Q==
+"@iconify/json@^1.1.276":
+  version "1.1.276"
+  resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.276.tgz#c8d51751abc84cc73a466f55bc2f352686451786"
+  integrity sha512-Ra/mGT+n38vhi/i1cjsPYOmSR2d6rNIXZ+OsrIWp9J35zAPQ93sSTQMpTyxZdLu3QxU0vYwtcaC7h/Y1/3H3wg==
 
 "@intlify/core-base@9.0.0-beta.14":
   version "9.0.0-beta.14"
@@ -1170,6 +1195,14 @@
   dependencies:
     "@iconify/iconify" ">=2.0.0-rc.1"
 
+"@rollup/plugin-babel@^5.2.0":
+  version "5.2.2"
+  resolved "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz#e5623a01dd8e37e004ba87f2de218c611727d9b2"
+  integrity sha512-MjmH7GvFT4TW8xFdIeFS3wqIX646y5tACdxkTO+khbHvS3ZcVJL6vkAHLw2wqPmkhwCfWHoNsp15VYNwW6JEJA==
+  dependencies:
+    "@babel/helper-module-imports" "^7.10.4"
+    "@rollup/pluginutils" "^3.1.0"
+
 "@rollup/plugin-commonjs@^16.0.0":
   version "16.0.0"
   resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f"
@@ -1214,31 +1247,31 @@
     is-module "^1.0.0"
     resolve "^1.19.0"
 
-"@rollup/plugin-node-resolve@^7.1.1":
-  version "7.1.3"
-  resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca"
-  integrity sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==
-  dependencies:
-    "@rollup/pluginutils" "^3.0.8"
-    "@types/resolve" "0.0.8"
-    builtin-modules "^3.1.0"
-    is-module "^1.0.0"
-    resolve "^1.14.2"
-
-"@rollup/plugin-node-resolve@^8.4.0":
-  version "8.4.0"
-  resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz#261d79a680e9dc3d86761c14462f24126ba83575"
-  integrity sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==
+"@rollup/plugin-node-resolve@^11.0.1":
+  version "11.0.1"
+  resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.0.1.tgz#d3765eec4bccf960801439a999382aed2dca959b"
+  integrity sha512-ltlsj/4Bhwwhb+Nb5xCz/6vieuEj2/BAkkqVIKmZwC7pIdl8srmgmglE4S0jFlZa32K4qvdQ6NHdmpRKD/LwoQ==
   dependencies:
     "@rollup/pluginutils" "^3.1.0"
     "@types/resolve" "1.17.1"
     builtin-modules "^3.1.0"
-    deep-freeze "^0.0.1"
+    deepmerge "^4.2.2"
+    is-module "^1.0.0"
+    resolve "^1.19.0"
+
+"@rollup/plugin-node-resolve@^9.0.0":
+  version "9.0.0"
+  resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz#39bd0034ce9126b39c1699695f440b4b7d2b62e6"
+  integrity sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==
+  dependencies:
+    "@rollup/pluginutils" "^3.1.0"
+    "@types/resolve" "1.17.1"
+    builtin-modules "^3.1.0"
     deepmerge "^4.2.2"
     is-module "^1.0.0"
     resolve "^1.17.0"
 
-"@rollup/plugin-replace@^2.3.1", "@rollup/plugin-replace@^2.3.3":
+"@rollup/plugin-replace@^2.3.3", "@rollup/plugin-replace@^2.3.4":
   version "2.3.4"
   resolved "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.4.tgz#7dd84c17755d62b509577f2db37eb524d7ca88ca"
   integrity sha512-waBhMzyAtjCL1GwZes2jaE9MjuQ/DQF2BatH3fRivUF3z0JBFrU0U6iBNC/4WR+2rLKhaAhPWDNPYp4mI6RqdQ==
@@ -1286,7 +1319,7 @@
     remark "^13.0.0"
     unist-util-find-all-after "^3.0.2"
 
-"@surma/rollup-plugin-off-main-thread@^1.1.1":
+"@surma/rollup-plugin-off-main-thread@^1.4.1":
   version "1.4.2"
   resolved "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz#e6786b6af5799f82f7ab3a82e53f6182d2b91a58"
   integrity sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A==
@@ -1367,10 +1400,10 @@
     "@types/qs" "*"
     "@types/serve-static" "*"
 
-"@types/fs-extra@^9.0.5":
-  version "9.0.5"
-  resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.5.tgz#2afb76a43a4bef80a363b94b314d0ca1694fc4f8"
-  integrity sha512-wr3t7wIW1c0A2BIJtdVp4EflriVaVVAsCAIHVzzh8B+GiFv9X1xeJjCs4upRXtzp7kQ6lP5xvskjoD4awJ1ZeA==
+"@types/fs-extra@^9.0.6":
+  version "9.0.6"
+  resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.6.tgz#488e56b77299899a608b8269719c1d133027a6ab"
+  integrity sha512-ecNRHw4clCkowNOBJH1e77nvbPxHYnWIXMv1IAoG/9+MYGkgoyr3Ppxr7XYFNL41V422EDhyV4/4SSK8L2mlig==
   dependencies:
     "@types/node" "*"
 
@@ -1517,13 +1550,6 @@
   version "1.2.3"
   resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
   integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
-
-"@types/resolve@0.0.8":
-  version "0.0.8"
-  resolved "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
-  integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
-  dependencies:
-    "@types/node" "*"
 
 "@types/resolve@1.17.1":
   version "1.17.1"
@@ -1841,7 +1867,7 @@
   resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
   integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
 
-acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0:
+acorn@^7.1.1, acorn@^7.4.0:
   version "7.4.1"
   resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
   integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
@@ -2105,13 +2131,6 @@
   dependencies:
     follow-redirects "^1.10.0"
 
-babel-extract-comments@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21"
-  integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==
-  dependencies:
-    babylon "^6.18.0"
-
 babel-helper-vue-jsx-merge-props@^2.0.3:
   version "2.0.3"
   resolved "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
@@ -2123,32 +2142,6 @@
   integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
   dependencies:
     object.assign "^4.1.0"
-
-babel-plugin-syntax-object-rest-spread@^6.8.0:
-  version "6.13.0"
-  resolved "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
-  integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=
-
-babel-plugin-transform-object-rest-spread@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
-  integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=
-  dependencies:
-    babel-plugin-syntax-object-rest-spread "^6.8.0"
-    babel-runtime "^6.26.0"
-
-babel-runtime@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
-  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
-  dependencies:
-    core-js "^2.4.0"
-    regenerator-runtime "^0.11.0"
-
-babylon@^6.18.0:
-  version "6.18.0"
-  resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
-  integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
 
 bail@^1.0.0:
   version "1.0.5"
@@ -2950,11 +2943,6 @@
     browserslist "^4.15.0"
     semver "7.0.0"
 
-core-js@^2.4.0:
-  version "2.6.12"
-  resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
-  integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
-
 core-js@^3.6.1, core-js@^3.6.5:
   version "3.8.1"
   resolved "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz#f51523668ac8a294d1285c3b9db44025fda66d47"
@@ -3010,10 +2998,10 @@
   resolved "https://registry.npmjs.org/crypto-es/-/crypto-es-1.2.6.tgz#468f3573a5d7b82e3b63b0004f55f905a6d3b12c"
   integrity sha512-PQnrovdr5ibmOxqAh/Vy+A30RokHom7kb9Z61EPwfASfbcJCrCG4+vNNegmebNVHiXvS7WjYpHDePxnE/biEbA==
 
-crypto-random-string@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
-  integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+crypto-random-string@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
+  integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
 
 cssesc@^3.0.0:
   version "3.0.0"
@@ -3094,6 +3082,13 @@
   dependencies:
     ms "2.1.2"
 
+debug@^4.3.2:
+  version "4.3.2"
+  resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
+  integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
+  dependencies:
+    ms "2.1.2"
+
 debug@~3.1.0:
   version "3.1.0"
   resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -3128,11 +3123,6 @@
   version "1.0.1"
   resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
   integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
-
-deep-freeze@^0.0.1:
-  version "0.0.1"
-  resolved "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84"
-  integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=
 
 deep-is@^0.1.3:
   version "0.1.3"
@@ -3912,7 +3902,7 @@
   resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
   integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
 
-fs-extra@8.1.0, fs-extra@^8.1.0:
+fs-extra@8.1.0:
   version "8.1.0"
   resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
   integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
@@ -4863,15 +4853,7 @@
   resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
   integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
 
-jest-worker@^24.9.0:
-  version "24.9.0"
-  resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5"
-  integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==
-  dependencies:
-    merge-stream "^2.0.0"
-    supports-color "^6.1.0"
-
-jest-worker@^26.0.0, jest-worker@^26.2.1:
+jest-worker@^26.2.1:
   version "26.6.2"
   resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
   integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
@@ -5265,7 +5247,7 @@
   resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
   integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
 
-lodash.template@^4.0.2, lodash.template@^4.5.0:
+lodash.template@^4.0.2:
   version "4.5.0"
   resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
   integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
@@ -6440,6 +6422,11 @@
   resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz#cd89f79bbcef21e3d21eb0da68ffe93f803e884b"
   integrity sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==
 
+pretty-bytes@^5.4.1:
+  version "5.5.0"
+  resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz#0cecda50a74a941589498011cf23275aa82b339e"
+  integrity sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==
+
 printj@~1.1.0, printj@~1.1.2:
   version "1.1.2"
   resolved "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
@@ -6667,11 +6654,6 @@
   resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
   integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
 
-regenerator-runtime@^0.11.0:
-  version "0.11.1"
-  resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
-  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-
 regenerator-runtime@^0.13.4:
   version "0.13.7"
   resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
@@ -6824,7 +6806,7 @@
   resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
-resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0:
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.17.0, resolve@^1.19.0:
   version "1.19.0"
   resolved "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
   integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
@@ -6865,14 +6847,6 @@
   dependencies:
     glob "^7.1.3"
 
-rollup-plugin-babel@^4.3.3:
-  version "4.4.0"
-  resolved "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz#d15bd259466a9d1accbdb2fe2fff17c52d030acb"
-  integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==
-  dependencies:
-    "@babel/helper-module-imports" "^7.0.0"
-    rollup-pluginutils "^2.8.1"
-
 rollup-plugin-dynamic-import-variables@^1.1.0:
   version "1.1.0"
   resolved "https://registry.npmjs.org/rollup-plugin-dynamic-import-variables/-/rollup-plugin-dynamic-import-variables-1.1.0.tgz#4981d38907a471b35234398a09047bef47a2006a"
@@ -6900,28 +6874,7 @@
     "@purge-icons/core" "^0.4.5"
     "@purge-icons/generated" "^0.4.1"
 
-rollup-plugin-terser@^5.3.1:
-  version "5.3.1"
-  resolved "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz#8c650062c22a8426c64268548957463bf981b413"
-  integrity sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w==
-  dependencies:
-    "@babel/code-frame" "^7.5.5"
-    jest-worker "^24.9.0"
-    rollup-pluginutils "^2.8.2"
-    serialize-javascript "^4.0.0"
-    terser "^4.6.2"
-
-rollup-plugin-terser@^6.1.0:
-  version "6.1.0"
-  resolved "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz#071866585aea104bfbb9dd1019ac523e63c81e45"
-  integrity sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw==
-  dependencies:
-    "@babel/code-frame" "^7.8.3"
-    jest-worker "^26.0.0"
-    serialize-javascript "^3.0.0"
-    terser "^4.7.0"
-
-rollup-plugin-terser@^7.0.2:
+rollup-plugin-terser@^7.0.0, rollup-plugin-terser@^7.0.2:
   version "7.0.2"
   resolved "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
   integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
@@ -6955,18 +6908,18 @@
   resolved "https://registry.npmjs.org/rollup-plugin-web-worker-loader/-/rollup-plugin-web-worker-loader-1.5.0.tgz#df21973426c6f95b238a84698ae27f8d8aab6b83"
   integrity sha512-Zx5l370yGDje35rFkM/wbT4dMIq2+kSBdLWQpqLkBuxmrQJcx0umA05kSbNRzccFsudQH4FKYCK8GtSBQRQBBg==
 
-rollup-plugin-workbox@^5.2.1:
-  version "5.2.1"
-  resolved "https://registry.npmjs.org/rollup-plugin-workbox/-/rollup-plugin-workbox-5.2.1.tgz#371b0753667df03886742ec072281525803c2c75"
-  integrity sha512-C+yIoYkZ3VUcJTZpOH2zbaarHCwy8eQod987eS8hXE6qwfMLDqV3RkLYNplnO0PcMi+3JgZPiE6d1zuXgwkO7Q==
+rollup-plugin-workbox@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.npmjs.org/rollup-plugin-workbox/-/rollup-plugin-workbox-6.1.0.tgz#120cde36547769fc8cc45eae97a338c4017ed936"
+  integrity sha512-BqeEBj53fiqNLjiiyVvuBlic3Apg2Us1mpTkn3zgqaipJoAOC3soi+W9vrOQcm190lHLo9WNvi1wQg/M7olJHg==
   dependencies:
-    "@rollup/plugin-node-resolve" "^8.4.0"
-    "@rollup/plugin-replace" "^2.3.3"
-    pretty-bytes "^5.3.0"
-    rollup-plugin-terser "^6.1.0"
-    workbox-build "^5.0.0"
+    "@rollup/plugin-node-resolve" "^11.0.1"
+    "@rollup/plugin-replace" "^2.3.4"
+    pretty-bytes "^5.4.1"
+    rollup-plugin-terser "^7.0.2"
+    workbox-build "^6.0.2"
 
-rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
+rollup-pluginutils@^2.8.2:
   version "2.8.2"
   resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
   integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
@@ -6981,14 +6934,12 @@
     "@types/estree" "0.0.39"
     "@types/node" "*"
 
-rollup@^1.31.1:
-  version "1.32.1"
-  resolved "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4"
-  integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==
-  dependencies:
-    "@types/estree" "*"
-    "@types/node" "*"
-    acorn "^7.1.0"
+rollup@^2.25.0:
+  version "2.35.1"
+  resolved "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c"
+  integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==
+  optionalDependencies:
+    fsevents "~2.1.2"
 
 rollup@^2.32.1, rollup@^2.34.1:
   version "2.34.2"
@@ -7086,13 +7037,6 @@
   integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
   dependencies:
     lru-cache "^6.0.0"
-
-serialize-javascript@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea"
-  integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==
-  dependencies:
-    randombytes "^2.1.0"
 
 serialize-javascript@^4.0.0:
   version "4.0.0"
@@ -7448,13 +7392,10 @@
   resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
   integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
 
-strip-comments@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d"
-  integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==
-  dependencies:
-    babel-extract-comments "^1.0.0"
-    babel-plugin-transform-object-rest-spread "^6.26.0"
+strip-comments@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b"
+  integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==
 
 strip-final-newline@^2.0.0:
   version "2.0.0"
@@ -7689,11 +7630,6 @@
     "@pawelgalazka/shell" "2.0.0"
     chalk "2.3.0"
 
-temp-dir@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
-  integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=
-
 temp-dir@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
@@ -7707,16 +7643,17 @@
     temp-dir "^2.0.0"
     uuid "^3.3.2"
 
-tempy@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz#6f6c5b295695a16130996ad5ab01a8bd726e8bf8"
-  integrity sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==
+tempy@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz#65e2c35abc06f1124a97f387b08303442bde59f3"
+  integrity sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==
   dependencies:
-    temp-dir "^1.0.0"
-    type-fest "^0.3.1"
-    unique-string "^1.0.0"
+    is-stream "^2.0.0"
+    temp-dir "^2.0.0"
+    type-fest "^0.16.0"
+    unique-string "^2.0.0"
 
-terser@^4.6.2, terser@^4.6.3, terser@^4.7.0:
+terser@^4.6.3:
   version "4.8.0"
   resolved "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
   integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
@@ -7898,15 +7835,15 @@
   resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
   integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
 
+type-fest@^0.16.0:
+  version "0.16.0"
+  resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860"
+  integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
+
 type-fest@^0.18.0:
   version "0.18.1"
   resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
   integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
-
-type-fest@^0.3.1:
-  version "0.3.1"
-  resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
-  integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
 
 type-fest@^0.6.0:
   version "0.6.0"
@@ -7998,12 +7935,12 @@
   resolved "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
   integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
 
-unique-string@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
-  integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
+unique-string@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
+  integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
   dependencies:
-    crypto-random-string "^1.0.0"
+    crypto-random-string "^2.0.0"
 
 unist-util-find-all-after@^3.0.2:
   version "3.0.2"
@@ -8159,14 +8096,14 @@
     "@purge-icons/generated" "^0.4.1"
     rollup-plugin-purge-icons "^0.4.5"
 
-vite-plugin-pwa@^0.1.7:
-  version "0.1.7"
-  resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.1.7.tgz#3e13faf2d61b1f5a1b341f6b08f32216ffae1f55"
-  integrity sha512-S5Hc1x/rcfb6cgKjlW7yxSTv1er6fquzGZt/+xC1wavSBa7Qf6wdf6QzYiYdwmUom5yUSDEawc2gEYgq5SsZFg==
+vite-plugin-pwa@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.2.0.tgz#e9368530c97537bdad7279f05de061ab9b024cce"
+  integrity sha512-OBNhlSqvqH9af9i8HsetmaRTrUjit3UP0rx33Sr0iBapM0gtuAmTjS4JPdSM54cGC1aVaIC3Rn3sY9wL0uxBrw==
   dependencies:
-    debug "^4.3.0"
+    debug "^4.3.2"
     fast-glob "^3.2.4"
-    rollup-plugin-workbox "^5.2.1"
+    rollup-plugin-workbox "^6.1.0"
 
 vite@^1.0.0-rc.13:
   version "1.0.0-rc.13"
@@ -8354,146 +8291,160 @@
   resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
   integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
 
-workbox-background-sync@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz#5ae0bbd455f4e9c319e8d827c055bb86c894fd12"
-  integrity sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA==
+workbox-background-sync@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.0.2.tgz#9205f5ef7fbf68203b925bdc85bdaa31a34fbbe6"
+  integrity sha512-KQU2ntvbvFoBvCRm+EDpWAaykt4u/oaF5j3C6io0dZVWhFc/ZwgYDii8fb34LTenug3VPWQELdw9dNBCoP4b0w==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-broadcast-update@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz#0eeb89170ddca7f6914fa3523fb14462891f2cfc"
-  integrity sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA==
+workbox-broadcast-update@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.0.2.tgz#fc034277e631e4193dcee9f6b0a77e415b4ddefb"
+  integrity sha512-yCXYEln7nU8FkMDysYQPirpgFXtsdBtxruHbvZzRsxMHvAELf3j/o6Ufae1zjl8XanLF696sqSNxehpCGSD6tw==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-build@^5.0.0:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-build/-/workbox-build-5.1.4.tgz#23d17ed5c32060c363030c8823b39d0eabf4c8c7"
-  integrity sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow==
+workbox-build@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-build/-/workbox-build-6.0.2.tgz#a23eebd6556cf473fedda77c08421b2d093efc32"
+  integrity sha512-Dukbt+p62Yzb12SXAmycTYvHngJ8aRtXy3hymsC8B6gxTCZmCZ0u5JuKhu7lNLbDwDkYE78lhFvT9SF+MXFz5A==
   dependencies:
-    "@babel/core" "^7.8.4"
-    "@babel/preset-env" "^7.8.4"
-    "@babel/runtime" "^7.8.4"
-    "@hapi/joi" "^15.1.0"
-    "@rollup/plugin-node-resolve" "^7.1.1"
-    "@rollup/plugin-replace" "^2.3.1"
-    "@surma/rollup-plugin-off-main-thread" "^1.1.1"
+    "@babel/core" "^7.11.1"
+    "@babel/preset-env" "^7.11.0"
+    "@babel/runtime" "^7.11.2"
+    "@hapi/joi" "^16.1.8"
+    "@rollup/plugin-babel" "^5.2.0"
+    "@rollup/plugin-node-resolve" "^9.0.0"
+    "@rollup/plugin-replace" "^2.3.3"
+    "@surma/rollup-plugin-off-main-thread" "^1.4.1"
     common-tags "^1.8.0"
     fast-json-stable-stringify "^2.1.0"
-    fs-extra "^8.1.0"
+    fs-extra "^9.0.1"
     glob "^7.1.6"
-    lodash.template "^4.5.0"
+    lodash "^4.17.20"
     pretty-bytes "^5.3.0"
-    rollup "^1.31.1"
-    rollup-plugin-babel "^4.3.3"
-    rollup-plugin-terser "^5.3.1"
+    rollup "^2.25.0"
+    rollup-plugin-terser "^7.0.0"
     source-map "^0.7.3"
     source-map-url "^0.4.0"
     stringify-object "^3.3.0"
-    strip-comments "^1.0.2"
-    tempy "^0.3.0"
+    strip-comments "^2.0.1"
+    tempy "^0.6.0"
     upath "^1.2.0"
-    workbox-background-sync "^5.1.4"
-    workbox-broadcast-update "^5.1.4"
-    workbox-cacheable-response "^5.1.4"
-    workbox-core "^5.1.4"
-    workbox-expiration "^5.1.4"
-    workbox-google-analytics "^5.1.4"
-    workbox-navigation-preload "^5.1.4"
-    workbox-precaching "^5.1.4"
-    workbox-range-requests "^5.1.4"
-    workbox-routing "^5.1.4"
-    workbox-strategies "^5.1.4"
-    workbox-streams "^5.1.4"
-    workbox-sw "^5.1.4"
-    workbox-window "^5.1.4"
+    workbox-background-sync "^6.0.2"
+    workbox-broadcast-update "^6.0.2"
+    workbox-cacheable-response "^6.0.2"
+    workbox-core "^6.0.2"
+    workbox-expiration "^6.0.2"
+    workbox-google-analytics "^6.0.2"
+    workbox-navigation-preload "^6.0.2"
+    workbox-precaching "^6.0.2"
+    workbox-range-requests "^6.0.2"
+    workbox-recipes "^6.0.2"
+    workbox-routing "^6.0.2"
+    workbox-strategies "^6.0.2"
+    workbox-streams "^6.0.2"
+    workbox-sw "^6.0.2"
+    workbox-window "^6.0.2"
 
-workbox-cacheable-response@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz#9ff26e1366214bdd05cf5a43da9305b274078a54"
-  integrity sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA==
+workbox-cacheable-response@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.0.2.tgz#00b1133c4c846a2874f32ae14206c0636bacfd87"
+  integrity sha512-OrgFiYWkmFXDIbNRYSu+fchcfoZqyJ4yZbdc8WKUjr9v/MghKHfR9u7UI077xBkjno5J3YNpbwx73/no3HkrzA==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-core@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.4.tgz#8bbfb2362ecdff30e25d123c82c79ac65d9264f4"
-  integrity sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg==
+workbox-core@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-core/-/workbox-core-6.0.2.tgz#2f865cfe633890b4210fd6d6fdb049a6daed0914"
+  integrity sha512-Ksl6qeikGb+BOCILoCUJGxwlEQOeeqdpOnpOr9UDt3NtacPYbfYBmpYpKArw5DFWK+5geBsFqgUUlXThlCYfKQ==
 
-workbox-expiration@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-5.1.4.tgz#92b5df461e8126114943a3b15c55e4ecb920b163"
-  integrity sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ==
+workbox-expiration@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.0.2.tgz#ac01e8d17f48daa31dc0872c09ee6f4d2cf28ccb"
+  integrity sha512-6+nbR18cklAdI3BPT675ytftXPwnVbXGR8mPWNWTJtl5y2urRYv56ZOJLD7FBFVkZ8EjWiRhNP/A0fkxgdKtWQ==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-google-analytics@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz#b3376806b1ac7d7df8418304d379707195fa8517"
-  integrity sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA==
+workbox-google-analytics@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.0.2.tgz#7e3641adb30a3acb25006b244035631cf6f65019"
+  integrity sha512-xmYJurR1M6Pzc2SBM/E7AgwmBszhu/YYDzBnU+HJPZFLbTG97ASIJyTXV1vcczA/dNaS0miIf0cFqneozVlDRw==
   dependencies:
-    workbox-background-sync "^5.1.4"
-    workbox-core "^5.1.4"
-    workbox-routing "^5.1.4"
-    workbox-strategies "^5.1.4"
+    workbox-background-sync "^6.0.2"
+    workbox-core "^6.0.2"
+    workbox-routing "^6.0.2"
+    workbox-strategies "^6.0.2"
 
-workbox-navigation-preload@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz#30d1b720d26a05efc5fa11503e5cc1ed5a78902a"
-  integrity sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ==
+workbox-navigation-preload@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.0.2.tgz#bfd9c61096be921b830153a3004b7212220748dc"
+  integrity sha512-7+ojLrjXmTFZBfGmUQIcBWB+xrFgXLMJGNQAtxT7Ta9A23rEWo8jqAgeuwAylebcORUlM+ztgYTV7eGp+AD+Yg==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-precaching@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-5.1.4.tgz#874f7ebdd750dd3e04249efae9a1b3f48285fe6b"
-  integrity sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA==
+workbox-precaching@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.0.2.tgz#cb45f290b0604bef1d9fc96bf42df82385d54e54"
+  integrity sha512-sqKWL2emzmGnfJpna+9RjUkUiqQO++AKfwljCbgkHg8wBbVLy/rnui3eelKgAI7D8R31LJFfiZkY/kXmwkjtlQ==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
+    workbox-routing "^6.0.2"
+    workbox-strategies "^6.0.2"
 
-workbox-range-requests@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz#7066a12c121df65bf76fdf2b0868016aa2bab859"
-  integrity sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw==
+workbox-range-requests@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.0.2.tgz#3b50cbe8ddaaed7e3bfaa2dfdcd6a22e02fe7770"
+  integrity sha512-qCrDbH9AzDbCErde71Nys2iNZO9I9M9Jgl/9/Q67dGQVwFsEq73SuIzS2DGIBKqtIdC5QUigC3d7XJONajclUQ==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-routing@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.4.tgz#3e8cd86bd3b6573488d1a2ce7385e547b547e970"
-  integrity sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw==
+workbox-recipes@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.0.2.tgz#ad4b3f26a71a7396004c4f617af318f3fd072208"
+  integrity sha512-ewZIHO4jYE6bnEeUIYS6joQy3l+MydpOsVr2F6EpE8ps++z1ScbSdLtJU+yu6WuO3lH44HFZLeFxYQqYm50QAA==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-cacheable-response "^6.0.2"
+    workbox-core "^6.0.2"
+    workbox-expiration "^6.0.2"
+    workbox-precaching "^6.0.2"
+    workbox-routing "^6.0.2"
+    workbox-strategies "^6.0.2"
 
-workbox-strategies@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.4.tgz#96b1418ccdfde5354612914964074d466c52d08c"
-  integrity sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA==
+workbox-routing@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.0.2.tgz#8380bc322a2b1c44978df8ff6ae4e4d723f4e3f8"
+  integrity sha512-iQ9ch3fL1YpztDLfHNURaHQ0ispgPCdzWmZZhtSHUyy/+YkTlIiDVTbOQCIpHIrWlKQiim6X3K2ItIy1FW9+wA==
   dependencies:
-    workbox-core "^5.1.4"
-    workbox-routing "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-streams@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-streams/-/workbox-streams-5.1.4.tgz#05754e5e3667bdc078df2c9315b3f41210d8cac0"
-  integrity sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw==
+workbox-strategies@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.0.2.tgz#f4383e2e5d46c1546e6e08048c9f5c9a7beb5137"
+  integrity sha512-HjLnYCVS60U7OKhl5NIq8NAQXrotJQRDakmIONnRlQIlP2If/kAiQSUP3QCHMq4EeXGiF+/CdlR1/bhYBHZzZg==
   dependencies:
-    workbox-core "^5.1.4"
-    workbox-routing "^5.1.4"
+    workbox-core "^6.0.2"
 
-workbox-sw@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-5.1.4.tgz#2bb34c9f7381f90d84cef644816d45150011d3db"
-  integrity sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA==
-
-workbox-window@^5.1.4:
-  version "5.1.4"
-  resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-5.1.4.tgz#2740f7dea7f93b99326179a62f1cc0ca2c93c863"
-  integrity sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw==
+workbox-streams@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.0.2.tgz#07c19025af309ad3475e737018a05ed538bffacd"
+  integrity sha512-bckftu/iMlg5LFXPZ6NX/FUc/w4illgxSuwtsZkQAO6Uen1EeegjfLyenO01/dwoyc3D/AlZepMdhv87XhE7HQ==
   dependencies:
-    workbox-core "^5.1.4"
+    workbox-core "^6.0.2"
+    workbox-routing "^6.0.2"
+
+workbox-sw@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.0.2.tgz#cd1b8b02ceaaf1abe5804936158a87ec605d271e"
+  integrity sha512-EoOjbyy5bpoBoSqt2PIeDOZ/JJ41f+WJjb979PkfIUWw4F+F/w2uKJJrMA5fk+nWnVge83Fwy8nF3dWNsqOrdg==
+
+workbox-window@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-6.0.2.tgz#9b47fdb7c088aa4e8b7d0c6cfda17c8bfca6bf7f"
+  integrity sha512-I/X+qUh1AwN9x/MxFbXsPn7DA27BMtzkXo55w1tBD8V54fv8nUCeC5E4RpXt/mlgdSwBztnURCQTWsdhTrSUjg==
+  dependencies:
+    workbox-core "^6.0.2"
 
 wrap-ansi@^5.1.0:
   version "5.1.0"

--
Gitblit v1.8.0