Quellcode durchsuchen

feat(组件): 新增通用的message

gemercheung vor 2 Jahren
Ursprung
Commit
dd6065c441

+ 1 - 0
docs/.vitepress/config.mts

@@ -68,6 +68,7 @@ export const config: UserConfig = {
     logoSmall: '/images/kankan_icon.ico',
     sidebars,
     nav,
+
     // agolia: {
     //     apiKey: '377f2b647a96d9b1d62e4780f2344da2',
     //     appId: 'BH4D9OD16A',

+ 4 - 0
docs/.vitepress/i18n/pages/component.json

@@ -24,6 +24,10 @@
           "text": "Dialog对话框"
         },
         {
+          "link": "/message",
+          "text": "Message 消息提示"
+        },
+        {
           "link": "/message-box",
           "text": "MessageBox 消息弹框"
         }

+ 2 - 2
docs/.vitepress/vitepress/components/demo/vp-example.vue

@@ -53,7 +53,7 @@ const store = new ReplStore({
   // default is the CDN link from unpkg.com with version matching Vue's version
   // from peerDependency
   defaultVueRuntimeURL:
-    'https://cdn.jsdelivr.net/npm/@vue/runtime-dom@latest/dist/runtime-dom.esm-browser.js',
+    'https://cdn.jsdelivr.net/npm/@vue/runtime-dom@3.2.47/dist/runtime-dom.esm-browser.js',
 })
 
 watchEffect(async () => {
@@ -63,7 +63,7 @@ watchEffect(async () => {
     if (unref(props.raw)) {
       store.setImportMap({
         imports: {
-          vue: 'https://cdn.jsdelivr.net/npm/@vue/runtime-dom@latest/dist/runtime-dom.esm-browser.js',
+          vue: 'https://cdn.jsdelivr.net/npm/@vue/runtime-dom@3.2.47/dist/runtime-dom.esm-browser.js',
           '@vue/shared':
             'https://cdn.jsdelivr.net/npm/@vue/shared@latest/dist/shared.esm-bundler.js',
           'kankan-components':

+ 22 - 0
docs/examples/message/basic.vue

@@ -0,0 +1,22 @@
+<template>
+  <kk-button :plain="true" @click="open">Show message</kk-button>
+  <kk-button :plain="true" @click="openVn">VNode</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { h } from 'vue'
+import { KkMessage, KkButton } from 'kankan-components'
+
+const open = () => {
+  KkMessage('this is a message.')
+}
+
+const openVn = () => {
+  KkMessage({
+    message: h('p', null, [
+      h('span', null, 'Message can be '),
+      h('i', { style: 'color: teal' }, 'VNode'),
+    ]),
+  })
+}
+</script>

+ 15 - 0
docs/examples/message/centered-content.vue

@@ -0,0 +1,15 @@
+<template>
+  <kk-button plain @click="openCenter">Centered text</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { KkMessage, KkButton } from 'kankan-components'
+
+const openCenter = () => {
+  KkMessage({
+    showClose: true,
+    message: 'Centered text',
+    center: true,
+  })
+}
+</script>

+ 38 - 0
docs/examples/message/closable.vue

@@ -0,0 +1,38 @@
+<template>
+  <kk-button :plain="true" @click="open1">message</kk-button>
+  <kk-button :plain="true" @click="open2">success</kk-button>
+  <kk-button :plain="true" @click="open3">warning</kk-button>
+  <kk-button :plain="true" @click="open4">error</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { KkMessage, KkButton } from 'kankan-components'
+
+const open1 = () => {
+  KkMessage({
+    showClose: true,
+    message: 'This is a message.',
+  })
+}
+const open2 = () => {
+  KkMessage({
+    showClose: true,
+    message: 'Congrats, this is a success message.',
+    type: 'success',
+  })
+}
+const open3 = () => {
+  KkMessage({
+    showClose: true,
+    message: 'Warning, this is a warning message.',
+    type: 'warning',
+  })
+}
+const open4 = () => {
+  KkMessage({
+    showClose: true,
+    message: 'Oops, this is a error message.',
+    type: 'error',
+  })
+}
+</script>

+ 29 - 0
docs/examples/message/different-types.vue

@@ -0,0 +1,29 @@
+<template>
+  <kk-button :plain="true" @click="open2">success</kk-button>
+  <kk-button :plain="true" @click="open3">warning</kk-button>
+  <kk-button :plain="true" @click="open1">message</kk-button>
+  <kk-button :plain="true" @click="open4">error</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { KkMessage, KkButton } from 'kankan-components'
+
+const open1 = () => {
+  KkMessage('this is a message.')
+}
+const open2 = () => {
+  KkMessage({
+    message: 'Congrats, this is a success message.',
+    type: 'success',
+  })
+}
+const open3 = () => {
+  KkMessage({
+    message: 'Warning, this is a warning message.',
+    type: 'warning',
+  })
+}
+const open4 = () => {
+  KkMessage.error('Oops, this is a error message.')
+}
+</script>

+ 14 - 0
docs/examples/message/grouping.vue

@@ -0,0 +1,14 @@
+<template>
+  <kk-button :plain="true" @click="open">Show message</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { KkMessage, KkButton } from 'kankan-components'
+const open = () => {
+  KkMessage({
+    message: 'this is a message.',
+    grouping: true,
+    type: 'success',
+  })
+}
+</script>

+ 14 - 0
docs/examples/message/raw-html.vue

@@ -0,0 +1,14 @@
+<template>
+  <kk-button :plain="true" @click="openHTML">Use HTML String</kk-button>
+</template>
+
+<script lang="ts" setup>
+import { KkMessage, KkButton } from 'kankan-components'
+
+const openHTML = () => {
+  KkMessage({
+    dangerouslyUseHTMLString: true,
+    message: '<strong>This is <i>HTML</i> string</strong>',
+  })
+}
+</script>

+ 3 - 1
docs/package.json

@@ -38,6 +38,7 @@
     "consola": "^2.15.3",
     "escape-html": "^1.0.3",
     "fast-glob": "^3.2.11",
+    "flexsearch": "^0.7.31",
     "markdown-it-container": "^3.0.0",
     "octokit": "^2.0.3",
     "prismjs": "^1.28.0",
@@ -49,6 +50,7 @@
     "vite-plugin-inspect": "^0.5.0",
     "vite-plugin-mkcert": "^1.7.2",
     "vite-plugin-pwa": "^0.12.0",
-    "vitepress": "^0.22.4"
+    "vitepress": "^0.22.4",
+    "vitepress-plugin-search": "1.0.4-alpha.20"
   }
 }

+ 1 - 0
docs/vite.config.ts

@@ -78,6 +78,7 @@ export default defineConfig(async ({ mode }) => {
     resolve: {
       alias,
     },
+
     plugins: [
       VueMacros({
         setupComponent: false,

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 178
docs/zh-CN/component/message-box copy.md


+ 2 - 2
docs/zh-CN/component/message-box.md

@@ -1,6 +1,6 @@
 ---
-title: Message
-lang: en-US
+title: MessageBox 消息弹框
+lang: zh-CN
 ---
 
 # MessageBox 消息弹框

+ 133 - 0
docs/zh-CN/component/message.md

@@ -0,0 +1,133 @@
+---
+title: Message 消息提示
+lang: zh-CN
+---
+
+# Message 消息提示
+
+常用于主动操作后的反馈提示。 与 Notification 的区别是后者更多用于系统级通知的被动提醒。
+
+## 基础用法
+
+:::demo
+
+message/basic
+
+:::
+
+## 不同状态
+
+用来显示「成功、警告、消息、错误」类的操作反馈。
+
+:::demo 当需要自定义更多属性时,Message 也可以接收一个对象为参数。 比如,设置 `type` 字段可以定义不同的状态,默认为 `info`。 此时正文内容以 `message` 的值传入。 同时,我们也为 `Message` 的各种 `type` 注册了方法,可以在不传入 `type` 字段的情况下像 `open4` 那样直接调用。
+
+message/different-types
+
+:::
+
+## 可关闭的消息提示
+
+可以添加关闭按钮。
+
+:::demo 默认的 `Message` 是不可以被人工关闭的。 如果你需要手动关闭功能,你可以把 `showClose` 设置为 true 此外,和 Notification 一样,Message 拥有可控的 `duration`, 默认的关闭时间为 3000 毫秒,当把这个属性的值设置为 0 便表示该消息不会被自动关闭。
+
+message/closable
+
+:::
+
+## 文字居中
+
+使用 `center` 属性让文字水平居中。
+
+:::demo
+
+message/centered-content
+
+:::
+
+## 使用 HTML 片段作为正文内容
+
+`message` 还支持使用 HTML 字符串作为正文内容。
+
+:::demo 将 `dangerouslyUseHTMLString` 属性设置为 true,message 就会被当作 HTML 片段处理。
+
+message/raw-html
+
+:::
+
+:::warning
+
+`message` 属性虽然支持传入 HTML 片段,但是在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 [XSS attacks](https://en.wikipedia.org/wiki/Cross-site_scripting) 攻击。 因此在 `dangerouslyUseHTMLString` 打开的情况下,请确保 `message` 的内容是可信的,永远不要将用户提交的内容赋值给 `message` 属性。
+
+:::
+
+## 分组消息合并
+
+合并相同内容的消息。
+
+:::demo 设置 `grouping` 为 true,内容相同的 `message` 将被合并。
+
+message/grouping
+
+:::
+
+## 全局方法
+
+kankan components 为 app.config.globalProperties 添加了全局方法 $message。 因此在 vue 实例中你可以使用当前页面中的调用方式调用 Message
+
+## Local import
+
+```ts
+import { KkMessage } from 'kankan-components'
+```
+
+此时调用方法为 `KkMessage(options)`。 我们也为每个 type 定义了各自的方法,如 `KkMessage.success(options)`。 并且可以调用 `KkMessage.closeAll()` 手动关闭所有实例。
+
+## App context inheritance <el-tag> >= 2.0.3</el-tag>
+
+现在 Message 接受一条 `context` 作为消息构造器的第二个参数,允许你将当前应用的上下文注入到 `Message` 中,这将允许你继承应用程序的所有属性。
+
+你可以像这样使用它:
+
+:::tip
+
+如果您全局注册了 KkMessage 组件,它将自动继承应用的上下文环境。
+
+:::
+
+```ts
+import { getCurrentInstance } from 'vue'
+import { KkMessage } from 'kankan-components'
+
+// in your setup method
+const { appContext } = getCurrentInstance()!
+KkMessage({}, appContext)
+```
+
+## API
+
+### Options
+
+| Name                     | Description                                                                                          | Type                                                 | Default |
+| ------------------------ | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------- |
+| message                  | message text                                                                                         | ^[string] / ^[VNode] / ^[Function]`() => VNode`      | ''      |
+| type                     | message type                                                                                         | ^[enum]`'success' \| 'warning' \| 'info' \| 'error'` | info    |
+| icon                     | custom icon component, overrides `type`                                                              | ^[string] / ^[Component]                             | —       |
+| dangerouslyUseHTMLString | whether `message` is treated as HTML string                                                          | ^[boolean]                                           | false   |
+| customClass              | custom class name for Message                                                                        | ^[string]                                            | ''      |
+| duration                 | display duration, millisecond. If set to 0, it will not turn off automatically                       | ^[number]                                            | 3000    |
+| showClose                | whether to show a close button                                                                       | ^[boolean]                                           | false   |
+| center                   | whether to center the text                                                                           | ^[boolean]                                           | false   |
+| onClose                  | callback function when closed with the message instance as the parameter                             | ^[Function]`() => void`                              | —       |
+| offset                   | set the distance to the top of viewport                                                              | ^[number]                                            | 16      |
+| appendTo                 | set the root element for the message, default to `document.body`                                     | ^[string] / ^[HTMLElement]                           | —       |
+| grouping                 | merge messages with the same content, type of VNode message is not supported                         | ^[boolean]                                           | false   |
+| repeatNum                | The number of repetitions, similar to badge, is used as the initial number when used with `grouping` | ^[number]                                            | 1       |
+
+### Methods
+
+`Message` and `this.$message` returns the current Message instance. To manually close the instance, you can call `close` on it.
+
+| Name  | Description       | Type                    |
+| ----- | ----------------- | ----------------------- |
+| close | close the Message | ^[Function]`() => void` |

+ 2 - 2
packages/components/basic/badge/style/css.ts

@@ -1,2 +1,2 @@
-import '@element-plus/components/base/style/css'
-import '@element-plus/theme-chalk/kk-badge.css'
+import '@kankan-components/components/base/style/css'
+import '@kankan-components/theme-chalk/kk-badge.css'

+ 2 - 2
packages/components/basic/badge/style/index.ts

@@ -1,2 +1,2 @@
-import '@element-plus/components/base/style'
-import '@element-plus/theme-chalk/src/badge.scss'
+import '@kankan-components/components/base/style'
+import '@kankan-components/theme-chalk/src/badge.scss'

+ 3 - 2
packages/components/basic/dialog/src/dialog-content.vue

@@ -13,9 +13,10 @@
         type="button"
         @click="$emit('close')"
       >
-        <kk-icon :class="ns.e('close')">
+        <!-- <kk-icon :class="ns.e('close')">
           <component :is="closeIcon || Close" />
-        </kk-icon>
+        </kk-icon> -->
+        <kk-icon type="close" />
       </button>
     </header>
     <div :id="bodyId" :class="ns.e('body')">

+ 1 - 1
packages/components/basic/focus-trap/__tests__/focus-trap.test.ts

@@ -1,7 +1,7 @@
 import { h, inject, nextTick } from 'vue'
 import { mount } from '@vue/test-utils'
 import { afterEach, describe, expect, it, vi } from 'vitest'
-import { EVENT_CODE } from '@element-plus/constants'
+import { EVENT_CODE } from '@kankan-components/constants'
 import ElFocusTrap from '../src/focus-trap.vue'
 import { FOCUS_TRAP_INJECTION_KEY } from '../src/tokens'
 

+ 1 - 1
packages/components/basic/icon/src/icon.vue

@@ -12,7 +12,7 @@
 </template>
 
 <script lang="ts" setup>
-import { computed, defineEmits, defineProps } from 'vue'
+import { computed } from 'vue'
 import { normalizeUnitToStyle, os } from '@kankan-components/utils'
 import { iconProps } from './icon'
 

+ 3 - 2
packages/components/basic/message-box/src/index.vue

@@ -61,9 +61,10 @@
                   handleAction(distinguishCancelAndClose ? 'close' : 'cancel')
                 "
               >
-                <kk-icon :class="ns.e('close')">
+                <!-- <kk-icon :class="ns.e('close')">
                   <close />
-                </kk-icon>
+                </kk-icon> -->
+                <kk-icon type="close" />
               </button>
             </div>
             <div :id="contentId" :class="ns.e('content')">

+ 13 - 13
packages/components/basic/message-box/src/message-box.type.ts

@@ -62,7 +62,7 @@ export type Callback =
   | ((action: Action) => any)
 
 /** Options used in MessageBox */
-export interface ElMessageBoxOptions {
+export interface KkMessageBoxOptions {
   /**
    * auto focus when open message-box
    */
@@ -106,7 +106,7 @@ export interface ElMessageBoxOptions {
   message?: string | VNode | (() => VNode)
 
   /** Title of the MessageBox */
-  title?: string | ElMessageBoxOptions
+  title?: string | KkMessageBoxOptions
 
   /** Message type, used for icon display */
   type?: MessageType
@@ -175,19 +175,19 @@ export interface ElMessageBoxOptions {
   appendTo?: HTMLElement | string
 }
 
-export type ElMessageBoxShortcutMethod = ((
-  message: ElMessageBoxOptions['message'],
-  title: ElMessageBoxOptions['title'],
-  options?: ElMessageBoxOptions,
+export type KkMessageBoxShortcutMethod = ((
+  message: KkMessageBoxOptions['message'],
+  title: KkMessageBoxOptions['title'],
+  options?: KkMessageBoxOptions,
   appContext?: AppContext | null
 ) => Promise<MessageBoxData>) &
   ((
-    message: ElMessageBoxOptions['message'],
-    options?: ElMessageBoxOptions,
+    message: KkMessageBoxOptions['message'],
+    options?: KkMessageBoxOptions,
     appContext?: AppContext | null
   ) => Promise<MessageBoxData>)
 
-export interface IElMessageBox {
+export interface IKkMessageBox {
   _context: AppContext | null
 
   /** Show a message box */
@@ -195,18 +195,18 @@ export interface IElMessageBox {
 
   /** Show a message box */
   (
-    options: ElMessageBoxOptions,
+    options: KkMessageBoxOptions,
     appContext?: AppContext | null
   ): Promise<MessageBoxData>
 
   /** Show an alert message box */
-  alert: ElMessageBoxShortcutMethod
+  alert: KkMessageBoxShortcutMethod
 
   /** Show a confirm message box */
-  confirm: ElMessageBoxShortcutMethod
+  confirm: KkMessageBoxShortcutMethod
 
   /** Show a prompt message box */
-  prompt: ElMessageBoxShortcutMethod
+  prompt: KkMessageBoxShortcutMethod
 
   /** Close current message box */
   close(): void

+ 14 - 14
packages/components/basic/message-box/src/messageBox.ts

@@ -16,9 +16,9 @@ import type { AppContext, ComponentPublicInstance, VNode } from 'vue'
 import type {
   Action,
   Callback,
-  ElMessageBoxOptions,
-  ElMessageBoxShortcutMethod,
-  IElMessageBox,
+  IKkMessageBox,
+  KkMessageBoxOptions,
+  KkMessageBoxShortcutMethod,
   MessageBoxData,
   MessageBoxState,
 } from './message-box.type'
@@ -143,11 +143,11 @@ const showMessage = (options: any, appContext?: AppContext | null) => {
 }
 
 async function MessageBox(
-  options: ElMessageBoxOptions,
+  options: KkMessageBoxOptions,
   appContext?: AppContext | null
 ): Promise<MessageBoxData>
 function MessageBox(
-  options: ElMessageBoxOptions | string | VNode,
+  options: KkMessageBoxOptions | string | VNode,
   appContext: AppContext | null = null
 ): Promise<{ value: string; action: Action } | Action> {
   if (!isClient) return Promise.reject()
@@ -163,7 +163,7 @@ function MessageBox(
   return new Promise((resolve, reject) => {
     const vm = showMessage(
       options,
-      appContext ?? (MessageBox as IElMessageBox)._context
+      appContext ?? (MessageBox as IKkMessageBox)._context
     )
     // collect this vm in order to handle upcoming events.
     messageInstance.set(vm, {
@@ -178,7 +178,7 @@ function MessageBox(
 const MESSAGE_BOX_VARIANTS = ['alert', 'confirm', 'prompt'] as const
 const MESSAGE_BOX_DEFAULT_OPTS: Record<
   typeof MESSAGE_BOX_VARIANTS[number],
-  Partial<ElMessageBoxOptions>
+  Partial<KkMessageBoxOptions>
 > = {
   alert: { closeOnPressEscape: false, closeOnClickModal: false },
   confirm: { showCancelButton: true },
@@ -186,21 +186,21 @@ const MESSAGE_BOX_DEFAULT_OPTS: Record<
 }
 
 MESSAGE_BOX_VARIANTS.forEach((boxType) => {
-  ;(MessageBox as IElMessageBox)[boxType] = messageBoxFactory(
+  ;(MessageBox as IKkMessageBox)[boxType] = messageBoxFactory(
     boxType
-  ) as ElMessageBoxShortcutMethod
+  ) as KkMessageBoxShortcutMethod
 })
 
 function messageBoxFactory(boxType: typeof MESSAGE_BOX_VARIANTS[number]) {
   return (
     message: string | VNode,
-    title: string | ElMessageBoxOptions,
-    options?: ElMessageBoxOptions,
+    title: string | KkMessageBoxOptions,
+    options?: KkMessageBoxOptions,
     appContext?: AppContext | null
   ) => {
     let titleOrOpts = ''
     if (isObject(title)) {
-      options = title as ElMessageBoxOptions
+      options = title as KkMessageBoxOptions
       titleOrOpts = ''
     } else if (isUndefined(title)) {
       titleOrOpts = ''
@@ -236,6 +236,6 @@ MessageBox.close = () => {
 
   messageInstance.clear()
 }
-;(MessageBox as IElMessageBox)._context = null
+;(MessageBox as IKkMessageBox)._context = null
 
-export default MessageBox as IElMessageBox
+export default MessageBox as IKkMessageBox

+ 5 - 3
packages/components/basic/message/src/message.vue

@@ -26,6 +26,7 @@
         :type="badgeType"
         :class="ns.e('badge')"
       />
+
       <kk-icon v-if="iconComponent" :class="[ns.e('icon'), typeClass]">
         <component :is="iconComponent" />
       </kk-icon>
@@ -36,9 +37,10 @@
         <!-- Caution here, message could've been compromised, never use user's input as message -->
         <p v-else :class="ns.e('content')" v-html="message" />
       </slot>
-      <kk-icon v-if="showClose" :class="ns.e('closeBtn')" @click.stop="close">
+      <!-- <kk-icon v-if="showClose" :class="ns.e('closeBtn')" >
         <Close />
-      </kk-icon>
+      </kk-icon> -->
+      <kk-icon v-if="showClose" type="close" @click.stop="close" />
     </div>
   </transition>
 </template>
@@ -59,7 +61,7 @@ import type { CSSProperties } from 'vue'
 const { Close } = TypeComponents
 
 defineOptions({
-  name: 'ElMessage',
+  name: 'KkMessage',
 })
 
 const props = defineProps(messageProps)

+ 1 - 1
packages/components/basic/message/src/method.ts

@@ -48,7 +48,7 @@ const normalizeOptions = (params?: MessageParams) => {
     // should fallback to default value with a warning
     if (!isElement(appendTo)) {
       debugWarn(
-        'ElMessage',
+        'KkMessage',
         'the appendTo option is not an HTMLElement. Falling back to document.body.'
       )
       appendTo = document.body

+ 2 - 1
packages/kankan-components/plugin.ts

@@ -1,4 +1,5 @@
+import { KkMessage } from '@kankan-components/components/basic/message'
 import { KkMessageBox } from '@kankan-components/components/basic/message-box'
 import type { Plugin } from 'vue'
 
-export default [KkMessageBox] as Plugin[]
+export default [KkMessage, KkMessageBox] as Plugin[]

+ 4 - 1
packages/theme-chalk/src/index.scss

@@ -4,9 +4,12 @@
 @use './button.scss';
 @use './badge.scss';
 
+@use './message.scss';
+@use './message-box.scss';
+
 @use './audio.scss';
 @use './overlay.scss';
 @use './dialog.scss';
 @use './input.scss';
-@use './message-box.scss'; // component adv styles
+
 @use './config-provider.scss';

+ 105 - 0
packages/theme-chalk/src/message.scss

@@ -0,0 +1,105 @@
+@use 'mixins/mixins' as *;
+@use 'mixins/var' as *;
+@use 'common/var' as *;
+
+@include b(message) {
+  @include set-component-css-var('message', $message);
+}
+
+@include b(message) {
+  width: fit-content;
+  max-width: calc(100% - 32px);
+  box-sizing: border-box;
+  border-radius: getCssVar('border-radius-base');
+  border-width: getCssVar('border-width');
+  border-style: getCssVar('border-style');
+  border-color: getCssVar('message', 'border-color');
+  position: fixed;
+  left: 50%;
+  top: 20px;
+  transform: translateX(-50%);
+  background-color: getCssVar('message', 'bg-color');
+  transition: opacity getCssVar('transition-duration'), transform 0.4s, top 0.4s;
+  padding: getCssVar('message', 'padding');
+  display: flex;
+  align-items: center;
+
+  @include when(center) {
+    justify-content: center;
+  }
+
+  @include when(closable) {
+    .#{$namespace}-message__content {
+      padding-right: 31px;
+    }
+  }
+
+  p {
+    margin: 0;
+  }
+
+  @each $type in (success, info, warning, error) {
+    @include m($type) {
+      @include css-var-from-global(
+        ('message', 'bg-color'),
+        ('color', $type, 'light-9')
+      );
+      @include css-var-from-global(
+        ('message', 'border-color'),
+        ('color', $type, 'light-8')
+      );
+      @include css-var-from-global(('message', 'text-color'), ('color', $type));
+
+      .#{$namespace}-message__content {
+        color: getCssVar('message', 'text-color');
+        overflow-wrap: anywhere;
+      }
+    }
+
+    & .#{$namespace}-message-icon--#{$type} {
+      color: getCssVar('message', 'text-color');
+    }
+  }
+
+  @include e(icon) {
+    margin-right: 10px;
+  }
+
+  .#{$namespace}-message__badge {
+    position: absolute;
+    top: -8px;
+    right: -8px;
+  }
+
+  @include e(content) {
+    padding: 0;
+    font-size: 14px;
+    line-height: 1;
+    &:focus {
+      outline-width: 0;
+    }
+  }
+
+  & .#{$namespace}-message__closeBtn {
+    position: absolute;
+    top: 50%;
+    right: 19px;
+    transform: translateY(-50%);
+    cursor: pointer;
+    color: getCssVar('message', 'close-icon-color');
+    font-size: getCssVar('message', 'close-size');
+
+    &:focus {
+      outline-width: 0;
+    }
+    &:hover {
+      color: getCssVar('message', 'close-hover-color');
+    }
+  }
+}
+
+.#{$namespace}-message-fade-enter-from,
+.#{$namespace}-message-fade-leave-to {
+  opacity: 0;
+  transform: translate(-50%, -100%);
+}

+ 110 - 72
pnpm-lock.yaml

@@ -158,7 +158,7 @@ importers:
         version: 3.2.1(@algolia/client-search@4.19.1)
       '@kankan-components/icons-vue':
         specifier: ^0.0.1
-        version: 0.0.1(vue@3.2.39)
+        version: 0.0.1(vue@3.3.4)
       '@kankan-components/metadata':
         specifier: workspace:*
         version: link:../internal/metadata
@@ -167,13 +167,13 @@ importers:
         version: link:../packages/utils
       '@vue/repl':
         specifier: ^1.3.2
-        version: 1.3.2(vue@3.2.39)
+        version: 1.3.2(vue@3.3.4)
       '@vue/shared':
         specifier: ^3.2.37
         version: 3.2.39
       '@vueuse/core':
         specifier: ^9.1.0
-        version: 9.3.0(vue@3.2.39)
+        version: 9.3.0(vue@3.3.4)
       axios:
         specifier: ^0.27.2
         version: 0.27.2
@@ -182,7 +182,7 @@ importers:
         version: 4.0.1
       element-plus:
         specifier: npm:element-plus@latest
-        version: 2.3.9(vue@3.2.39)
+        version: 2.3.9(vue@3.3.4)
       kankan-components:
         specifier: workspace:*
         version: link:../packages/kankan-components
@@ -200,7 +200,7 @@ importers:
         version: 0.2.4
       vue:
         specifier: ^3.2.37
-        version: 3.2.39
+        version: 3.3.4
     devDependencies:
       '@crowdin/cli':
         specifier: ^3.7.8
@@ -241,6 +241,9 @@ importers:
       fast-glob:
         specifier: ^3.2.11
         version: 3.2.12
+      flexsearch:
+        specifier: ^0.7.31
+        version: 0.7.31
       markdown-it-container:
         specifier: ^3.0.0
         version: 3.0.0
@@ -258,10 +261,10 @@ importers:
         version: 0.14.11
       unplugin-vue-components:
         specifier: ^0.20.1
-        version: 0.20.1(rollup@2.79.1)(vite@2.9.15)(vue@3.2.39)
+        version: 0.20.1(rollup@2.79.1)(vite@2.9.15)(vue@3.3.4)
       unplugin-vue-macros:
         specifier: ^0.11.2
-        version: 0.11.2(rollup@2.79.1)(vite@2.9.15)(vue@3.2.39)
+        version: 0.11.2(rollup@2.79.1)(vite@2.9.15)(vue@3.3.4)
       vite:
         specifier: ^2.9.15
         version: 2.9.15(sass@1.66.0)
@@ -277,6 +280,9 @@ importers:
       vitepress:
         specifier: ^0.22.4
         version: 0.22.4(@algolia/client-search@4.19.1)(sass@1.66.0)
+      vitepress-plugin-search:
+        specifier: 1.0.4-alpha.20
+        version: 1.0.4-alpha.20(flexsearch@0.7.31)(vitepress@0.22.4)(vue@3.3.4)
 
   internal/build:
     dependencies:
@@ -892,7 +898,7 @@ packages:
     resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-annotate-as-pure@7.22.5:
     resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
@@ -1007,7 +1013,7 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/template': 7.20.7
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-function-name@7.22.5:
     resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==}
@@ -1021,7 +1027,7 @@ packages:
     resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-hoist-variables@7.22.5:
     resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
@@ -1034,7 +1040,7 @@ packages:
     resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-member-expression-to-functions@7.22.5:
     resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==}
@@ -1089,7 +1095,7 @@ packages:
     resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-optimise-call-expression@7.22.5:
     resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
@@ -1127,7 +1133,7 @@ packages:
       '@babel/helper-member-expression-to-functions': 7.18.9
       '@babel/helper-optimise-call-expression': 7.18.6
       '@babel/traverse': 7.19.1
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
     transitivePeerDependencies:
       - supports-color
 
@@ -1147,7 +1153,7 @@ packages:
     resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-simple-access@7.22.5:
     resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
@@ -1167,7 +1173,7 @@ packages:
     resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.10
 
   /@babel/helper-split-export-declaration@7.22.6:
     resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
@@ -1255,13 +1261,6 @@ packages:
     dependencies:
       '@babel/types': 7.20.7
 
-  /@babel/parser@7.20.15:
-    resolution: {integrity: sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
-    dependencies:
-      '@babel/types': 7.20.7
-
   /@babel/parser@7.22.10:
     resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==}
     engines: {node: '>=6.0.0'}
@@ -2205,7 +2204,7 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/code-frame': 7.18.6
-      '@babel/parser': 7.20.15
+      '@babel/parser': 7.22.10
       '@babel/types': 7.20.7
 
   /@babel/template@7.20.7:
@@ -2213,8 +2212,8 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/code-frame': 7.18.6
-      '@babel/parser': 7.20.15
-      '@babel/types': 7.20.7
+      '@babel/parser': 7.22.10
+      '@babel/types': 7.22.10
 
   /@babel/template@7.22.5:
     resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==}
@@ -2235,7 +2234,7 @@ packages:
       '@babel/helper-function-name': 7.19.0
       '@babel/helper-hoist-variables': 7.18.6
       '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/parser': 7.20.15
+      '@babel/parser': 7.22.10
       '@babel/types': 7.20.7
       debug: 4.3.4
       globals: 11.12.0
@@ -2703,12 +2702,12 @@ packages:
     transitivePeerDependencies:
       - '@algolia/client-search'
 
-  /@element-plus/icons-vue@2.1.0(vue@3.2.39):
+  /@element-plus/icons-vue@2.1.0(vue@3.3.4):
     resolution: {integrity: sha512-PSBn3elNoanENc1vnCfh+3WA9fimRC7n+fWkf3rE5jvv+aBohNHABC/KAR5KWPecxWxDTVT1ERpRbOMRcOV/vA==}
     peerDependencies:
       vue: ^3.2.0
     dependencies:
-      vue: 3.2.39
+      vue: 3.3.4
     dev: false
 
   /@esbuild-kit/cjs-loader@2.4.0:
@@ -3137,14 +3136,14 @@ packages:
     engines: {node: '>=6.0.0'}
     dependencies:
       '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
+      '@jridgewell/sourcemap-codec': 1.4.15
 
   /@jridgewell/gen-mapping@0.3.2:
     resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
     engines: {node: '>=6.0.0'}
     dependencies:
       '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
+      '@jridgewell/sourcemap-codec': 1.4.15
       '@jridgewell/trace-mapping': 0.3.17
 
   /@jridgewell/gen-mapping@0.3.3:
@@ -4776,6 +4775,10 @@ packages:
     resolution: {integrity: sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==}
     dev: true
 
+  /@types/flexsearch@0.7.3:
+    resolution: {integrity: sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==}
+    dev: true
+
   /@types/fs-extra@9.0.13:
     resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
     dependencies:
@@ -5395,7 +5398,7 @@ packages:
       - supports-color
     dev: true
 
-  /@vitejs/plugin-vue@2.3.4(vite@2.9.15)(vue@3.2.39):
+  /@vitejs/plugin-vue@2.3.4(vite@2.9.15)(vue@3.3.4):
     resolution: {integrity: sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg==}
     engines: {node: '>=12.0.0'}
     peerDependencies:
@@ -5403,7 +5406,7 @@ packages:
       vue: ^3.2.25
     dependencies:
       vite: 2.9.15(sass@1.66.0)
-      vue: 3.2.39
+      vue: 3.3.4
     dev: true
 
   /@vitejs/plugin-vue@2.3.4(vite@2.9.16)(vue@3.2.39):
@@ -5443,7 +5446,7 @@ packages:
     resolution: {integrity: sha512-T3iJ7Ej5Ywrsn1nEfvOQ98LdFZu3TtoXD8UELHto/u5QyQk4U2GfPl+0ZjuS39ZPocU9l/5CMhrxHsgv/hFWVA==}
     dependencies:
       '@volar/source-map': 1.0.7
-      '@vue/reactivity': 3.2.47
+      '@vue/reactivity': 3.3.4
       muggle-string: 0.1.0
     dev: true
 
@@ -5573,7 +5576,7 @@ packages:
   /@vue/compiler-core@3.2.39:
     resolution: {integrity: sha512-mf/36OWXqWn0wsC40nwRRGheR/qoID+lZXbIuLnr4/AngM0ov8Xvv8GHunC0rKRIkh60bTqydlqTeBo49rlbqw==}
     dependencies:
-      '@babel/parser': 7.20.15
+      '@babel/parser': 7.22.10
       '@vue/shared': 3.2.39
       estree-walker: 2.0.2
       source-map: 0.6.1
@@ -5644,7 +5647,7 @@ packages:
   /@vue/reactivity-transform@3.2.39:
     resolution: {integrity: sha512-HGuWu864zStiWs9wBC6JYOP1E00UjMdDWIG5W+FpUx28hV3uz9ODOKVNm/vdOy/Pvzg8+OcANxAVC85WFBbl3A==}
     dependencies:
-      '@babel/parser': 7.20.15
+      '@babel/parser': 7.22.10
       '@vue/compiler-core': 3.2.39
       '@vue/shared': 3.2.39
       estree-walker: 2.0.2
@@ -5675,12 +5678,12 @@ packages:
     dependencies:
       '@vue/shared': 3.3.4
 
-  /@vue/repl@1.3.2(vue@3.2.39):
+  /@vue/repl@1.3.2(vue@3.3.4):
     resolution: {integrity: sha512-5joGOuTFmjaugG3E1h/oP1EXSMcVXRUwLIoo8xvYQnqDrCT6g1SfsH1pfei5PpC5DUxMX1584CekZu6REgGYkQ==}
     peerDependencies:
       vue: ^3.2.13
     dependencies:
-      vue: 3.2.39
+      vue: 3.3.4
     dev: false
 
   /@vue/runtime-core@3.2.39:
@@ -5751,18 +5754,6 @@ packages:
       vue-component-type-helpers: 1.8.4
     dev: true
 
-  /@vueuse/core@9.13.0(vue@3.2.39):
-    resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
-    dependencies:
-      '@types/web-bluetooth': 0.0.16
-      '@vueuse/metadata': 9.13.0
-      '@vueuse/shared': 9.13.0(vue@3.2.39)
-      vue-demi: 0.14.5(vue@3.2.39)
-    transitivePeerDependencies:
-      - '@vue/composition-api'
-      - vue
-    dev: false
-
   /@vueuse/core@9.13.0(vue@3.3.4):
     resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
     dependencies:
@@ -5787,6 +5778,18 @@ packages:
       - vue
     dev: false
 
+  /@vueuse/core@9.3.0(vue@3.3.4):
+    resolution: {integrity: sha512-64Rna8IQDWpdrJxgitDg7yv1yTp41ZmvV8zlLEylK4QQLWAhz1OFGZDPZ8bU4lwcGgbEJ2sGi2jrdNh4LttUSQ==}
+    dependencies:
+      '@types/web-bluetooth': 0.0.15
+      '@vueuse/metadata': 9.3.0
+      '@vueuse/shared': 9.3.0(vue@3.3.4)
+      vue-demi: 0.13.11(vue@3.3.4)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
   /@vueuse/metadata@9.13.0:
     resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
     dev: false
@@ -5795,28 +5798,28 @@ packages:
     resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==}
     dev: false
 
-  /@vueuse/shared@9.13.0(vue@3.2.39):
+  /@vueuse/shared@9.13.0(vue@3.3.4):
     resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
     dependencies:
-      vue-demi: 0.14.5(vue@3.2.39)
+      vue-demi: 0.14.5(vue@3.3.4)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
     dev: false
 
-  /@vueuse/shared@9.13.0(vue@3.3.4):
-    resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
+  /@vueuse/shared@9.3.0(vue@3.2.39):
+    resolution: {integrity: sha512-caGUWLY0DpPC6l31KxeUy6vPVNA0yKxx81jFYLoMpyP6cF84FG5Dkf69DfSUqL57wX8JcUkJDMnQaQIZPWFEQQ==}
     dependencies:
-      vue-demi: 0.14.5(vue@3.3.4)
+      vue-demi: 0.14.5(vue@3.2.39)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
     dev: false
 
-  /@vueuse/shared@9.3.0(vue@3.2.39):
+  /@vueuse/shared@9.3.0(vue@3.3.4):
     resolution: {integrity: sha512-caGUWLY0DpPC6l31KxeUy6vPVNA0yKxx81jFYLoMpyP6cF84FG5Dkf69DfSUqL57wX8JcUkJDMnQaQIZPWFEQQ==}
     dependencies:
-      vue-demi: 0.13.11(vue@3.2.39)
+      vue-demi: 0.14.5(vue@3.3.4)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
@@ -6461,7 +6464,7 @@ packages:
     resolution: {integrity: sha512-9reB+iYF6jCCDqKDNNQI8iA2MJcy0jCLvEjfya72F7Zai5i2CB8hk9K/kzkZhagja9othQCFPEvQW11LhPKjmg==}
     engines: {node: '>=14.19.0'}
     dependencies:
-      '@babel/parser': 7.20.15
+      '@babel/parser': 7.22.10
       '@babel/types': 7.20.7
 
   /async-done@1.3.2:
@@ -8100,18 +8103,18 @@ packages:
     resolution: {integrity: sha512-mwknuemBZnoOCths4GtpU/SDuVMp3uQHKa2UNJT9/aVD6WVRjGpXOxRGX7lm6ILIenTdGXPSTCTDaWos5tEU8Q==}
     dev: true
 
-  /element-plus@2.3.9(vue@3.2.39):
+  /element-plus@2.3.9(vue@3.3.4):
     resolution: {integrity: sha512-TIOLnPl4cnoCPXqK3QYh+jpkthUBQnAM21O7o3Lhbse8v9pfrRXRTaBJtoEKnYNa8GZ4lZptUfH0PeZgDCNLUg==}
     peerDependencies:
       vue: ^3.2.0
     dependencies:
       '@ctrl/tinycolor': 3.6.0
-      '@element-plus/icons-vue': 2.1.0(vue@3.2.39)
+      '@element-plus/icons-vue': 2.1.0(vue@3.3.4)
       '@floating-ui/dom': 1.5.1
       '@popperjs/core': /@sxzz/popperjs-es@2.11.7
       '@types/lodash': 4.14.197
       '@types/lodash-es': 4.17.8
-      '@vueuse/core': 9.13.0(vue@3.2.39)
+      '@vueuse/core': 9.13.0(vue@3.3.4)
       async-validator: 4.2.5
       dayjs: 1.11.9
       escape-html: 1.0.3
@@ -8120,7 +8123,7 @@ packages:
       lodash-unified: 1.0.3(@types/lodash-es@4.17.8)(lodash-es@4.17.21)(lodash@4.17.21)
       memoize-one: 6.0.0
       normalize-wheel-es: 1.2.0
-      vue: 3.2.39
+      vue: 3.3.4
     transitivePeerDependencies:
       - '@vue/composition-api'
     dev: false
@@ -8166,7 +8169,6 @@ packages:
   /entities@3.0.1:
     resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
     engines: {node: '>=0.12'}
-    dev: false
 
   /env-paths@2.2.1:
     resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
@@ -9930,6 +9932,10 @@ packages:
   /flatted@3.2.7:
     resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
 
+  /flexsearch@0.7.31:
+    resolution: {integrity: sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA==}
+    dev: true
+
   /flush-write-stream@1.1.1:
     resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
     dependencies:
@@ -10257,6 +10263,10 @@ packages:
       unique-stream: 2.3.1
     dev: false
 
+  /glob-to-regexp@0.4.1:
+    resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+    dev: true
+
   /glob-watcher@5.0.5:
     resolution: {integrity: sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==}
     engines: {node: '>= 0.10'}
@@ -12138,7 +12148,6 @@ packages:
     resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==}
     dependencies:
       uc.micro: 1.0.6
-    dev: false
 
   /lint-staged@13.3.0:
     resolution: {integrity: sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==}
@@ -12517,7 +12526,6 @@ packages:
       linkify-it: 4.0.1
       mdurl: 1.0.1
       uc.micro: 1.0.6
-    dev: false
 
   /matchdep@2.0.0:
     resolution: {integrity: sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==}
@@ -12553,7 +12561,6 @@ packages:
 
   /mdurl@1.0.1:
     resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
-    dev: false
 
   /mem@6.1.1:
     resolution: {integrity: sha512-Ci6bIfq/UgcxPTYa8dQQ5FY3BzKkT894bwXWXxC/zqs0XgMO2cT20CGkOqda7gZNkmK5VP4x89IGZ6K7hfbn3Q==}
@@ -15817,7 +15824,6 @@ packages:
 
   /uc.micro@1.0.6:
     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
-    dev: false
 
   /ufo@0.8.5:
     resolution: {integrity: sha512-e4+UtA5IRO+ha6hYklwj6r7BjiGMxS0O+UaSg9HbaTefg4kMkzj4tXzEBajRR+wkxf+golgAWKzLbytCUDMJAA==}
@@ -16121,7 +16127,7 @@ packages:
       - supports-color
     dev: true
 
-  /unplugin-vue-components@0.20.1(rollup@2.79.1)(vite@2.9.15)(vue@3.2.39):
+  /unplugin-vue-components@0.20.1(rollup@2.79.1)(vite@2.9.15)(vue@3.3.4):
     resolution: {integrity: sha512-I70rKUvnJXxBvvTvKhjMV6jXh48BdiUNn2jcQiTdZjqBA3Xgkze31tdc4KBX46yryIy0y6pVaZ9gVBNPrF785g==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -16141,7 +16147,7 @@ packages:
       minimatch: 5.1.0
       resolve: 1.22.1
       unplugin: 0.7.2(rollup@2.79.1)(vite@2.9.15)
-      vue: 3.2.39
+      vue: 3.3.4
     transitivePeerDependencies:
       - esbuild
       - rollup
@@ -16241,7 +16247,7 @@ packages:
       - webpack
     dev: false
 
-  /unplugin-vue-macros@0.11.2(rollup@2.79.1)(vite@2.9.15)(vue@3.2.39):
+  /unplugin-vue-macros@0.11.2(rollup@2.79.1)(vite@2.9.15)(vue@3.3.4):
     resolution: {integrity: sha512-DvEFbqyio24pOzSyvzDiCaPXnOwJEd9u1Dr2cshMcnSft6OWBgwbm6IumVBbOSydEpClORcZAouxA9CyjUyMbQ==}
     engines: {node: '>=14.19.0'}
     peerDependencies:
@@ -16257,7 +16263,7 @@ packages:
       local-pkg: 0.4.2
       unplugin-combine: 0.2.2(rollup@2.79.1)(vite@2.9.15)
       unplugin-vue-define-options: 0.11.2
-      vue: 3.2.39
+      vue: 3.3.4
     transitivePeerDependencies:
       - esbuild
       - rollup
@@ -16750,6 +16756,23 @@ packages:
       fsevents: 2.3.2
     dev: true
 
+  /vitepress-plugin-search@1.0.4-alpha.20(flexsearch@0.7.31)(vitepress@0.22.4)(vue@3.3.4):
+    resolution: {integrity: sha512-zG+ev9pw1Mg7htABlFCNXb8XwnKN+qfTKw+vU0Ers6RIrABx+45EAAFBoaL1mEpl1FRFn1o/dQ7F4b8GP6HdGQ==}
+    engines: {node: ^14.13.1 || ^16.7.0 || >=18}
+    peerDependencies:
+      flexsearch: ^0.7.31
+      vitepress: ^1.0.0-alpha.65
+      vue: '3'
+    dependencies:
+      '@types/flexsearch': 0.7.3
+      '@types/markdown-it': 12.2.3
+      flexsearch: 0.7.31
+      glob-to-regexp: 0.4.1
+      markdown-it: 13.0.1
+      vitepress: 0.22.4(@algolia/client-search@4.19.1)(sass@1.66.0)
+      vue: 3.3.4
+    dev: true
+
   /vitepress@0.22.4(@algolia/client-search@4.19.1)(sass@1.66.0):
     resolution: {integrity: sha512-oZUnLO/SpYdThaBKefDeOiVlr0Rie4Ppx3FzMnMyLtJnI5GlBMNjqYqMy/4+umm/iC+ZDJfI+IlDKxv5fZnYzA==}
     engines: {node: '>=14.0.0'}
@@ -16757,10 +16780,10 @@ packages:
     dependencies:
       '@docsearch/css': 3.2.1
       '@docsearch/js': 3.2.1(@algolia/client-search@4.19.1)
-      '@vitejs/plugin-vue': 2.3.4(vite@2.9.15)(vue@3.2.39)
+      '@vitejs/plugin-vue': 2.3.4(vite@2.9.15)(vue@3.3.4)
       prismjs: 1.29.0
       vite: 2.9.15(sass@1.66.0)
-      vue: 3.2.39
+      vue: 3.3.4
     transitivePeerDependencies:
       - '@algolia/client-search'
       - '@types/react'
@@ -16833,6 +16856,21 @@ packages:
       vue: 3.2.39
     dev: false
 
+  /vue-demi@0.13.11(vue@3.3.4):
+    resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+    dependencies:
+      vue: 3.3.4
+    dev: false
+
   /vue-demi@0.14.5(vue@3.2.39):
     resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
     engines: {node: '>=12'}