@morya-ui/mcp 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/data/catalog.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
- "generatedAt": "2026-09-18T07:52:49.105Z",
2
+ "generatedAt": "2026-09-21T09:58:15.212Z",
3
3
  "library": {
4
4
  "name": "morya-ui",
5
- "version": "0.2.7"
5
+ "version": "0.2.9"
6
6
  },
7
7
  "mcp": {
8
8
  "name": "@morya-ui/mcp",
9
- "version": "0.2.7"
9
+ "version": "0.2.9"
10
10
  },
11
11
  "components": [
12
12
  {
@@ -6821,7 +6821,7 @@
6821
6821
  "sectionId": "内置插图",
6822
6822
  "lang": "vue",
6823
6823
  "preview": true,
6824
- "code": "<script setup lang=\"ts\">\r\nimport { MEmpty } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-8\">\r\n <MEmpty\r\n illustration=\"no-content\"\r\n title=\"暂无相关内容\"\r\n description=\"这里还没有可展示的内容。\"\r\n />\r\n <MEmpty\r\n illustration=\"no-result\"\r\n title=\"搜索结果为空\"\r\n description=\"试试调整关键词或筛选条件。\"\r\n />\r\n <MEmpty\r\n illustration=\"no-message\"\r\n title=\"没有新消息\"\r\n description=\"有新动态时会第一时间通知你。\"\r\n />\r\n </div>\r\n</template>",
6824
+ "code": "<script setup lang=\"ts\">\nimport { MEmpty } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-8\">\n <MEmpty\n illustration=\"no-content\"\n title=\"暂无相关内容\"\n description=\"这里还没有可展示的内容。\"\n />\n <MEmpty\n illustration=\"no-result\"\n title=\"搜索结果为空\"\n description=\"试试调整关键词或筛选条件。\"\n />\n <MEmpty\n illustration=\"no-message\"\n title=\"没有新消息\"\n description=\"有新动态时会第一时间通知你。\"\n />\n </div>\n</template>",
6825
6825
  "locale": "zh-CN"
6826
6826
  },
6827
6827
  {
@@ -6830,7 +6830,7 @@
6830
6830
  "sectionId": "紧凑模式",
6831
6831
  "lang": "vue",
6832
6832
  "preview": true,
6833
- "code": "<script setup lang=\"ts\">\r\nimport { MEmpty } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <MEmpty\r\n simple\r\n title=\"\"\r\n description=\"该分组下暂无成员\"\r\n />\r\n</template>",
6833
+ "code": "<script setup lang=\"ts\">\nimport { MEmpty } from 'morya-ui'\n</script>\n\n<template>\n <MEmpty\n simple\n title=\"\"\n description=\"该分组下暂无成员\"\n />\n</template>",
6834
6834
  "locale": "zh-CN"
6835
6835
  },
6836
6836
  {
@@ -6875,7 +6875,7 @@
6875
6875
  "sectionId": "built-in-illustrations",
6876
6876
  "lang": "vue",
6877
6877
  "preview": true,
6878
- "code": "<script setup lang=\"ts\">\r\nimport { MEmpty } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-8\">\r\n <MEmpty\r\n illustration=\"no-content\"\r\n title=\"暂无相关内容\"\r\n description=\"这里还没有可展示的内容。\"\r\n />\r\n <MEmpty\r\n illustration=\"no-result\"\r\n title=\"搜索结果为空\"\r\n description=\"试试调整关键词或筛选条件。\"\r\n />\r\n <MEmpty\r\n illustration=\"no-message\"\r\n title=\"没有新消息\"\r\n description=\"有新动态时会第一时间通知你。\"\r\n />\r\n </div>\r\n</template>",
6878
+ "code": "<script setup lang=\"ts\">\nimport { MEmpty } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-8\">\n <MEmpty\n illustration=\"no-content\"\n title=\"暂无相关内容\"\n description=\"这里还没有可展示的内容。\"\n />\n <MEmpty\n illustration=\"no-result\"\n title=\"搜索结果为空\"\n description=\"试试调整关键词或筛选条件。\"\n />\n <MEmpty\n illustration=\"no-message\"\n title=\"没有新消息\"\n description=\"有新动态时会第一时间通知你。\"\n />\n </div>\n</template>",
6879
6879
  "locale": "en-US"
6880
6880
  },
6881
6881
  {
@@ -6884,7 +6884,7 @@
6884
6884
  "sectionId": "compact",
6885
6885
  "lang": "vue",
6886
6886
  "preview": true,
6887
- "code": "<script setup lang=\"ts\">\r\nimport { MEmpty } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <MEmpty\r\n simple\r\n title=\"\"\r\n description=\"No members in this group yet\"\r\n />\r\n</template>",
6887
+ "code": "<script setup lang=\"ts\">\nimport { MEmpty } from 'morya-ui'\n</script>\n\n<template>\n <MEmpty\n simple\n title=\"\"\n description=\"No members in this group yet\"\n />\n</template>",
6888
6888
  "locale": "en-US"
6889
6889
  }
6890
6890
  ],
@@ -8947,7 +8947,7 @@
8947
8947
  "sectionId": "全部系统图标",
8948
8948
  "lang": "vue",
8949
8949
  "preview": true,
8950
- "code": "<script setup lang=\"ts\">\nimport type {ToastMessage} from 'morya-ui';\nimport { iconNames, MIcon, MInput, MToast } from 'morya-ui'\nimport { computed, ref } from 'vue'\n\nconst query = ref('')\nconst copied = ref<string | null>(null)\nconst messages = ref<ToastMessage[]>([])\nlet toastSeq = 0\nlet copiedTimer: ReturnType<typeof setTimeout> | undefined\n\nconst filtered = computed(() => {\n const q = query.value.trim().toLowerCase()\n if (!q) return [...iconNames]\n return iconNames.filter((name) => name.toLowerCase().includes(q))\n})\n\nfunction itemStyle(name: string) {\n const active = copied.value === name\n return [\n 'align-items:center',\n 'background:var(--m-color-surface)',\n `border:1px solid ${active ? 'var(--m-color-primary)' : 'var(--m-color-border)'}`,\n 'border-radius:var(--m-radius-control, 3px)',\n `color:${active ? 'var(--m-color-primary)' : 'var(--m-color-text)'}`,\n 'cursor:pointer',\n 'display:flex',\n 'flex-direction:column',\n 'font:inherit',\n 'gap:0.65rem',\n 'justify-content:center',\n 'min-height:6.5rem',\n 'padding:0.85rem 0.5rem',\n 'width:100%',\n ].join(';')\n}\n\nasync function copyName(name: string) {\n try {\n await navigator.clipboard.writeText(name)\n } catch {\n const area = document.createElement('textarea')\n area.value = name\n document.body.appendChild(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n }\n copied.value = name\n if (copiedTimer) clearTimeout(copiedTimer)\n copiedTimer = setTimeout(() => {\n if (copied.value === name) copied.value = null\n }, 1200)\n\n const id = `icon-copy-${++toastSeq}`\n messages.value = [\n ...messages.value,\n {\n id,\n severity: 'success',\n summary: '已复制',\n detail: name,\n closable: true,\n },\n ]\n window.setTimeout(() => {\n messages.value = messages.value.filter((item) => item.id !== id)\n }, 1600)\n}\n\nfunction onToastClose(message: ToastMessage) {\n messages.value = messages.value.filter((item) => item.id !== message.id)\n}\n</script>\n\n<template>\n <div class=\"w-full\">\n <MInput\n v-model=\"query\"\n clearable\n fluid\n placeholder=\"搜索图标名称…\"\n class=\"max-w-xs mb-4\"\n >\n <template #prefix>\n <MIcon name=\"search\" size=\"sm\" />\n </template>\n </MInput>\n\n <p\n v-if=\"!filtered.length\"\n style=\"color: var(--m-color-text-muted); font-size: 0.875rem; margin: 0.5rem 0 0\"\n >\n 没有匹配的图标\n </p>\n\n <div\n v-else\n style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(7.25rem,1fr));gap:0.75rem;width:100%\"\n >\n <button\n v-for=\"name in filtered\"\n :key=\"name\"\n type=\"button\"\n :style=\"itemStyle(name)\"\n :title=\"`点击复制 ${name}`\"\n @click=\"copyName(name)\"\n >\n <MIcon :name=\"name\" size=\"large\" />\n <span\n style=\"font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.72rem;line-height:1.3;max-width:100%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap\"\n >\n {{ copied === name ? '已复制' : name }}\n </span>\n </button>\n </div>\n\n <MToast :messages=\"messages\" position=\"top-right\" @close=\"onToastClose\" />\n </div>\n</template>",
8950
+ "code": "<script setup lang=\"ts\">\nimport type { IconCategoryId, ToastMessage } from 'morya-ui'\nimport {\n getIconCategory,\n getIconCategoryGroups,\n iconCategoryMeta,\n iconNames,\n MIcon,\n MInput,\n MToast,\n} from 'morya-ui'\nimport { computed, ref } from 'vue'\n\nconst query = ref('')\nconst category = ref<IconCategoryId | 'all'>('all')\nconst copied = ref<string | null>(null)\nconst messages = ref<ToastMessage[]>([])\nlet toastSeq = 0\nlet copiedTimer: ReturnType<typeof setTimeout> | undefined\n\nconst categoryOptions = computed(() => [\n { id: 'all' as const, label: '全部' },\n ...iconCategoryMeta.map((item) => ({ id: item.id, label: item.labelZh })),\n])\n\nconst filteredNames = computed(() => {\n const q = query.value.trim().toLowerCase()\n return iconNames.filter((name) => {\n if (q && !name.toLowerCase().includes(q)) return false\n if (category.value !== 'all') return getIconCategory(name) === category.value\n return true\n })\n})\n\nconst grouped = computed(() => getIconCategoryGroups(filteredNames.value))\n\nfunction chipStyle(id: IconCategoryId | 'all') {\n const active = category.value === id\n return [\n 'background:' + (active ? 'var(--m-color-primary-soft, color-mix(in srgb, var(--m-color-primary) 14%, transparent))' : 'var(--m-color-surface)'),\n 'border:1px solid ' + (active ? 'var(--m-color-primary)' : 'var(--m-color-border)'),\n 'border-radius:var(--m-radius-full, 999px)',\n 'color:' + (active ? 'var(--m-color-primary)' : 'var(--m-color-text)'),\n 'cursor:pointer',\n 'font:inherit',\n 'font-size:0.8125rem',\n 'line-height:1.2',\n 'padding:0.35rem 0.75rem',\n ].join(';')\n}\n\nfunction itemStyle(name: string) {\n const active = copied.value === name\n return [\n 'align-items:center',\n 'background:var(--m-color-surface)',\n `border:1px solid ${active ? 'var(--m-color-primary)' : 'var(--m-color-border)'}`,\n 'border-radius:var(--m-radius-control, 3px)',\n `color:${active ? 'var(--m-color-primary)' : 'var(--m-color-text)'}`,\n 'cursor:pointer',\n 'display:flex',\n 'flex-direction:column',\n 'font:inherit',\n 'gap:0.65rem',\n 'justify-content:center',\n 'min-height:6.5rem',\n 'padding:0.85rem 0.5rem',\n 'width:100%',\n ].join(';')\n}\n\nasync function copyName(name: string) {\n try {\n await navigator.clipboard.writeText(name)\n } catch {\n const area = document.createElement('textarea')\n area.value = name\n document.body.appendChild(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n }\n copied.value = name\n if (copiedTimer) clearTimeout(copiedTimer)\n copiedTimer = setTimeout(() => {\n if (copied.value === name) copied.value = null\n }, 1200)\n\n const id = `icon-copy-${++toastSeq}`\n messages.value = [\n ...messages.value,\n {\n id,\n severity: 'success',\n summary: '已复制',\n detail: name,\n closable: true,\n },\n ]\n window.setTimeout(() => {\n messages.value = messages.value.filter((item) => item.id !== id)\n }, 1600)\n}\n\nfunction onToastClose(message: ToastMessage) {\n messages.value = messages.value.filter((item) => item.id !== message.id)\n}\n</script>\n\n<template>\n <div class=\"w-full\">\n <MInput\n v-model=\"query\"\n clearable\n fluid\n placeholder=\"搜索图标名称…\"\n class=\"max-w-xs mb-3\"\n >\n <template #prefix>\n <MIcon name=\"search\" size=\"sm\" />\n </template>\n </MInput>\n\n <div style=\"display:flex;flex-wrap:wrap;gap:0.5rem;margin-bottom:1rem\">\n <button\n v-for=\"opt in categoryOptions\"\n :key=\"opt.id\"\n type=\"button\"\n :style=\"chipStyle(opt.id)\"\n @click=\"category = opt.id\"\n >\n {{ opt.label }}\n </button>\n </div>\n\n <p\n v-if=\"!grouped.length\"\n style=\"color: var(--m-color-text-muted); font-size: 0.875rem; margin: 0.5rem 0 0\"\n >\n 没有匹配的图标\n </p>\n\n <div v-else style=\"display:grid;gap:1.25rem;width:100%\">\n <section v-for=\"group in grouped\" :key=\"group.id\">\n <h4\n style=\"align-items:baseline;color:var(--m-color-text);display:flex;font-size:0.875rem;font-weight:600;gap:0.5rem;margin:0 0 0.65rem\"\n >\n <span>{{ group.labelZh }}</span>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem;font-weight:500\">\n {{ group.icons.length }}\n </span>\n </h4>\n <div\n style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(7.25rem,1fr));gap:0.75rem;width:100%\"\n >\n <button\n v-for=\"name in group.icons\"\n :key=\"name\"\n type=\"button\"\n :style=\"itemStyle(name)\"\n :title=\"`点击复制 ${name}`\"\n @click=\"copyName(name)\"\n >\n <MIcon :name=\"name\" size=\"large\" />\n <span\n style=\"font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.72rem;line-height:1.3;max-width:100%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap\"\n >\n {{ copied === name ? '已复制' : name }}\n </span>\n </button>\n </div>\n </section>\n </div>\n\n <MToast :messages=\"messages\" position=\"top-right\" @close=\"onToastClose\" />\n </div>\n</template>",
8951
8951
  "locale": "zh-CN"
8952
8952
  },
8953
8953
  {
@@ -8983,7 +8983,7 @@
8983
8983
  "sectionId": "all-system-icons",
8984
8984
  "lang": "vue",
8985
8985
  "preview": true,
8986
- "code": "<script setup lang=\"ts\">\nimport type {ToastMessage} from 'morya-ui';\nimport { iconNames, MIcon, MInput, MToast } from 'morya-ui'\nimport { computed, ref } from 'vue'\n\nconst query = ref('')\nconst copied = ref<string | null>(null)\nconst messages = ref<ToastMessage[]>([])\nlet toastSeq = 0\nlet copiedTimer: ReturnType<typeof setTimeout> | undefined\n\nconst filtered = computed(() => {\n const q = query.value.trim().toLowerCase()\n if (!q) return [...iconNames]\n return iconNames.filter((name) => name.toLowerCase().includes(q))\n})\n\nfunction itemStyle(name: string) {\n const active = copied.value === name\n return [\n 'align-items:center',\n 'background:var(--m-color-surface)',\n `border:1px solid ${active ? 'var(--m-color-primary)' : 'var(--m-color-border)'}`,\n 'border-radius:var(--m-radius-control, 3px)',\n `color:${active ? 'var(--m-color-primary)' : 'var(--m-color-text)'}`,\n 'cursor:pointer',\n 'display:flex',\n 'flex-direction:column',\n 'font:inherit',\n 'gap:0.65rem',\n 'justify-content:center',\n 'min-height:6.5rem',\n 'padding:0.85rem 0.5rem',\n 'width:100%',\n ].join(';')\n}\n\nasync function copyName(name: string) {\n try {\n await navigator.clipboard.writeText(name)\n } catch {\n const area = document.createElement('textarea')\n area.value = name\n document.body.appendChild(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n }\n copied.value = name\n if (copiedTimer) clearTimeout(copiedTimer)\n copiedTimer = setTimeout(() => {\n if (copied.value === name) copied.value = null\n }, 1200)\n\n const id = `icon-copy-${++toastSeq}`\n messages.value = [\n ...messages.value,\n {\n id,\n severity: 'success',\n summary: 'Copied',\n detail: name,\n closable: true,\n },\n ]\n window.setTimeout(() => {\n messages.value = messages.value.filter((item) => item.id !== id)\n }, 1600)\n}\n\nfunction onToastClose(message: ToastMessage) {\n messages.value = messages.value.filter((item) => item.id !== message.id)\n}\n</script>\n\n<template>\n <div class=\"w-full\">\n <MInput\n v-model=\"query\"\n clearable\n fluid\n placeholder=\"Search icon names…\"\n class=\"max-w-xs mb-4\"\n >\n <template #prefix>\n <MIcon name=\"search\" size=\"sm\" />\n </template>\n </MInput>\n\n <p\n v-if=\"!filtered.length\"\n style=\"color: var(--m-color-text-muted); font-size: 0.875rem; margin: 0.5rem 0 0\"\n >\n No matching icons\n </p>\n\n <div\n v-else\n style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(7.25rem,1fr));gap:0.75rem;width:100%\"\n >\n <button\n v-for=\"name in filtered\"\n :key=\"name\"\n type=\"button\"\n :style=\"itemStyle(name)\"\n :title=\"`Click to copy ${name}`\"\n @click=\"copyName(name)\"\n >\n <MIcon :name=\"name\" size=\"large\" />\n <span\n style=\"font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.72rem;line-height:1.3;max-width:100%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap\"\n >\n {{ copied === name ? 'Copied' : name }}\n </span>\n </button>\n </div>\n\n <MToast :messages=\"messages\" position=\"top-right\" @close=\"onToastClose\" />\n </div>\n</template>",
8986
+ "code": "<script setup lang=\"ts\">\nimport type { IconCategoryId, ToastMessage } from 'morya-ui'\nimport {\n getIconCategory,\n getIconCategoryGroups,\n iconCategoryMeta,\n iconNames,\n MIcon,\n MInput,\n MToast,\n} from 'morya-ui'\nimport { computed, ref } from 'vue'\n\nconst query = ref('')\nconst category = ref<IconCategoryId | 'all'>('all')\nconst copied = ref<string | null>(null)\nconst messages = ref<ToastMessage[]>([])\nlet toastSeq = 0\nlet copiedTimer: ReturnType<typeof setTimeout> | undefined\n\nconst categoryOptions = computed(() => [\n { id: 'all' as const, label: 'All' },\n ...iconCategoryMeta.map((item) => ({ id: item.id, label: item.labelEn })),\n])\n\nconst filteredNames = computed(() => {\n const q = query.value.trim().toLowerCase()\n return iconNames.filter((name) => {\n if (q && !name.toLowerCase().includes(q)) return false\n if (category.value !== 'all') return getIconCategory(name) === category.value\n return true\n })\n})\n\nconst grouped = computed(() => getIconCategoryGroups(filteredNames.value))\n\nfunction chipStyle(id: IconCategoryId | 'all') {\n const active = category.value === id\n return [\n 'background:' + (active ? 'var(--m-color-primary-soft, color-mix(in srgb, var(--m-color-primary) 14%, transparent))' : 'var(--m-color-surface)'),\n 'border:1px solid ' + (active ? 'var(--m-color-primary)' : 'var(--m-color-border)'),\n 'border-radius:var(--m-radius-full, 999px)',\n 'color:' + (active ? 'var(--m-color-primary)' : 'var(--m-color-text)'),\n 'cursor:pointer',\n 'font:inherit',\n 'font-size:0.8125rem',\n 'line-height:1.2',\n 'padding:0.35rem 0.75rem',\n ].join(';')\n}\n\nfunction itemStyle(name: string) {\n const active = copied.value === name\n return [\n 'align-items:center',\n 'background:var(--m-color-surface)',\n `border:1px solid ${active ? 'var(--m-color-primary)' : 'var(--m-color-border)'}`,\n 'border-radius:var(--m-radius-control, 3px)',\n `color:${active ? 'var(--m-color-primary)' : 'var(--m-color-text)'}`,\n 'cursor:pointer',\n 'display:flex',\n 'flex-direction:column',\n 'font:inherit',\n 'gap:0.65rem',\n 'justify-content:center',\n 'min-height:6.5rem',\n 'padding:0.85rem 0.5rem',\n 'width:100%',\n ].join(';')\n}\n\nasync function copyName(name: string) {\n try {\n await navigator.clipboard.writeText(name)\n } catch {\n const area = document.createElement('textarea')\n area.value = name\n document.body.appendChild(area)\n area.select()\n document.execCommand('copy')\n area.remove()\n }\n copied.value = name\n if (copiedTimer) clearTimeout(copiedTimer)\n copiedTimer = setTimeout(() => {\n if (copied.value === name) copied.value = null\n }, 1200)\n\n const id = `icon-copy-${++toastSeq}`\n messages.value = [\n ...messages.value,\n {\n id,\n severity: 'success',\n summary: 'Copied',\n detail: name,\n closable: true,\n },\n ]\n window.setTimeout(() => {\n messages.value = messages.value.filter((item) => item.id !== id)\n }, 1600)\n}\n\nfunction onToastClose(message: ToastMessage) {\n messages.value = messages.value.filter((item) => item.id !== message.id)\n}\n</script>\n\n<template>\n <div class=\"w-full\">\n <MInput\n v-model=\"query\"\n clearable\n fluid\n placeholder=\"Search icon names…\"\n class=\"max-w-xs mb-3\"\n >\n <template #prefix>\n <MIcon name=\"search\" size=\"sm\" />\n </template>\n </MInput>\n\n <div style=\"display:flex;flex-wrap:wrap;gap:0.5rem;margin-bottom:1rem\">\n <button\n v-for=\"opt in categoryOptions\"\n :key=\"opt.id\"\n type=\"button\"\n :style=\"chipStyle(opt.id)\"\n @click=\"category = opt.id\"\n >\n {{ opt.label }}\n </button>\n </div>\n\n <p\n v-if=\"!grouped.length\"\n style=\"color: var(--m-color-text-muted); font-size: 0.875rem; margin: 0.5rem 0 0\"\n >\n No matching icons\n </p>\n\n <div v-else style=\"display:grid;gap:1.25rem;width:100%\">\n <section v-for=\"group in grouped\" :key=\"group.id\">\n <h4\n style=\"align-items:baseline;color:var(--m-color-text);display:flex;font-size:0.875rem;font-weight:600;gap:0.5rem;margin:0 0 0.65rem\"\n >\n <span>{{ group.labelEn }}</span>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem;font-weight:500\">\n {{ group.icons.length }}\n </span>\n </h4>\n <div\n style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(7.25rem,1fr));gap:0.75rem;width:100%\"\n >\n <button\n v-for=\"name in group.icons\"\n :key=\"name\"\n type=\"button\"\n :style=\"itemStyle(name)\"\n :title=\"`Click to copy ${name}`\"\n @click=\"copyName(name)\"\n >\n <MIcon :name=\"name\" size=\"large\" />\n <span\n style=\"font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.72rem;line-height:1.3;max-width:100%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap\"\n >\n {{ copied === name ? 'Copied' : name }}\n </span>\n </button>\n </div>\n </section>\n </div>\n\n <MToast :messages=\"messages\" position=\"top-right\" @close=\"onToastClose\" />\n </div>\n</template>",
8987
8987
  "locale": "en-US"
8988
8988
  },
8989
8989
  {
@@ -9004,7 +9004,7 @@
9004
9004
  {
9005
9005
  "id": "overview",
9006
9006
  "title": "",
9007
- "body": "# Icon\n\n`MIcon` 只维护**组件库系统图标**(关闭、箭头、状态、操作等)。完整业务图标请用默认插槽接入 [Lucide](https://lucide.dev) 等库,避免把数百个 SVG 打进 `morya-ui`。"
9007
+ "body": "# Icon\n\n`MIcon` 维护**组件库系统图标**(关闭、箭头、状态、导航、业务常用等,含 Tabler outline)。完整海量图标请用默认插槽接入 [Lucide](https://lucide.dev) 等库。"
9008
9008
  },
9009
9009
  {
9010
9010
  "id": "引入",
@@ -9019,7 +9019,7 @@
9019
9019
  {
9020
9020
  "id": "全部系统图标",
9021
9021
  "title": "全部系统图标",
9022
- "body": "点击图标即可复制名称(如 `search`),用法:`<MIcon name=\"search\" />`。\n\n```vue preview src=\"./demos/AllSystemIcons.zh.vue\"\n```"
9022
+ "body": "点击图标即可复制名称(如 `search`),用法:`<MIcon name=\"search\" />`。可按分类筛选,或搜索名称。\n\n```vue preview src=\"./demos/AllSystemIcons.zh.vue\"\n```"
9023
9023
  },
9024
9024
  {
9025
9025
  "id": "自定义-lucide-推荐业务侧",
@@ -9039,7 +9039,7 @@
9039
9039
  {
9040
9040
  "id": "工具导出",
9041
9041
  "title": "工具导出",
9042
- "body": "| 导出 | 说明 |\n| --- | --- |\n| `iconNames` | 全部系统图标名数组。 |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | 注册表与类型守卫。 |"
9042
+ "body": "| 导出 | 说明 |\n| --- | --- |\n| `iconNames` | 全部系统图标名数组。 |\n| `iconCategoryMeta` / `getIconCategory` / `getIconCategoryGroups` | 图标分类元数据与分组。 |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | 注册表与类型守卫。 |"
9043
9043
  },
9044
9044
  {
9045
9045
  "id": "events",
@@ -9047,7 +9047,7 @@
9047
9047
  "body": "无自定义事件。"
9048
9048
  }
9049
9049
  ],
9050
- "markdown": "---\ntitle: Icon\ncategory: 01 / BASIC\ndescription: 系统线框图标注册表。业务图标用默认插槽接入 Lucide 等库。\n---\n\n# Icon\n\n`MIcon` 只维护**组件库系统图标**(关闭、箭头、状态、操作等)。完整业务图标请用默认插槽接入 [Lucide](https://lucide.dev) 等库,避免把数百个 SVG 打进 `morya-ui`。\n\n## 引入\n\n```ts\nimport { iconNames, MIcon } from 'morya-ui'\n```\n\n## 基础用法\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## 全部系统图标\n\n点击图标即可复制名称(如 `search`),用法:`<MIcon name=\"search\" />`。\n\n```vue preview src=\"./demos/AllSystemIcons.zh.vue\"\n```\n\n## 自定义 / Lucide(推荐业务侧)\n\n系统图标不够时,不要往组件库堆 SVG,用默认插槽挂任意图标组件:\n\n```vue\n<script setup lang=\"ts\">\nimport { User } from 'lucide-vue-next'\nimport { MButton, MIcon, MIconField, MInput } from 'morya-ui'\n</script>\n\n<template>\n <MIcon label=\"用户\" size=\"md\">\n <User :size=\"16\" :stroke-width=\"1.8\" />\n </MIcon>\n\n <MIconField>\n <template #icon>\n <MIcon size=\"sm\">\n <User :size=\"14\" :stroke-width=\"1.8\" />\n </MIcon>\n </template>\n <MInput placeholder=\"搜索用户\" />\n </MIconField>\n\n <!-- Button 也可直接传组件,不必包 MIcon -->\n <MButton :icon=\"User\" label=\"资料\" />\n</template>\n```\n\n安装示例:`pnpm add lucide-vue-next`。线宽建议 `1.75`–`2`,与系统图标 `1.8` 接近。\n\n有默认插槽时**优先渲染插槽**,忽略 `name`。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `name` | [IconName](/docs/types#IconName) | — | 系统图标名;插槽存在时可省略。 |\n| `label` | `string` | — | 可访问名称;省略时 `aria-hidden`。 |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | 尺寸;`sm`/`lg` 映射到 small/large。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Slots\n\n| 插槽 | 说明 |\n| --- | --- |\n| `default` | 自定义 SVG / 第三方图标组件。 |\n\n## 工具导出\n\n| 导出 | 说明 |\n| --- | --- |\n| `iconNames` | 全部系统图标名数组。 |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | 注册表与类型守卫。 |\n\n## Events\n\n无自定义事件。\n"
9050
+ "markdown": "---\ntitle: Icon\ncategory: 01 / BASIC\ndescription: 系统线框图标注册表。业务图标用默认插槽接入 Lucide 等库。\n---\n\n# Icon\n\n`MIcon` 维护**组件库系统图标**(关闭、箭头、状态、导航、业务常用等,含 Tabler outline)。完整海量图标请用默认插槽接入 [Lucide](https://lucide.dev) 等库。\n\n## 引入\n\n```ts\nimport { iconNames, MIcon } from 'morya-ui'\n```\n\n## 基础用法\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## 全部系统图标\n\n点击图标即可复制名称(如 `search`),用法:`<MIcon name=\"search\" />`。可按分类筛选,或搜索名称。\n\n```vue preview src=\"./demos/AllSystemIcons.zh.vue\"\n```\n\n## 自定义 / Lucide(推荐业务侧)\n\n系统图标不够时,不要往组件库堆 SVG,用默认插槽挂任意图标组件:\n\n```vue\n<script setup lang=\"ts\">\nimport { User } from 'lucide-vue-next'\nimport { MButton, MIcon, MIconField, MInput } from 'morya-ui'\n</script>\n\n<template>\n <MIcon label=\"用户\" size=\"md\">\n <User :size=\"16\" :stroke-width=\"1.8\" />\n </MIcon>\n\n <MIconField>\n <template #icon>\n <MIcon size=\"sm\">\n <User :size=\"14\" :stroke-width=\"1.8\" />\n </MIcon>\n </template>\n <MInput placeholder=\"搜索用户\" />\n </MIconField>\n\n <!-- Button 也可直接传组件,不必包 MIcon -->\n <MButton :icon=\"User\" label=\"资料\" />\n</template>\n```\n\n安装示例:`pnpm add lucide-vue-next`。线宽建议 `1.75`–`2`,与系统图标 `1.8` 接近。\n\n有默认插槽时**优先渲染插槽**,忽略 `name`。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `name` | [IconName](/docs/types#IconName) | — | 系统图标名;插槽存在时可省略。 |\n| `label` | `string` | — | 可访问名称;省略时 `aria-hidden`。 |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | 尺寸;`sm`/`lg` 映射到 small/large。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Slots\n\n| 插槽 | 说明 |\n| --- | --- |\n| `default` | 自定义 SVG / 第三方图标组件。 |\n\n## 工具导出\n\n| 导出 | 说明 |\n| --- | --- |\n| `iconNames` | 全部系统图标名数组。 |\n| `iconCategoryMeta` / `getIconCategory` / `getIconCategoryGroups` | 图标分类元数据与分组。 |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | 注册表与类型守卫。 |\n\n## Events\n\n无自定义事件。\n"
9051
9051
  },
9052
9052
  "en-US": {
9053
9053
  "title": "Icon",
@@ -9056,7 +9056,7 @@
9056
9056
  {
9057
9057
  "id": "overview",
9058
9058
  "title": "",
9059
- "body": "# Icon\n\n`MIcon` only maintains **component-library system icons** (close, arrows, status, actions, and so on). For full business icon sets, use the default slot with [Lucide](https://lucide.dev) or another library so hundreds of SVGs are not bundled into `morya-ui`."
9059
+ "body": "# Icon\n\n`MIcon` maintains **component-library system icons** (close, arrows, status, navigation, common business icons from Tabler outline). For large business icon sets, use the default slot with [Lucide](https://lucide.dev) or another library."
9060
9060
  },
9061
9061
  {
9062
9062
  "id": "import",
@@ -9071,7 +9071,7 @@
9071
9071
  {
9072
9072
  "id": "all-system-icons",
9073
9073
  "title": "All system icons",
9074
- "body": "Click an icon to copy its name (for example `search`). Usage: `<MIcon name=\"search\" />`.\n\n```vue preview src=\"./demos/AllSystemIcons.en.vue\"\n```"
9074
+ "body": "Click an icon to copy its name (for example `search`). Usage: `<MIcon name=\"search\" />`. Filter by category or search by name.\n\n```vue preview src=\"./demos/AllSystemIcons.en.vue\"\n```"
9075
9075
  },
9076
9076
  {
9077
9077
  "id": "custom-lucide-recommended-on-the-app-side",
@@ -9091,7 +9091,7 @@
9091
9091
  {
9092
9092
  "id": "utility-exports",
9093
9093
  "title": "Utility exports",
9094
- "body": "| Export | Description |\n| --- | --- |\n| `iconNames` | Array of all system icon names. |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | Registry and type guards. |"
9094
+ "body": "| Export | Description |\n| --- | --- |\n| `iconNames` | Array of all system icon names. |\n| `iconCategoryMeta` / `getIconCategory` / `getIconCategoryGroups` | Category metadata and grouping helpers. |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | Registry and type guards. |"
9095
9095
  },
9096
9096
  {
9097
9097
  "id": "events",
@@ -9099,7 +9099,7 @@
9099
9099
  "body": "No custom events."
9100
9100
  }
9101
9101
  ],
9102
- "markdown": "---\ntitle: Icon\ncategory: 01 / BASIC\ndescription: System outline icon registry. Use the default slot for business icons from Lucide and similar libraries.\n---\n\n# Icon\n\n`MIcon` only maintains **component-library system icons** (close, arrows, status, actions, and so on). For full business icon sets, use the default slot with [Lucide](https://lucide.dev) or another library so hundreds of SVGs are not bundled into `morya-ui`.\n\n## Import\n\n```ts\nimport { iconNames, MIcon } from 'morya-ui'\n```\n\n## Basic\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## All system icons\n\nClick an icon to copy its name (for example `search`). Usage: `<MIcon name=\"search\" />`.\n\n```vue preview src=\"./demos/AllSystemIcons.en.vue\"\n```\n\n## Custom / Lucide (recommended on the app side)\n\nWhen system icons are not enough, do not pile SVGs into the component library. Mount any icon component through the default slot:\n\n```vue\n<script setup lang=\"ts\">\nimport { User } from 'lucide-vue-next'\nimport { MButton, MIcon, MIconField, MInput } from 'morya-ui'\n</script>\n\n<template>\n <MIcon label=\"User\" size=\"md\">\n <User :size=\"16\" :stroke-width=\"1.8\" />\n </MIcon>\n\n <MIconField>\n <template #icon>\n <MIcon size=\"sm\">\n <User :size=\"14\" :stroke-width=\"1.8\" />\n </MIcon>\n </template>\n <MInput placeholder=\"Search users\" />\n </MIconField>\n\n <!-- Button can also take a component directly without wrapping MIcon -->\n <MButton :icon=\"User\" label=\"Profile\" />\n</template>\n```\n\nInstall example: `pnpm add lucide-vue-next`. Prefer stroke width `1.75`–`2`, close to the system icon width of `1.8`.\n\nWhen the default slot is present, it is **rendered first** and `name` is ignored.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `name` | [IconName](/docs/types#IconName) | — | System icon name; optional when a slot is provided. |\n| `label` | `string` | — | Accessible name; omitted icons use `aria-hidden`. |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | Size; `sm`/`lg` map to small/large. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Custom SVG / third-party icon component. |\n\n## Utility exports\n\n| Export | Description |\n| --- | --- |\n| `iconNames` | Array of all system icon names. |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | Registry and type guards. |\n\n## Events\n\nNo custom events.\n"
9102
+ "markdown": "---\ntitle: Icon\ncategory: 01 / BASIC\ndescription: System outline icon registry. Use the default slot for business icons from Lucide and similar libraries.\n---\n\n# Icon\n\n`MIcon` maintains **component-library system icons** (close, arrows, status, navigation, common business icons from Tabler outline). For large business icon sets, use the default slot with [Lucide](https://lucide.dev) or another library.\n\n## Import\n\n```ts\nimport { iconNames, MIcon } from 'morya-ui'\n```\n\n## Basic\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## All system icons\n\nClick an icon to copy its name (for example `search`). Usage: `<MIcon name=\"search\" />`. Filter by category or search by name.\n\n```vue preview src=\"./demos/AllSystemIcons.en.vue\"\n```\n\n## Custom / Lucide (recommended on the app side)\n\nWhen system icons are not enough, do not pile SVGs into the component library. Mount any icon component through the default slot:\n\n```vue\n<script setup lang=\"ts\">\nimport { User } from 'lucide-vue-next'\nimport { MButton, MIcon, MIconField, MInput } from 'morya-ui'\n</script>\n\n<template>\n <MIcon label=\"User\" size=\"md\">\n <User :size=\"16\" :stroke-width=\"1.8\" />\n </MIcon>\n\n <MIconField>\n <template #icon>\n <MIcon size=\"sm\">\n <User :size=\"14\" :stroke-width=\"1.8\" />\n </MIcon>\n </template>\n <MInput placeholder=\"Search users\" />\n </MIconField>\n\n <!-- Button can also take a component directly without wrapping MIcon -->\n <MButton :icon=\"User\" label=\"Profile\" />\n</template>\n```\n\nInstall example: `pnpm add lucide-vue-next`. Prefer stroke width `1.75`–`2`, close to the system icon width of `1.8`.\n\nWhen the default slot is present, it is **rendered first** and `name` is ignored.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `name` | [IconName](/docs/types#IconName) | — | System icon name; optional when a slot is provided. |\n| `label` | `string` | — | Accessible name; omitted icons use `aria-hidden`. |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | Size; `sm`/`lg` map to small/large. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Custom SVG / third-party icon component. |\n\n## Utility exports\n\n| Export | Description |\n| --- | --- |\n| `iconNames` | Array of all system icon names. |\n| `iconCategoryMeta` / `getIconCategory` / `getIconCategoryGroups` | Category metadata and grouping helpers. |\n| `iconRegistry` / `getIconDefinition` / `isIconName` | Registry and type guards. |\n\n## Events\n\nNo custom events.\n"
9103
9103
  }
9104
9104
  }
9105
9105
  },
@@ -11905,7 +11905,7 @@
11905
11905
  "sectionId": "基础用法",
11906
11906
  "lang": "vue",
11907
11907
  "preview": true,
11908
- "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutFooter, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Header\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem;display:flex;align-items:center;justify-content:center\">\n Content(自动撑开)\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.75rem 1rem\">\n Footer\n </MLayoutFooter>\n </MLayout>\n</template>",
11908
+ "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutFooter, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Header\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem;display:flex;align-items:center;justify-content:center\">\n Content(自动撑开)\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.75rem 1rem\">\n Footer\n </MLayoutFooter>\n </MLayout>\n</template>",
11909
11909
  "locale": "zh-CN"
11910
11910
  },
11911
11911
  {
@@ -11914,7 +11914,7 @@
11914
11914
  "sectionId": "with-sider",
11915
11915
  "lang": "vue",
11916
11916
  "preview": true,
11917
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem;display:flex;align-items:center;justify-content:space-between\">\n <strong>App</strong>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem\">{{ collapsed ? '已折叠' : '已展开' }}</span>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n :width=\"160\"\n content-style=\"padding:0.75rem\"\n >\n <div style=\"display:grid;gap:0.5rem\">\n <div>概览</div>\n <div>项目</div>\n <div>设置</div>\n </div>\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n 主内容区会横向、纵向同时撑满。\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11917
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('overview')\nconst model = [\n { key: 'overview', label: '概览', icon: 'layout-dashboard' },\n { key: 'projects', label: '项目', icon: 'folder' },\n { key: 'settings', label: '设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem;display:flex;align-items:center;justify-content:space-between\">\n <strong>App</strong>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem\">{{ collapsed ? '已折叠' : '已展开' }}</span>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :width=\"168\"\n :collapsed-width=\"64\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n />\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem\">\n 当前选中:{{ selectedKey }}\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11918
11918
  "locale": "zh-CN"
11919
11919
  },
11920
11920
  {
@@ -11923,7 +11923,7 @@
11923
11923
  "sectionId": "right-sider",
11924
11924
  "lang": "vue",
11925
11925
  "preview": true,
11926
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Inspector\n </MLayoutHeader>\n <MLayout has-sider sider-placement=\"right\">\n <MLayoutSider bordered :width=\"140\" content-style=\"padding:0.75rem\">\n 属性面板\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n 画布 / 主区域\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11926
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Inspector\n </MLayoutHeader>\n <MLayout has-sider sider-placement=\"right\">\n <MLayoutSider bordered :width=\"140\" style=\"padding:0.75rem\">\n 属性面板\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem\">\n 画布 / 主区域\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11927
11927
  "locale": "zh-CN"
11928
11928
  },
11929
11929
  {
@@ -11932,7 +11932,7 @@
11932
11932
  "sectionId": "full-shell",
11933
11933
  "lang": "vue",
11934
11934
  "preview": true,
11935
- "code": "<script setup lang=\"ts\">\nimport {\n MButton,\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n MTag,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\n</script>\n\n<template>\n <MLayout style=\"height:18rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader\n bordered\n inverted\n style=\"padding:0.65rem 1rem;display:flex;align-items:center;gap:0.75rem\"\n >\n <strong>Morya UI</strong>\n <MTag value=\"Studio\" />\n <span style=\"flex:1\" />\n <MButton size=\"small\" label=\"发布\" />\n </MLayoutHeader>\n\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n inverted\n show-trigger=\"bar\"\n :width=\"168\"\n :collapsed-width=\"56\"\n content-style=\"padding:0.75rem\"\n >\n <div style=\"display:grid;gap:0.65rem;font-size:0.875rem\">\n <div>仪表盘</div>\n <div>数据源</div>\n <div>组件</div>\n <div>主题</div>\n </div>\n </MLayoutSider>\n\n <MLayout>\n <MLayoutContent embedded content-style=\"padding:1rem;display:grid;gap:0.75rem;align-content:start\">\n <strong>工作区</strong>\n <p style=\"margin:0;color:var(--m-color-text-muted);font-size:0.875rem\">\n Content 已撑满 Header 与 Footer 之间的空间;侧栏折叠不影响主区高度。\n </p>\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.5rem 1rem;color:var(--m-color-text-muted);font-size:0.75rem\">\n Ready · local\n </MLayoutFooter>\n </MLayout>\n </MLayout>\n </MLayout>\n</template>",
11935
+ "code": "<script setup lang=\"ts\">\nimport {\n MButton,\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n MTag,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: '仪表盘', icon: 'layout-dashboard' },\n { key: 'datasources', label: '数据源', icon: 'database' },\n { key: 'widgets', label: '组件', icon: 'components' },\n { key: 'theme', label: '主题', icon: 'palette' },\n]\n</script>\n\n<template>\n <MLayout style=\"height:18rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader\n bordered\n inverted\n style=\"padding:0.65rem 1rem;display:flex;align-items:center;gap:0.75rem\"\n >\n <strong>Morya UI</strong>\n <MTag value=\"Studio\" />\n <span style=\"flex:1\" />\n <MButton size=\"small\" label=\"发布\" />\n </MLayoutHeader>\n\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n inverted\n show-trigger=\"bar\"\n collapse-mode=\"width\"\n :width=\"168\"\n :collapsed-width=\"56\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"56\"\n inverted\n />\n </MLayoutSider>\n\n <MLayout>\n <MLayoutContent embedded style=\"padding:1rem;display:grid;gap:0.75rem;align-content:start\">\n <strong>工作区</strong>\n <p style=\"margin:0;color:var(--m-color-text-muted);font-size:0.875rem\">\n 当前选中:{{ selectedKey }}。Content 已撑满 Header 与 Footer 之间的空间;侧栏折叠不影响主区高度。\n </p>\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.5rem 1rem;color:var(--m-color-text-muted);font-size:0.75rem\">\n Ready · local\n </MLayoutFooter>\n </MLayout>\n </MLayout>\n </MLayout>\n</template>",
11936
11936
  "locale": "zh-CN"
11937
11937
  },
11938
11938
  {
@@ -11941,7 +11941,7 @@
11941
11941
  "sectionId": "embedded-content",
11942
11942
  "lang": "vue",
11943
11943
  "preview": true,
11944
- "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:12rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Settings\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n 嵌套表单 / 列表放在这里。\n </MLayoutContent>\n </MLayout>\n</template>",
11944
+ "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:12rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Settings\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem\">\n 嵌套表单 / 列表放在这里。\n </MLayoutContent>\n </MLayout>\n</template>",
11945
11945
  "locale": "zh-CN"
11946
11946
  },
11947
11947
  {
@@ -11950,7 +11950,7 @@
11950
11950
  "sectionId": "scrollable-content",
11951
11951
  "lang": "vue",
11952
11952
  "preview": true,
11953
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Scroll demo\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider bordered :width=\"120\" content-style=\"padding:0.75rem\">\n 固定侧栏\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n <div style=\"display:grid;gap:0.5rem\">\n <div v-for=\"n in 20\" :key=\"n\">\n 行 {{ n }} — 向下滚动\n </div>\n </div>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11953
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Scroll demo\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider bordered :width=\"120\" style=\"padding:0.75rem\">\n 固定侧栏\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem;overflow:auto;min-height:0\">\n <div style=\"display:grid;gap:0.5rem\">\n <div v-for=\"n in 20\" :key=\"n\">\n 行 {{ n }} — 向下滚动\n </div>\n </div>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11954
11954
  "locale": "zh-CN"
11955
11955
  },
11956
11956
  {
@@ -11959,7 +11959,7 @@
11959
11959
  "sectionId": "absolute-shell",
11960
11960
  "lang": "vue",
11961
11961
  "preview": true,
11962
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <div style=\"position:relative;height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayout position=\"absolute\" has-sider>\n <MLayoutSider bordered :width=\"120\" content-style=\"padding:0.75rem\">\n Nav\n </MLayoutSider>\n <MLayout>\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Absolute layout\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n 填满相对定位容器\n </MLayoutContent>\n </MLayout>\n </MLayout>\n </div>\n</template>",
11962
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <div style=\"position:relative;height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayout position=\"absolute\" has-sider>\n <MLayoutSider bordered :width=\"120\" style=\"padding:0.75rem\">\n Nav\n </MLayoutSider>\n <MLayout>\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Absolute layout\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem\">\n 填满相对定位容器\n </MLayoutContent>\n </MLayout>\n </MLayout>\n </div>\n</template>",
11963
11963
  "locale": "zh-CN"
11964
11964
  },
11965
11965
  {
@@ -11977,7 +11977,7 @@
11977
11977
  "sectionId": "basic",
11978
11978
  "lang": "vue",
11979
11979
  "preview": true,
11980
- "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutFooter, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Header\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem;display:flex;align-items:center;justify-content:center\">\n Content (fills remaining space)\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.75rem 1rem\">\n Footer\n </MLayoutFooter>\n </MLayout>\n</template>",
11980
+ "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutFooter, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Header\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem;display:flex;align-items:center;justify-content:center\">\n Content (fills remaining space)\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.75rem 1rem\">\n Footer\n </MLayoutFooter>\n </MLayout>\n</template>",
11981
11981
  "locale": "en-US"
11982
11982
  },
11983
11983
  {
@@ -11986,7 +11986,7 @@
11986
11986
  "sectionId": "with-sider",
11987
11987
  "lang": "vue",
11988
11988
  "preview": true,
11989
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem;display:flex;align-items:center;justify-content:space-between\">\n <strong>App</strong>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem\">{{ collapsed ? 'Collapsed' : 'Expanded' }}</span>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n :width=\"160\"\n content-style=\"padding:0.75rem\"\n >\n <div style=\"display:grid;gap:0.5rem\">\n <div>Overview</div>\n <div>Projects</div>\n <div>Settings</div>\n </div>\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n Main area stretches both horizontally and vertically.\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11989
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('overview')\nconst model = [\n { key: 'overview', label: 'Overview', icon: 'layout-dashboard' },\n { key: 'projects', label: 'Projects', icon: 'folder' },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <MLayout style=\"height:16rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem;display:flex;align-items:center;justify-content:space-between\">\n <strong>App</strong>\n <span style=\"color:var(--m-color-text-muted);font-size:0.75rem\">{{ collapsed ? 'Collapsed' : 'Expanded' }}</span>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :width=\"168\"\n :collapsed-width=\"64\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n />\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem\">\n Selected: {{ selectedKey }}\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11990
11990
  "locale": "en-US"
11991
11991
  },
11992
11992
  {
@@ -11995,7 +11995,7 @@
11995
11995
  "sectionId": "right-sider",
11996
11996
  "lang": "vue",
11997
11997
  "preview": true,
11998
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Inspector\n </MLayoutHeader>\n <MLayout has-sider sider-placement=\"right\">\n <MLayoutSider bordered :width=\"140\" content-style=\"padding:0.75rem\">\n Props panel\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n Canvas / main\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11998
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Inspector\n </MLayoutHeader>\n <MLayout has-sider sider-placement=\"right\">\n <MLayoutSider bordered :width=\"140\" style=\"padding:0.75rem\">\n Props panel\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem\">\n Canvas / main\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
11999
11999
  "locale": "en-US"
12000
12000
  },
12001
12001
  {
@@ -12004,7 +12004,7 @@
12004
12004
  "sectionId": "full-shell",
12005
12005
  "lang": "vue",
12006
12006
  "preview": true,
12007
- "code": "<script setup lang=\"ts\">\nimport {\n MButton,\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n MTag,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\n</script>\n\n<template>\n <MLayout style=\"height:18rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader\n bordered\n inverted\n style=\"padding:0.65rem 1rem;display:flex;align-items:center;gap:0.75rem\"\n >\n <strong>Morya UI</strong>\n <MTag value=\"Studio\" />\n <span style=\"flex:1\" />\n <MButton size=\"small\" label=\"Publish\" />\n </MLayoutHeader>\n\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n inverted\n show-trigger=\"bar\"\n :width=\"168\"\n :collapsed-width=\"56\"\n content-style=\"padding:0.75rem\"\n >\n <div style=\"display:grid;gap:0.65rem;font-size:0.875rem\">\n <div>Dashboard</div>\n <div>Datasources</div>\n <div>Widgets</div>\n <div>Theme</div>\n </div>\n </MLayoutSider>\n\n <MLayout>\n <MLayoutContent embedded content-style=\"padding:1rem;display:grid;gap:0.75rem;align-content:start\">\n <strong>Workspace</strong>\n <p style=\"margin:0;color:var(--m-color-text-muted);font-size:0.875rem\">\n Content fills the space between Header and Footer; collapsing the sider keeps the height.\n </p>\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.5rem 1rem;color:var(--m-color-text-muted);font-size:0.75rem\">\n Ready · local\n </MLayoutFooter>\n </MLayout>\n </MLayout>\n </MLayout>\n</template>",
12007
+ "code": "<script setup lang=\"ts\">\nimport {\n MButton,\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n MTag,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n { key: 'datasources', label: 'Datasources', icon: 'database' },\n { key: 'widgets', label: 'Widgets', icon: 'components' },\n { key: 'theme', label: 'Theme', icon: 'palette' },\n]\n</script>\n\n<template>\n <MLayout style=\"height:18rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader\n bordered\n inverted\n style=\"padding:0.65rem 1rem;display:flex;align-items:center;gap:0.75rem\"\n >\n <strong>Morya UI</strong>\n <MTag value=\"Studio\" />\n <span style=\"flex:1\" />\n <MButton size=\"small\" label=\"Publish\" />\n </MLayoutHeader>\n\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n inverted\n show-trigger=\"bar\"\n collapse-mode=\"width\"\n :width=\"168\"\n :collapsed-width=\"56\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"56\"\n inverted\n />\n </MLayoutSider>\n\n <MLayout>\n <MLayoutContent embedded style=\"padding:1rem;display:grid;gap:0.75rem;align-content:start\">\n <strong>Workspace</strong>\n <p style=\"margin:0;color:var(--m-color-text-muted);font-size:0.875rem\">\n Selected: {{ selectedKey }}. Content fills the space between Header and Footer; collapsing the sider keeps the height.\n </p>\n </MLayoutContent>\n <MLayoutFooter bordered style=\"padding:0.5rem 1rem;color:var(--m-color-text-muted);font-size:0.75rem\">\n Ready · local\n </MLayoutFooter>\n </MLayout>\n </MLayout>\n </MLayout>\n</template>",
12008
12008
  "locale": "en-US"
12009
12009
  },
12010
12010
  {
@@ -12013,7 +12013,7 @@
12013
12013
  "sectionId": "embedded-content",
12014
12014
  "lang": "vue",
12015
12015
  "preview": true,
12016
- "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:12rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Settings\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n Nested forms / lists go here.\n </MLayoutContent>\n </MLayout>\n</template>",
12016
+ "code": "<script setup lang=\"ts\">\nimport { MLayout, MLayoutContent, MLayoutHeader } from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:12rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Settings\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem\">\n Nested forms / lists go here.\n </MLayoutContent>\n </MLayout>\n</template>",
12017
12017
  "locale": "en-US"
12018
12018
  },
12019
12019
  {
@@ -12022,7 +12022,7 @@
12022
12022
  "sectionId": "scrollable-content",
12023
12023
  "lang": "vue",
12024
12024
  "preview": true,
12025
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Scroll demo\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider bordered :width=\"120\" content-style=\"padding:0.75rem\">\n Fixed sider\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n <div style=\"display:grid;gap:0.5rem\">\n <div v-for=\"n in 20\" :key=\"n\">\n Row {{ n }} — scroll down\n </div>\n </div>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
12025
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <MLayout style=\"height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Scroll demo\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider bordered :width=\"120\" style=\"padding:0.75rem\">\n Fixed sider\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding:1rem;overflow:auto;min-height:0\">\n <div style=\"display:grid;gap:0.5rem\">\n <div v-for=\"n in 20\" :key=\"n\">\n Row {{ n }} — scroll down\n </div>\n </div>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
12026
12026
  "locale": "en-US"
12027
12027
  },
12028
12028
  {
@@ -12031,7 +12031,7 @@
12031
12031
  "sectionId": "absolute-shell",
12032
12032
  "lang": "vue",
12033
12033
  "preview": true,
12034
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <div style=\"position:relative;height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayout position=\"absolute\" has-sider>\n <MLayoutSider bordered :width=\"120\" content-style=\"padding:0.75rem\">\n Nav\n </MLayoutSider>\n <MLayout>\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Absolute layout\n </MLayoutHeader>\n <MLayoutContent embedded content-style=\"padding:1rem\">\n Fills the relative container\n </MLayoutContent>\n </MLayout>\n </MLayout>\n </div>\n</template>",
12034
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n</script>\n\n<template>\n <div style=\"position:relative;height:14rem;border:1px solid var(--m-color-border);border-radius:var(--m-radius-md);overflow:hidden\">\n <MLayout position=\"absolute\" has-sider>\n <MLayoutSider bordered :width=\"120\" style=\"padding:0.75rem\">\n Nav\n </MLayoutSider>\n <MLayout>\n <MLayoutHeader bordered style=\"padding:0.75rem 1rem\">\n Absolute layout\n </MLayoutHeader>\n <MLayoutContent embedded style=\"padding:1rem\">\n Fills the relative container\n </MLayoutContent>\n </MLayout>\n </MLayout>\n </div>\n</template>",
12035
12035
  "locale": "en-US"
12036
12036
  }
12037
12037
  ],
@@ -12058,7 +12058,7 @@
12058
12058
  {
12059
12059
  "id": "with-sider",
12060
12060
  "title": "With Sider",
12061
- "body": "顶栏 + 左侧栏 + 主内容。内层 `has-sider` 的 Layout 会吃掉 Header 以下的全部高度。\n\n```vue preview src=\"./demos/WithSider.zh.vue\"\n```"
12061
+ "body": "顶栏 + 左侧栏 + 主内容。侧栏内嵌 `MMenu`,并通过 `v-model:collapsed` 与菜单折叠联动。内层 `has-sider` 的 Layout 会吃掉 Header 以下的全部高度。\n\n```vue preview src=\"./demos/WithSider.zh.vue\"\n```"
12062
12062
  },
12063
12063
  {
12064
12064
  "id": "right-sider",
@@ -12068,7 +12068,7 @@
12068
12068
  {
12069
12069
  "id": "full-shell",
12070
12070
  "title": "Full Shell",
12071
- "body": "完整后台骨架:顶栏 + 侧栏 + 内容 + 底栏。\n\n```vue preview src=\"./demos/FullShell.zh.vue\"\n```"
12071
+ "body": "完整后台骨架:顶栏 + 反色侧栏(`MMenu` `inverted`)+ 内容 + 底栏。\n\n```vue preview src=\"./demos/FullShell.zh.vue\"\n```"
12072
12072
  },
12073
12073
  {
12074
12074
  "id": "embedded-content",
@@ -12078,7 +12078,7 @@
12078
12078
  {
12079
12079
  "id": "scrollable-content",
12080
12080
  "title": "Scrollable Content",
12081
- "body": "内容超出时仅 Content 区域滚动,Header / Sider 保持固定。`MLayout` / `MLayoutContent` / `MLayoutSider` 通过内置 `MScrollbar` 提供统一滚动条。\n\n```vue preview src=\"./demos/ScrollableContent.zh.vue\"\n```"
12081
+ "body": "内容超出时,可在 `MLayoutContent` 上自行设置 `overflow: auto`(或包一层 `MScrollbar`);Header / Sider 保持固定。`MLayout` 根容器仍内置 `MScrollbar`;`MLayoutContent` / `MLayoutSider` 为单层壳。\n\n```vue preview src=\"./demos/ScrollableContent.zh.vue\"\n```"
12082
12082
  },
12083
12083
  {
12084
12084
  "id": "absolute-shell",
@@ -12093,17 +12093,17 @@
12093
12093
  {
12094
12094
  "id": "layoutsider-props",
12095
12095
  "title": "LayoutSider Props",
12096
- "body": "| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | 展开宽度(始终写在 `width` 上)。 |\n| `collapsedWidth` | `number` | `48` | 折叠时的 `max-width`。 |\n| `collapsed` | `boolean` | — | 折叠状态,支持 `v-model:collapsed`。 |\n| `defaultCollapsed` | `boolean` | `false` | 非受控初始折叠。 |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | 折叠触发器;`arrow` 等同 `arrow-circle`。 |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` 裁切内容;`width` 随侧栏收缩。 |\n| `showCollapsedContent` | `boolean` | `true` | 折叠后是否仍显示侧栏内容。 |\n| `bordered` / `inverted` | `boolean` | `false` | 边框 / 反色。 |\n| `triggerClass` / `triggerStyle` | — | — | 展开态触发器样式。 |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | 折叠态触发器样式。 |\n| `contentClass` / `contentStyle` | — | | 滚动容器 class / style。 |"
12096
+ "body": "| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | 展开宽度(始终写在 `width` 上)。 |\n| `collapsedWidth` | `number` | `48` | 折叠时的 `max-width`。 |\n| `collapsed` | `boolean` | — | 折叠状态,支持 `v-model:collapsed`。 |\n| `defaultCollapsed` | `boolean` | `false` | 非受控初始折叠。 |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | 折叠触发器;`arrow` 等同 `arrow-circle`。 |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` 裁切内容;`width` 随侧栏收缩。 |\n| `showCollapsedContent` | `boolean` | `true` | 折叠后是否仍显示侧栏内容。 |\n| `bordered` / `inverted` | `boolean` | `false` | 边框 / 反色。 |\n| `triggerClass` / `triggerStyle` | — | — | 展开态触发器样式。 |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | 折叠态触发器样式。 |\n| `padding` | `number \\| string` | — | 可选内边距;无默认值。 |\n| `radius` | `number \\| string` | — | 圆角。 |"
12097
12097
  },
12098
12098
  {
12099
12099
  "id": "events",
12100
12100
  "title": "Events",
12101
- "body": "| 事件 | 说明 |\n| --- | --- |\n| `scroll` | 滚动容器滚动时触发。 |\n| `after-enter` | 侧栏展开动画结束。 |\n| `after-leave` | 侧栏收起动画结束。 |\n| `collapse` | 侧栏开始收起。 |\n| `expand` | 侧栏开始展开。 |\n| `update:collapsed` | 折叠状态 v-model。 |"
12101
+ "body": "| 事件 | 说明 |\n| --- | --- |\n| `scroll` | `MLayout` 滚动容器滚动时触发。 |\n| `after-enter` | 侧栏展开动画结束。 |\n| `after-leave` | 侧栏收起动画结束。 |\n| `collapse` | 侧栏开始收起。 |\n| `expand` | 侧栏开始展开。 |\n| `update:collapsed` | 折叠状态 v-model。 |"
12102
12102
  },
12103
12103
  {
12104
12104
  "id": "expose",
12105
12105
  "title": "Expose",
12106
- "body": "`MLayout` / `MLayoutContent` / `MLayoutSider` 均暴露 `scrollTo(...)`。"
12106
+ "body": "`MLayout` 暴露 `scrollTo(...)`。"
12107
12107
  },
12108
12108
  {
12109
12109
  "id": "components",
@@ -12116,7 +12116,7 @@
12116
12116
  "body": "| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 布局区域。 |"
12117
12117
  }
12118
12118
  ],
12119
- "markdown": "---\ntitle: Layout\ncategory: 06 / LAYOUT\ndescription: 页面级布局骨架,含 Header / Sider / Content / Footer。\n---\n\n# Layout\n\n页面级布局容器。侧栏场景需在对应 `MLayout` 上设置 `has-sider`。根布局使用 `fill-viewport`(`height: 100dvh`)或显式 `height` 后,`MLayoutContent` / `MLayoutSider` 会撑满剩余空间。\n\n## 引入\n\n```ts\nimport {\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n```\n\n## 基础用法\n\nHeader / Content / Footer。Content 会占满中间剩余高度。\n\n```vue preview src=\"./demos/Basic.zh.vue\"\n```\n\n## With Sider\n\n顶栏 + 左侧栏 + 主内容。内层 `has-sider` 的 Layout 会吃掉 Header 以下的全部高度。\n\n```vue preview src=\"./demos/WithSider.zh.vue\"\n```\n\n## Right Sider\n\n```vue preview src=\"./demos/RightSider.zh.vue\"\n```\n\n## Full Shell\n\n完整后台骨架:顶栏 + 侧栏 + 内容 + 底栏。\n\n```vue preview src=\"./demos/FullShell.zh.vue\"\n```\n\n## Embedded Content\n\n`embedded` 给内容区柔和背景,便于和顶栏/侧栏区分。\n\n```vue preview src=\"./demos/EmbeddedContent.zh.vue\"\n```\n\n## Scrollable Content\n\n内容超出时仅 Content 区域滚动,Header / Sider 保持固定。`MLayout` / `MLayoutContent` / `MLayoutSider` 通过内置 `MScrollbar` 提供统一滚动条。\n\n```vue preview src=\"./demos/ScrollableContent.zh.vue\"\n```\n\n## Absolute Shell\n\n根布局 `position=\"absolute\"` 铺满父级(父级需 `position: relative` + 明确高度)。\n\n```vue preview src=\"./demos/AbsoluteShell.zh.vue\"\n```\n\n## Layout Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `hasSider` | `boolean` | `false` | 横向容纳 `MLayoutSider`。 |\n| `siderPlacement` | `'left' \\| 'right'` | `'left'` | 侧栏位置。 |\n| `fillViewport` | `boolean` | `false` | 根布局撑满视口(`100dvh`),侧栏/内容才能按剩余高度拉伸。 |\n| `embedded` | `boolean` | `false` | 柔和背景(嵌套内容区)。 |\n| `position` | `'static' \\| 'absolute'` | `'static'` | 定位模式。 |\n| `contentClass` / `contentStyle` | — | — | 滚动容器 class / style。 |\n| `height` | `number \\| string` | — | — |\n| `padding` | `number \\| string` | — | — |\n| `radius` | `number \\| string` | — | — |\n\n## LayoutSider Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | 展开宽度(始终写在 `width` 上)。 |\n| `collapsedWidth` | `number` | `48` | 折叠时的 `max-width`。 |\n| `collapsed` | `boolean` | — | 折叠状态,支持 `v-model:collapsed`。 |\n| `defaultCollapsed` | `boolean` | `false` | 非受控初始折叠。 |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | 折叠触发器;`arrow` 等同 `arrow-circle`。 |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` 裁切内容;`width` 随侧栏收缩。 |\n| `showCollapsedContent` | `boolean` | `true` | 折叠后是否仍显示侧栏内容。 |\n| `bordered` / `inverted` | `boolean` | `false` | 边框 / 反色。 |\n| `triggerClass` / `triggerStyle` | — | — | 展开态触发器样式。 |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | 折叠态触发器样式。 |\n| `contentClass` / `contentStyle` | — | | 滚动容器 class / style。 |\n\n## Events\n\n| 事件 | 说明 |\n| --- | --- |\n| `scroll` | 滚动容器滚动时触发。 |\n| `after-enter` | 侧栏展开动画结束。 |\n| `after-leave` | 侧栏收起动画结束。 |\n| `collapse` | 侧栏开始收起。 |\n| `expand` | 侧栏开始展开。 |\n| `update:collapsed` | 折叠状态 v-model。 |\n\n## Expose\n\n`MLayout` / `MLayoutContent` / `MLayoutSider` 均暴露 `scrollTo(...)`。\n\n## Components\n\n| 组件 | 说明 |\n| --- | --- |\n| `MLayout` | 根布局。 |\n| `MLayoutHeader` | 顶栏。 |\n| `MLayoutContent` | 主内容区(默认撑满剩余空间)。 |\n| `MLayoutFooter` | 底栏。 |\n| `MLayoutSider` | 侧栏。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 布局区域。 |\n"
12119
+ "markdown": "---\ntitle: Layout\ncategory: 06 / LAYOUT\ndescription: 页面级布局骨架,含 Header / Sider / Content / Footer。\n---\n\n# Layout\n\n页面级布局容器。侧栏场景需在对应 `MLayout` 上设置 `has-sider`。根布局使用 `fill-viewport`(`height: 100dvh`)或显式 `height` 后,`MLayoutContent` / `MLayoutSider` 会撑满剩余空间。\n\n## 引入\n\n```ts\nimport {\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n```\n\n## 基础用法\n\nHeader / Content / Footer。Content 会占满中间剩余高度。\n\n```vue preview src=\"./demos/Basic.zh.vue\"\n```\n\n## With Sider\n\n顶栏 + 左侧栏 + 主内容。侧栏内嵌 `MMenu`,并通过 `v-model:collapsed` 与菜单折叠联动。内层 `has-sider` 的 Layout 会吃掉 Header 以下的全部高度。\n\n```vue preview src=\"./demos/WithSider.zh.vue\"\n```\n\n## Right Sider\n\n```vue preview src=\"./demos/RightSider.zh.vue\"\n```\n\n## Full Shell\n\n完整后台骨架:顶栏 + 反色侧栏(`MMenu` `inverted`)+ 内容 + 底栏。\n\n```vue preview src=\"./demos/FullShell.zh.vue\"\n```\n\n## Embedded Content\n\n`embedded` 给内容区柔和背景,便于和顶栏/侧栏区分。\n\n```vue preview src=\"./demos/EmbeddedContent.zh.vue\"\n```\n\n## Scrollable Content\n\n内容超出时,可在 `MLayoutContent` 上自行设置 `overflow: auto`(或包一层 `MScrollbar`);Header / Sider 保持固定。`MLayout` 根容器仍内置 `MScrollbar`;`MLayoutContent` / `MLayoutSider` 为单层壳。\n\n```vue preview src=\"./demos/ScrollableContent.zh.vue\"\n```\n\n## Absolute Shell\n\n根布局 `position=\"absolute\"` 铺满父级(父级需 `position: relative` + 明确高度)。\n\n```vue preview src=\"./demos/AbsoluteShell.zh.vue\"\n```\n\n## Layout Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `hasSider` | `boolean` | `false` | 横向容纳 `MLayoutSider`。 |\n| `siderPlacement` | `'left' \\| 'right'` | `'left'` | 侧栏位置。 |\n| `fillViewport` | `boolean` | `false` | 根布局撑满视口(`100dvh`),侧栏/内容才能按剩余高度拉伸。 |\n| `embedded` | `boolean` | `false` | 柔和背景(嵌套内容区)。 |\n| `position` | `'static' \\| 'absolute'` | `'static'` | 定位模式。 |\n| `contentClass` / `contentStyle` | — | — | 滚动容器 class / style。 |\n| `height` | `number \\| string` | — | — |\n| `padding` | `number \\| string` | — | — |\n| `radius` | `number \\| string` | — | — |\n\n## LayoutSider Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | 展开宽度(始终写在 `width` 上)。 |\n| `collapsedWidth` | `number` | `48` | 折叠时的 `max-width`。 |\n| `collapsed` | `boolean` | — | 折叠状态,支持 `v-model:collapsed`。 |\n| `defaultCollapsed` | `boolean` | `false` | 非受控初始折叠。 |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | 折叠触发器;`arrow` 等同 `arrow-circle`。 |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` 裁切内容;`width` 随侧栏收缩。 |\n| `showCollapsedContent` | `boolean` | `true` | 折叠后是否仍显示侧栏内容。 |\n| `bordered` / `inverted` | `boolean` | `false` | 边框 / 反色。 |\n| `triggerClass` / `triggerStyle` | — | — | 展开态触发器样式。 |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | 折叠态触发器样式。 |\n| `padding` | `number \\| string` | — | 可选内边距;无默认值。 |\n| `radius` | `number \\| string` | — | 圆角。 |\n\n## Events\n\n| 事件 | 说明 |\n| --- | --- |\n| `scroll` | `MLayout` 滚动容器滚动时触发。 |\n| `after-enter` | 侧栏展开动画结束。 |\n| `after-leave` | 侧栏收起动画结束。 |\n| `collapse` | 侧栏开始收起。 |\n| `expand` | 侧栏开始展开。 |\n| `update:collapsed` | 折叠状态 v-model。 |\n\n## Expose\n\n`MLayout` 暴露 `scrollTo(...)`。\n\n## Components\n\n| 组件 | 说明 |\n| --- | --- |\n| `MLayout` | 根布局。 |\n| `MLayoutHeader` | 顶栏。 |\n| `MLayoutContent` | 主内容区(默认撑满剩余空间)。 |\n| `MLayoutFooter` | 底栏。 |\n| `MLayoutSider` | 侧栏。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 布局区域。 |\n"
12120
12120
  },
12121
12121
  "en-US": {
12122
12122
  "title": "Layout",
@@ -12140,7 +12140,7 @@
12140
12140
  {
12141
12141
  "id": "with-sider",
12142
12142
  "title": "With Sider",
12143
- "body": "Header + left sider + main. The inner `has-sider` layout consumes all height below the header.\n\n```vue preview src=\"./demos/WithSider.en.vue\"\n```"
12143
+ "body": "Header + left sider + main. The sider hosts `MMenu`, bound to `v-model:collapsed`. The inner `has-sider` layout consumes all height below the header.\n\n```vue preview src=\"./demos/WithSider.en.vue\"\n```"
12144
12144
  },
12145
12145
  {
12146
12146
  "id": "right-sider",
@@ -12150,7 +12150,7 @@
12150
12150
  {
12151
12151
  "id": "full-shell",
12152
12152
  "title": "Full Shell",
12153
- "body": "Admin-style shell: header + sider + content + footer.\n\n```vue preview src=\"./demos/FullShell.en.vue\"\n```"
12153
+ "body": "Admin-style shell: header + inverted sider (`MMenu` `inverted`) + content + footer.\n\n```vue preview src=\"./demos/FullShell.en.vue\"\n```"
12154
12154
  },
12155
12155
  {
12156
12156
  "id": "embedded-content",
@@ -12160,7 +12160,7 @@
12160
12160
  {
12161
12161
  "id": "scrollable-content",
12162
12162
  "title": "Scrollable Content",
12163
- "body": "Only the content pane scrolls; header and sider stay fixed. `MLayout`, `MLayoutContent`, and `MLayoutSider` use built-in `MScrollbar`.\n\n```vue preview src=\"./demos/ScrollableContent.en.vue\"\n```"
12163
+ "body": "When content overflows, set `overflow: auto` on `MLayoutContent` (or wrap with `MScrollbar`); header and sider stay fixed. Root `MLayout` still has built-in `MScrollbar`; `MLayoutContent` / `MLayoutSider` are single-element shells.\n\n```vue preview src=\"./demos/ScrollableContent.en.vue\"\n```"
12164
12164
  },
12165
12165
  {
12166
12166
  "id": "absolute-shell",
@@ -12175,17 +12175,17 @@
12175
12175
  {
12176
12176
  "id": "layoutsider-props",
12177
12177
  "title": "LayoutSider Props",
12178
- "body": "| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | Expanded width (always set as `width`). |\n| `collapsedWidth` | `number` | `48` | Collapsed `max-width`. |\n| `collapsed` | `boolean` | — | Collapsed state (`v-model:collapsed`). |\n| `defaultCollapsed` | `boolean` | `false` | Uncontrolled initial collapsed state. |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | Collapse trigger; `arrow` aliases `arrow-circle`. |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` clips content; `width` shrinks with sider. |\n| `showCollapsedContent` | `boolean` | `true` | Keep sider content visible while collapsed. |\n| `bordered` / `inverted` | `boolean` | `false` | Border / inverted colors. |\n| `triggerClass` / `triggerStyle` | — | — | Expanded trigger styles. |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | Collapsed trigger styles. |\n| `contentClass` / `contentStyle` | — | | Scroll container class / style. |"
12178
+ "body": "| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | Expanded width (always set as `width`). |\n| `collapsedWidth` | `number` | `48` | Collapsed `max-width`. |\n| `collapsed` | `boolean` | — | Collapsed state (`v-model:collapsed`). |\n| `defaultCollapsed` | `boolean` | `false` | Uncontrolled initial collapsed state. |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | Collapse trigger; `arrow` aliases `arrow-circle`. |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` clips content; `width` shrinks with sider. |\n| `showCollapsedContent` | `boolean` | `true` | Keep sider content visible while collapsed. |\n| `bordered` / `inverted` | `boolean` | `false` | Border / inverted colors. |\n| `triggerClass` / `triggerStyle` | — | — | Expanded trigger styles. |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | Collapsed trigger styles. |\n| `padding` | `number \\| string` | — | Optional padding; no default. |\n| `radius` | `number \\| string` | — | Border radius. |"
12179
12179
  },
12180
12180
  {
12181
12181
  "id": "events",
12182
12182
  "title": "Events",
12183
- "body": "| Event | Description |\n| --- | --- |\n| `scroll` | Fired when the scroll container scrolls. |"
12183
+ "body": "| Event | Description |\n| --- | --- |\n| `scroll` | Fired when the `MLayout` scroll container scrolls. |\n| `after-enter` | Fired when the sider expand transition ends. |\n| `after-leave` | Fired when the sider collapse transition ends. |\n| `collapse` | Fired when the sider starts collapsing. |\n| `expand` | Fired when the sider starts expanding. |\n| `update:collapsed` | Collapsed state v-model. |"
12184
12184
  },
12185
12185
  {
12186
12186
  "id": "expose",
12187
12187
  "title": "Expose",
12188
- "body": "`MLayout` / `MLayoutContent` / `MLayoutSider` expose `scrollTo(...)`."
12188
+ "body": "`MLayout` exposes `scrollTo(...)`."
12189
12189
  },
12190
12190
  {
12191
12191
  "id": "components",
@@ -12198,7 +12198,7 @@
12198
12198
  "body": "| Slot | Description |\n| --- | --- |\n| `default` | Layout regions. |"
12199
12199
  }
12200
12200
  ],
12201
- "markdown": "---\ntitle: Layout\ncategory: 06 / LAYOUT\ndescription: Page layout shell with Header / Sider / Content / Footer.\n---\n\n# Layout\n\nPage-level layout shell. Set `has-sider` on the `MLayout` that hosts a sider. Give the root layout a fixed `height` (or `min-height`) so `MLayoutContent` can fill the remaining space.\n\n## Import\n\n```ts\nimport {\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n```\n\n## Basic\n\nHeader / Content / Footer. Content fills the leftover height.\n\n```vue preview src=\"./demos/Basic.en.vue\"\n```\n\n## With Sider\n\nHeader + left sider + main. The inner `has-sider` layout consumes all height below the header.\n\n```vue preview src=\"./demos/WithSider.en.vue\"\n```\n\n## Right Sider\n\n```vue preview src=\"./demos/RightSider.en.vue\"\n```\n\n## Full Shell\n\nAdmin-style shell: header + sider + content + footer.\n\n```vue preview src=\"./demos/FullShell.en.vue\"\n```\n\n## Embedded Content\n\n`embedded` softens the content background so it separates from header / sider.\n\n```vue preview src=\"./demos/EmbeddedContent.en.vue\"\n```\n\n## Scrollable Content\n\nOnly the content pane scrolls; header and sider stay fixed. `MLayout`, `MLayoutContent`, and `MLayoutSider` use built-in `MScrollbar`.\n\n```vue preview src=\"./demos/ScrollableContent.en.vue\"\n```\n\n## Absolute Shell\n\nRoot `position=\"absolute\"` fills a relatively positioned parent with an explicit height.\n\n```vue preview src=\"./demos/AbsoluteShell.en.vue\"\n```\n\n## Layout Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `hasSider` | `boolean` | `false` | Horizontal layout for `MLayoutSider`. |\n| `siderPlacement` | `'left' \\| 'right'` | `'left'` | Sider side. |\n| `embedded` | `boolean` | `false` | Soft background for nested content. |\n| `position` | `'static' \\| 'absolute'` | `'static'` | Positioning mode. |\n| `contentClass` / `contentStyle` | — | — | Scroll container class / style. |\n\n## LayoutSider Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | Expanded width (always set as `width`). |\n| `collapsedWidth` | `number` | `48` | Collapsed `max-width`. |\n| `collapsed` | `boolean` | — | Collapsed state (`v-model:collapsed`). |\n| `defaultCollapsed` | `boolean` | `false` | Uncontrolled initial collapsed state. |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | Collapse trigger; `arrow` aliases `arrow-circle`. |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` clips content; `width` shrinks with sider. |\n| `showCollapsedContent` | `boolean` | `true` | Keep sider content visible while collapsed. |\n| `bordered` / `inverted` | `boolean` | `false` | Border / inverted colors. |\n| `triggerClass` / `triggerStyle` | — | — | Expanded trigger styles. |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | Collapsed trigger styles. |\n| `contentClass` / `contentStyle` | — | | Scroll container class / style. |\n\n## Events\n\n| Event | Description |\n| --- | --- |\n| `scroll` | Fired when the scroll container scrolls. |\n\n## Expose\n\n`MLayout` / `MLayoutContent` / `MLayoutSider` expose `scrollTo(...)`.\n\n## Components\n\n| Component | Description |\n| --- | --- |\n| `MLayout` | Root layout. |\n| `MLayoutHeader` | Header bar. |\n| `MLayoutContent` | Main content (fills leftover space by default). |\n| `MLayoutFooter` | Footer bar. |\n| `MLayoutSider` | Side panel. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Layout regions. |\n"
12201
+ "markdown": "---\ntitle: Layout\ncategory: 06 / LAYOUT\ndescription: Page layout shell with Header / Sider / Content / Footer.\n---\n\n# Layout\n\nPage-level layout shell. Set `has-sider` on the `MLayout` that hosts a sider. Give the root layout a fixed `height` (or `min-height`) so `MLayoutContent` can fill the remaining space.\n\n## Import\n\n```ts\nimport {\n MLayout,\n MLayoutContent,\n MLayoutFooter,\n MLayoutHeader,\n MLayoutSider,\n} from 'morya-ui'\n```\n\n## Basic\n\nHeader / Content / Footer. Content fills the leftover height.\n\n```vue preview src=\"./demos/Basic.en.vue\"\n```\n\n## With Sider\n\nHeader + left sider + main. The sider hosts `MMenu`, bound to `v-model:collapsed`. The inner `has-sider` layout consumes all height below the header.\n\n```vue preview src=\"./demos/WithSider.en.vue\"\n```\n\n## Right Sider\n\n```vue preview src=\"./demos/RightSider.en.vue\"\n```\n\n## Full Shell\n\nAdmin-style shell: header + inverted sider (`MMenu` `inverted`) + content + footer.\n\n```vue preview src=\"./demos/FullShell.en.vue\"\n```\n\n## Embedded Content\n\n`embedded` softens the content background so it separates from header / sider.\n\n```vue preview src=\"./demos/EmbeddedContent.en.vue\"\n```\n\n## Scrollable Content\n\nWhen content overflows, set `overflow: auto` on `MLayoutContent` (or wrap with `MScrollbar`); header and sider stay fixed. Root `MLayout` still has built-in `MScrollbar`; `MLayoutContent` / `MLayoutSider` are single-element shells.\n\n```vue preview src=\"./demos/ScrollableContent.en.vue\"\n```\n\n## Absolute Shell\n\nRoot `position=\"absolute\"` fills a relatively positioned parent with an explicit height.\n\n```vue preview src=\"./demos/AbsoluteShell.en.vue\"\n```\n\n## Layout Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `hasSider` | `boolean` | `false` | Horizontal layout for `MLayoutSider`. |\n| `siderPlacement` | `'left' \\| 'right'` | `'left'` | Sider side. |\n| `embedded` | `boolean` | `false` | Soft background for nested content. |\n| `position` | `'static' \\| 'absolute'` | `'static'` | Positioning mode. |\n| `contentClass` / `contentStyle` | — | — | Scroll container class / style. |\n\n## LayoutSider Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `width` | `number \\| string` | `272` | Expanded width (always set as `width`). |\n| `collapsedWidth` | `number` | `48` | Collapsed `max-width`. |\n| `collapsed` | `boolean` | — | Collapsed state (`v-model:collapsed`). |\n| `defaultCollapsed` | `boolean` | `false` | Uncontrolled initial collapsed state. |\n| `showTrigger` | `boolean \\| 'bar' \\| 'arrow-circle' \\| 'arrow'` | `false` | Collapse trigger; `arrow` aliases `arrow-circle`. |\n| `collapseMode` | `'width' \\| 'transform'` | `'transform'` | `transform` clips content; `width` shrinks with sider. |\n| `showCollapsedContent` | `boolean` | `true` | Keep sider content visible while collapsed. |\n| `bordered` / `inverted` | `boolean` | `false` | Border / inverted colors. |\n| `triggerClass` / `triggerStyle` | — | — | Expanded trigger styles. |\n| `collapsedTriggerClass` / `collapsedTriggerStyle` | — | — | Collapsed trigger styles. |\n| `padding` | `number \\| string` | — | Optional padding; no default. |\n| `radius` | `number \\| string` | — | Border radius. |\n\n## Events\n\n| Event | Description |\n| --- | --- |\n| `scroll` | Fired when the `MLayout` scroll container scrolls. |\n| `after-enter` | Fired when the sider expand transition ends. |\n| `after-leave` | Fired when the sider collapse transition ends. |\n| `collapse` | Fired when the sider starts collapsing. |\n| `expand` | Fired when the sider starts expanding. |\n| `update:collapsed` | Collapsed state v-model. |\n\n## Expose\n\n`MLayout` exposes `scrollTo(...)`.\n\n## Components\n\n| Component | Description |\n| --- | --- |\n| `MLayout` | Root layout. |\n| `MLayoutHeader` | Header bar. |\n| `MLayoutContent` | Main content (fills leftover space by default). |\n| `MLayoutFooter` | Footer bar. |\n| `MLayoutSider` | Side panel. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Layout regions. |\n"
12202
12202
  }
12203
12203
  }
12204
12204
  },
@@ -12400,6 +12400,358 @@
12400
12400
  }
12401
12401
  }
12402
12402
  },
12403
+ {
12404
+ "id": "Loading",
12405
+ "name": "Loading",
12406
+ "exportName": "MLoading",
12407
+ "category": "05 / FEEDBACK",
12408
+ "description": "加载指示与遮罩:多种动效、区域加载、v-loading 指令和命令式 service。",
12409
+ "descriptionEn": "Loading indicator and mask, with multiple effects, a region overlay, the v-loading directive, and an imperative service.",
12410
+ "import": "import { MLoading } from 'morya-ui'",
12411
+ "props": [
12412
+ {
12413
+ "name": "loading",
12414
+ "type": "boolean",
12415
+ "default": "true",
12416
+ "description": "包裹内容或 `fullscreen` 时是否显示遮罩。单独指示器始终显示。"
12417
+ },
12418
+ {
12419
+ "name": "effect",
12420
+ "type": "'circular' | 'aurora' | 'bounce' | 'wave' | 'pulse' | 'stardust'",
12421
+ "default": "'circular'",
12422
+ "description": "动效。可用 `componentDefaults.Loading.effect` 改默认值。"
12423
+ },
12424
+ {
12425
+ "name": "text",
12426
+ "type": "string",
12427
+ "default": "—",
12428
+ "description": "指示器下方文案。不传则不显示。"
12429
+ },
12430
+ {
12431
+ "name": "ariaLabel",
12432
+ "type": "string",
12433
+ "default": "locale `loading",
12434
+ "description": "无文案时的可访问名称。有文案时以文案为准。"
12435
+ },
12436
+ {
12437
+ "name": "size",
12438
+ "type": "'small' | 'large' | 'sm' | 'md' | 'lg'",
12439
+ "default": "—",
12440
+ "description": "指示器缩放。"
12441
+ },
12442
+ {
12443
+ "name": "background",
12444
+ "type": "string",
12445
+ "default": "—",
12446
+ "description": "遮罩背景,任意 CSS 颜色。"
12447
+ },
12448
+ {
12449
+ "name": "customClass",
12450
+ "type": "string",
12451
+ "default": "—",
12452
+ "description": "加在遮罩上的类名。"
12453
+ },
12454
+ {
12455
+ "name": "fullscreen",
12456
+ "type": "boolean",
12457
+ "default": "false",
12458
+ "description": "遮罩铺满视口(Teleport 到 `body`)。"
12459
+ },
12460
+ {
12461
+ "name": "lock",
12462
+ "type": "boolean",
12463
+ "default": "false",
12464
+ "description": "显示时禁止页面滚动。"
12465
+ },
12466
+ {
12467
+ "name": "delay",
12468
+ "type": "number",
12469
+ "default": "0",
12470
+ "description": "显示前延迟(ms)。"
12471
+ },
12472
+ {
12473
+ "name": "pt",
12474
+ "type": "[RootPassThrough](/docs/types#RootPassThrough) `{ root? }",
12475
+ "default": "—",
12476
+ "description": "DOM 透传,见 [样式与 attrs](/docs/attrs)。"
12477
+ }
12478
+ ],
12479
+ "events": [],
12480
+ "slots": [
12481
+ {
12482
+ "name": "default",
12483
+ "description": "被遮罩盖住的内容。"
12484
+ },
12485
+ {
12486
+ "name": "indicator",
12487
+ "description": "替换遮罩中的指示器。仅在有默认插槽或 `fullscreen` 时生效。"
12488
+ }
12489
+ ],
12490
+ "examples": [
12491
+ {
12492
+ "id": "引入-1",
12493
+ "section": "引入",
12494
+ "sectionId": "引入",
12495
+ "lang": "ts",
12496
+ "preview": false,
12497
+ "code": "import { loading, MLoading, useLoading, vLoading } from 'morya-ui'",
12498
+ "locale": "zh-CN"
12499
+ },
12500
+ {
12501
+ "id": "动效-1",
12502
+ "section": "动效",
12503
+ "sectionId": "动效",
12504
+ "lang": "vue",
12505
+ "preview": true,
12506
+ "code": "<script setup lang=\"ts\">\nimport { MLoading } from 'morya-ui'\n\nconst effects = [\n { id: 'circular', label: '圆环' },\n { id: 'aurora', label: '极光环' },\n { id: 'bounce', label: '弹跳球' },\n { id: 'wave', label: '波浪条' },\n { id: 'pulse', label: '脉冲环' },\n { id: 'stardust', label: '星尘' },\n] as const\n</script>\n\n<template>\n <div class=\"grid grid-cols-2 gap-4 md:grid-cols-3\">\n <div\n v-for=\"item in effects\"\n :key=\"item.id\"\n class=\"flex min-h-36 items-center justify-center rounded-md border border-solid border-[var(--m-color-border)] bg-[var(--m-color-surface)] p-4\"\n >\n <MLoading :effect=\"item.id\" :text=\"item.label\" />\n </div>\n </div>\n</template>",
12507
+ "locale": "zh-CN"
12508
+ },
12509
+ {
12510
+ "id": "区域加载-1",
12511
+ "section": "区域加载",
12512
+ "sectionId": "区域加载",
12513
+ "lang": "vue",
12514
+ "preview": true,
12515
+ "code": "<script setup lang=\"ts\">\nimport { MButton, MLoading, vLoading } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst loading = ref(true)\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <MLoading :loading=\"loading\" text=\"加载中\" effect=\"wave\">\n <div class=\"min-h-32 p-4\">\n 区域内容\n </div>\n </MLoading>\n <div\n v-loading=\"loading\"\n m-loading-text=\"加载中\"\n m-loading-effect=\"circular\"\n class=\"min-h-32 rounded-md border border-solid border-[var(--m-color-border)] p-4\"\n >\n 指令覆盖的区域\n </div>\n <div>\n <MButton size=\"small\" :label=\"loading ? '结束加载' : '开始加载'\" @click=\"loading = !loading\" />\n </div>\n </div>\n</template>",
12516
+ "locale": "zh-CN"
12517
+ },
12518
+ {
12519
+ "id": "服务式调用-1",
12520
+ "section": "服务式调用",
12521
+ "sectionId": "服务式调用",
12522
+ "lang": "vue",
12523
+ "preview": true,
12524
+ "code": "<script setup lang=\"ts\">\nimport { MButton, useLoading } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst panel = ref<HTMLElement>()\nconst { open } = useLoading()\n\nfunction openRegion() {\n const instance = open({\n target: panel.value,\n text: '加载中',\n effect: 'wave',\n })\n window.setTimeout(() => instance.close(), 1600)\n}\n\nfunction openFullscreen() {\n const instance = open({\n text: '正在提交',\n effect: 'aurora',\n lock: true,\n })\n window.setTimeout(() => instance.close(), 1600)\n}\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <div\n ref=\"panel\"\n class=\"min-h-32 rounded-md border border-solid border-[var(--m-color-border)] p-4\"\n >\n 可被服务盖住的区域\n </div>\n <div class=\"flex flex-wrap gap-3\">\n <MButton label=\"区域加载\" severity=\"secondary\" @click=\"openRegion\" />\n <MButton label=\"全屏加载\" @click=\"openFullscreen\" />\n </div>\n </div>\n</template>",
12525
+ "locale": "zh-CN"
12526
+ },
12527
+ {
12528
+ "id": "服务式调用-2",
12529
+ "section": "服务式调用",
12530
+ "sectionId": "服务式调用",
12531
+ "lang": "ts",
12532
+ "preview": false,
12533
+ "code": "const instance = loading.service({\n text: '正在提交',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('即将完成')\ninstance.close()",
12534
+ "locale": "zh-CN"
12535
+ },
12536
+ {
12537
+ "id": "服务式调用-3",
12538
+ "section": "服务式调用",
12539
+ "sectionId": "服务式调用",
12540
+ "lang": "ts",
12541
+ "preview": false,
12542
+ "code": "loading.service({\n target: '#panel',\n text: '加载中',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: '自定义',\n})",
12543
+ "locale": "zh-CN"
12544
+ },
12545
+ {
12546
+ "id": "服务式调用-4",
12547
+ "section": "服务式调用",
12548
+ "sectionId": "服务式调用",
12549
+ "lang": "ts",
12550
+ "preview": false,
12551
+ "code": "const { open, close } = useLoading({ effect: 'wave' })\nopen({ text: '保存中' })\nclose()",
12552
+ "locale": "zh-CN"
12553
+ },
12554
+ {
12555
+ "id": "import-1",
12556
+ "section": "Import",
12557
+ "sectionId": "import",
12558
+ "lang": "ts",
12559
+ "preview": false,
12560
+ "code": "import { loading, MLoading, useLoading, vLoading } from 'morya-ui'",
12561
+ "locale": "en-US"
12562
+ },
12563
+ {
12564
+ "id": "effects-1",
12565
+ "section": "Effects",
12566
+ "sectionId": "effects",
12567
+ "lang": "vue",
12568
+ "preview": true,
12569
+ "code": "<script setup lang=\"ts\">\nimport { MLoading } from 'morya-ui'\n\nconst effects = [\n { id: 'circular', label: '圆环' },\n { id: 'aurora', label: '极光环' },\n { id: 'bounce', label: '弹跳球' },\n { id: 'wave', label: '波浪条' },\n { id: 'pulse', label: '脉冲环' },\n { id: 'stardust', label: '星尘' },\n] as const\n</script>\n\n<template>\n <div class=\"grid grid-cols-2 gap-4 md:grid-cols-3\">\n <div\n v-for=\"item in effects\"\n :key=\"item.id\"\n class=\"flex min-h-36 items-center justify-center rounded-md border border-solid border-[var(--m-color-border)] bg-[var(--m-color-surface)] p-4\"\n >\n <MLoading :effect=\"item.id\" :text=\"item.label\" />\n </div>\n </div>\n</template>",
12570
+ "locale": "en-US"
12571
+ },
12572
+ {
12573
+ "id": "region-1",
12574
+ "section": "Region",
12575
+ "sectionId": "region",
12576
+ "lang": "vue",
12577
+ "preview": true,
12578
+ "code": "<script setup lang=\"ts\">\nimport { MButton, MLoading, vLoading } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst loading = ref(true)\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <MLoading :loading=\"loading\" text=\"Loading\" effect=\"wave\">\n <div class=\"min-h-32 p-4\">\n Region content\n </div>\n </MLoading>\n <div\n v-loading=\"loading\"\n m-loading-text=\"Loading\"\n m-loading-effect=\"circular\"\n class=\"min-h-32 rounded-md border border-solid border-[var(--m-color-border)] p-4\"\n >\n Directive target\n </div>\n <div>\n <MButton size=\"small\" :label=\"loading ? 'Stop' : 'Start'\" @click=\"loading = !loading\" />\n </div>\n </div>\n</template>",
12579
+ "locale": "en-US"
12580
+ },
12581
+ {
12582
+ "id": "service-1",
12583
+ "section": "Service",
12584
+ "sectionId": "service",
12585
+ "lang": "vue",
12586
+ "preview": true,
12587
+ "code": "<script setup lang=\"ts\">\nimport { MButton, useLoading } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst panel = ref<HTMLElement>()\nconst { open } = useLoading()\n\nfunction openRegion() {\n const instance = open({\n target: panel.value,\n text: 'Loading',\n effect: 'wave',\n })\n window.setTimeout(() => instance.close(), 1600)\n}\n\nfunction openFullscreen() {\n const instance = open({\n text: 'Submitting',\n effect: 'aurora',\n lock: true,\n })\n window.setTimeout(() => instance.close(), 1600)\n}\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <div\n ref=\"panel\"\n class=\"min-h-32 rounded-md border border-solid border-[var(--m-color-border)] p-4\"\n >\n Region covered by the service\n </div>\n <div class=\"flex flex-wrap gap-3\">\n <MButton label=\"Cover region\" severity=\"secondary\" @click=\"openRegion\" />\n <MButton label=\"Fullscreen\" @click=\"openFullscreen\" />\n </div>\n </div>\n</template>",
12588
+ "locale": "en-US"
12589
+ },
12590
+ {
12591
+ "id": "service-2",
12592
+ "section": "Service",
12593
+ "sectionId": "service",
12594
+ "lang": "ts",
12595
+ "preview": false,
12596
+ "code": "const instance = loading.service({\n text: 'Submitting',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('Almost done')\ninstance.close()",
12597
+ "locale": "en-US"
12598
+ },
12599
+ {
12600
+ "id": "service-3",
12601
+ "section": "Service",
12602
+ "sectionId": "service",
12603
+ "lang": "ts",
12604
+ "preview": false,
12605
+ "code": "loading.service({\n target: '#panel',\n text: 'Loading',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: 'Custom',\n})",
12606
+ "locale": "en-US"
12607
+ },
12608
+ {
12609
+ "id": "service-4",
12610
+ "section": "Service",
12611
+ "sectionId": "service",
12612
+ "lang": "ts",
12613
+ "preview": false,
12614
+ "code": "const { open, close } = useLoading({ effect: 'wave' })\nopen({ text: 'Saving' })\nclose()",
12615
+ "locale": "en-US"
12616
+ }
12617
+ ],
12618
+ "locales": {
12619
+ "zh-CN": {
12620
+ "title": "Loading",
12621
+ "description": "加载指示与遮罩:多种动效、区域加载、v-loading 指令和命令式 service。",
12622
+ "sections": [
12623
+ {
12624
+ "id": "overview",
12625
+ "title": "",
12626
+ "body": "# Loading\n\n用于区域或全屏的加载反馈。可以只渲染指示器,也可以盖住一块内容,或用指令和服务在任意节点上打开遮罩。\n\n内置圆环、极光环、弹跳球、波浪条、脉冲环和星尘。默认是圆环(`effect=\"circular\"`)。要改全局默认动效,设置 `componentDefaults.Loading.effect`。\n\n全屏遮罩会 Teleport 到 `body`,避免被父级 `overflow` / `transform` 裁切。同一时间只保留一个全屏实例。"
12627
+ },
12628
+ {
12629
+ "id": "引入",
12630
+ "title": "引入",
12631
+ "body": "```ts\nimport { loading, MLoading, useLoading, vLoading } from 'morya-ui'\n```\n\n`app.use(MoryaUI)` 会注册 `v-loading`。按需引入时,在 `<script setup>` 里导入 `vLoading` 即可在模板中使用该指令。"
12632
+ },
12633
+ {
12634
+ "id": "动效",
12635
+ "title": "动效",
12636
+ "body": "```vue preview src=\"./demos/Effects.vue\"\n```"
12637
+ },
12638
+ {
12639
+ "id": "区域加载",
12640
+ "title": "区域加载",
12641
+ "body": "组件包住内容,或在元素上使用 `v-loading`。未传 `text` 时不显示文案,读屏仍使用 locale 的 `loading`。可用 `delay` 避免短请求闪一下。\n\n```vue preview src=\"./demos/Region.zh.vue\"\n```"
12642
+ },
12643
+ {
12644
+ "id": "服务式调用",
12645
+ "title": "服务式调用",
12646
+ "body": "不传 `target` 时遮罩铺满视口。`close()` 会先播放离场再卸载,`setText()` 改文案。也可用 `useLoading()`,在组件卸载时自动关闭。\n\n```vue preview src=\"./demos/Service.zh.vue\"\n```\n\n```ts\nconst instance = loading.service({\n text: '正在提交',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('即将完成')\ninstance.close()\n```\n\n覆盖某个节点,或传入自定义指示器:\n\n```ts\nloading.service({\n target: '#panel',\n text: '加载中',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: '自定义',\n})\n```\n\n```ts\nconst { open, close } = useLoading({ effect: 'wave' })\nopen({ text: '保存中' })\nclose()\n```"
12647
+ },
12648
+ {
12649
+ "id": "指令",
12650
+ "title": "指令",
12651
+ "body": "| 写法 | 说明 |\n| --- | --- |\n| `v-loading` | 布尔值,或带 `text` / `effect` / `background` / `lock` / `delay` / `spinner` 等字段的对象。 |\n| `v-loading.fullscreen` | 全屏遮罩。 |\n| `v-loading.lock` | 打开时锁定页面滚动。 |\n| `v-loading.body` | 遮罩挂到 `body`,并盖住当前元素(跟随尺寸变化)。 |\n| `m-loading-text` | 文案。 |\n| `m-loading-effect` | `circular` / `aurora` / `bounce` / `wave` / `pulse` / `stardust`。 |\n| `m-loading-background` | 遮罩背景色。 |\n| `m-loading-custom-class` | 加在遮罩上的类名。 |\n| `m-loading-delay` | 显示前延迟(ms)。 |"
12652
+ },
12653
+ {
12654
+ "id": "props",
12655
+ "title": "Props",
12656
+ "body": "| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `loading` | `boolean` | `true` | 包裹内容或 `fullscreen` 时是否显示遮罩。单独指示器始终显示。 |\n| `effect` | `'circular' \\| 'aurora' \\| 'bounce' \\| 'wave' \\| 'pulse' \\| 'stardust'` | `'circular'` | 动效。可用 `componentDefaults.Loading.effect` 改默认值。 |\n| `text` | `string` | — | 指示器下方文案。不传则不显示。 |\n| `ariaLabel` | `string` | locale `loading` | 无文案时的可访问名称。有文案时以文案为准。 |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | — | 指示器缩放。 |\n| `background` | `string` | — | 遮罩背景,任意 CSS 颜色。 |\n| `customClass` | `string` | — | 加在遮罩上的类名。 |\n| `fullscreen` | `boolean` | `false` | 遮罩铺满视口(Teleport 到 `body`)。 |\n| `lock` | `boolean` | `false` | 显示时禁止页面滚动。 |\n| `delay` | `number` | `0` | 显示前延迟(ms)。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs)。 |"
12657
+ },
12658
+ {
12659
+ "id": "events",
12660
+ "title": "Events",
12661
+ "body": "无自定义事件。"
12662
+ },
12663
+ {
12664
+ "id": "slots",
12665
+ "title": "Slots",
12666
+ "body": "| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 被遮罩盖住的内容。 |\n| `indicator` | 替换遮罩中的指示器。仅在有默认插槽或 `fullscreen` 时生效。 |"
12667
+ },
12668
+ {
12669
+ "id": "服务",
12670
+ "title": "服务",
12671
+ "body": "`loading.service(options)` 返回 `{ close, setText }`。`useLoading(defaults)` 返回 `{ open, close, setText }`。\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `target` | `string \\| HTMLElement` | — | 要盖住的元素或选择器。省略则为全屏。 |\n| `fullscreen` | `boolean` | 无 `target` 时为 `true` | 铺满视口。 |\n| `body` | `boolean` | `false` | 遮罩挂到 `body`,定位到 `target` 上。 |\n| `lock` | `boolean` | `false` | 锁定页面滚动。 |\n| `text` | `string` | — | 文案。 |\n| `effect` | 同组件 | `'circular'` | 动效。 |\n| `spinner` | `MRenderable` | — | 自定义指示器;设置后忽略内置 `effect`。 |\n| `background` | `string` | — | 遮罩背景。 |\n| `customClass` | `string` | — | 遮罩类名。 |\n| `size` | 同组件 | — | 指示器尺寸。 |\n| `delay` | `number` | — | 显示前延迟(ms)。 |"
12672
+ },
12673
+ {
12674
+ "id": "主题",
12675
+ "title": "主题",
12676
+ "body": "指示器颜色走语义色:`--m-color-primary`、`--m-color-success`、`--m-color-warning`、`--m-color-danger`、`--m-color-text-muted`。遮罩默认是表面色的半透明混合,可用 `background` 或 `--m-loading-mask-bg` 覆盖。全屏层级是 `--m-loading-z-index`(默认 `--m-z-base + 200`)。\n\n`prefers-reduced-motion: reduce` 时循环动效关闭。"
12677
+ },
12678
+ {
12679
+ "id": "无障碍",
12680
+ "title": "无障碍",
12681
+ "body": "- 指示器使用 `role=\"status\"`。\n- 遮罩区域设置 `aria-busy`,被盖住的内容设为 `inert`。\n- 不要只靠动画表示加载;需要说明时传入 `text`。"
12682
+ }
12683
+ ],
12684
+ "markdown": "---\ntitle: Loading\ncategory: 05 / FEEDBACK\ndescription: 加载指示与遮罩:多种动效、区域加载、v-loading 指令和命令式 service。\n---\n\n# Loading\n\n用于区域或全屏的加载反馈。可以只渲染指示器,也可以盖住一块内容,或用指令和服务在任意节点上打开遮罩。\n\n内置圆环、极光环、弹跳球、波浪条、脉冲环和星尘。默认是圆环(`effect=\"circular\"`)。要改全局默认动效,设置 `componentDefaults.Loading.effect`。\n\n全屏遮罩会 Teleport 到 `body`,避免被父级 `overflow` / `transform` 裁切。同一时间只保留一个全屏实例。\n\n## 引入\n\n```ts\nimport { loading, MLoading, useLoading, vLoading } from 'morya-ui'\n```\n\n`app.use(MoryaUI)` 会注册 `v-loading`。按需引入时,在 `<script setup>` 里导入 `vLoading` 即可在模板中使用该指令。\n\n## 动效\n\n```vue preview src=\"./demos/Effects.vue\"\n```\n\n## 区域加载\n\n组件包住内容,或在元素上使用 `v-loading`。未传 `text` 时不显示文案,读屏仍使用 locale 的 `loading`。可用 `delay` 避免短请求闪一下。\n\n```vue preview src=\"./demos/Region.zh.vue\"\n```\n\n## 服务式调用\n\n不传 `target` 时遮罩铺满视口。`close()` 会先播放离场再卸载,`setText()` 改文案。也可用 `useLoading()`,在组件卸载时自动关闭。\n\n```vue preview src=\"./demos/Service.zh.vue\"\n```\n\n```ts\nconst instance = loading.service({\n text: '正在提交',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('即将完成')\ninstance.close()\n```\n\n覆盖某个节点,或传入自定义指示器:\n\n```ts\nloading.service({\n target: '#panel',\n text: '加载中',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: '自定义',\n})\n```\n\n```ts\nconst { open, close } = useLoading({ effect: 'wave' })\nopen({ text: '保存中' })\nclose()\n```\n\n## 指令\n\n| 写法 | 说明 |\n| --- | --- |\n| `v-loading` | 布尔值,或带 `text` / `effect` / `background` / `lock` / `delay` / `spinner` 等字段的对象。 |\n| `v-loading.fullscreen` | 全屏遮罩。 |\n| `v-loading.lock` | 打开时锁定页面滚动。 |\n| `v-loading.body` | 遮罩挂到 `body`,并盖住当前元素(跟随尺寸变化)。 |\n| `m-loading-text` | 文案。 |\n| `m-loading-effect` | `circular` / `aurora` / `bounce` / `wave` / `pulse` / `stardust`。 |\n| `m-loading-background` | 遮罩背景色。 |\n| `m-loading-custom-class` | 加在遮罩上的类名。 |\n| `m-loading-delay` | 显示前延迟(ms)。 |\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `loading` | `boolean` | `true` | 包裹内容或 `fullscreen` 时是否显示遮罩。单独指示器始终显示。 |\n| `effect` | `'circular' \\| 'aurora' \\| 'bounce' \\| 'wave' \\| 'pulse' \\| 'stardust'` | `'circular'` | 动效。可用 `componentDefaults.Loading.effect` 改默认值。 |\n| `text` | `string` | — | 指示器下方文案。不传则不显示。 |\n| `ariaLabel` | `string` | locale `loading` | 无文案时的可访问名称。有文案时以文案为准。 |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | — | 指示器缩放。 |\n| `background` | `string` | — | 遮罩背景,任意 CSS 颜色。 |\n| `customClass` | `string` | — | 加在遮罩上的类名。 |\n| `fullscreen` | `boolean` | `false` | 遮罩铺满视口(Teleport 到 `body`)。 |\n| `lock` | `boolean` | `false` | 显示时禁止页面滚动。 |\n| `delay` | `number` | `0` | 显示前延迟(ms)。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs)。 |\n\n## Events\n\n无自定义事件。\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 被遮罩盖住的内容。 |\n| `indicator` | 替换遮罩中的指示器。仅在有默认插槽或 `fullscreen` 时生效。 |\n\n## 服务\n\n`loading.service(options)` 返回 `{ close, setText }`。`useLoading(defaults)` 返回 `{ open, close, setText }`。\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `target` | `string \\| HTMLElement` | — | 要盖住的元素或选择器。省略则为全屏。 |\n| `fullscreen` | `boolean` | 无 `target` 时为 `true` | 铺满视口。 |\n| `body` | `boolean` | `false` | 遮罩挂到 `body`,定位到 `target` 上。 |\n| `lock` | `boolean` | `false` | 锁定页面滚动。 |\n| `text` | `string` | — | 文案。 |\n| `effect` | 同组件 | `'circular'` | 动效。 |\n| `spinner` | `MRenderable` | — | 自定义指示器;设置后忽略内置 `effect`。 |\n| `background` | `string` | — | 遮罩背景。 |\n| `customClass` | `string` | — | 遮罩类名。 |\n| `size` | 同组件 | — | 指示器尺寸。 |\n| `delay` | `number` | — | 显示前延迟(ms)。 |\n\n## 主题\n\n指示器颜色走语义色:`--m-color-primary`、`--m-color-success`、`--m-color-warning`、`--m-color-danger`、`--m-color-text-muted`。遮罩默认是表面色的半透明混合,可用 `background` 或 `--m-loading-mask-bg` 覆盖。全屏层级是 `--m-loading-z-index`(默认 `--m-z-base + 200`)。\n\n`prefers-reduced-motion: reduce` 时循环动效关闭。\n\n## 无障碍\n\n- 指示器使用 `role=\"status\"`。\n- 遮罩区域设置 `aria-busy`,被盖住的内容设为 `inert`。\n- 不要只靠动画表示加载;需要说明时传入 `text`。\n"
12685
+ },
12686
+ "en-US": {
12687
+ "title": "Loading",
12688
+ "description": "Loading indicator and mask, with multiple effects, a region overlay, the v-loading directive, and an imperative service.",
12689
+ "sections": [
12690
+ {
12691
+ "id": "overview",
12692
+ "title": "",
12693
+ "body": "# Loading\n\nRegion or fullscreen loading feedback. Render an indicator on its own, cover a block of content, or open a mask on any node with the directive or service.\n\nBuilt-in graphics are a circular spinner, aurora ring, bouncing balls, wave bars, pulse rings, and stardust. The default is the circular spinner (`effect=\"circular\"`). Set `componentDefaults.Loading.effect` to change the global default.\n\nFullscreen masks teleport to `body` so parent `overflow` / `transform` cannot clip them. Only one fullscreen instance stays open at a time."
12694
+ },
12695
+ {
12696
+ "id": "import",
12697
+ "title": "Import",
12698
+ "body": "```ts\nimport { loading, MLoading, useLoading, vLoading } from 'morya-ui'\n```\n\n`app.use(MoryaUI)` registers `v-loading`. For on-demand usage, import `vLoading` in `<script setup>` and the template can use the directive."
12699
+ },
12700
+ {
12701
+ "id": "effects",
12702
+ "title": "Effects",
12703
+ "body": "```vue preview src=\"./demos/Effects.vue\"\n```"
12704
+ },
12705
+ {
12706
+ "id": "region",
12707
+ "title": "Region",
12708
+ "body": "Wrap content with the component, or put `v-loading` on an element. Omit `text` to hide the caption; screen readers still get the locale `loading` string. Use `delay` to avoid a flash on short requests.\n\n```vue preview src=\"./demos/Region.en.vue\"\n```"
12709
+ },
12710
+ {
12711
+ "id": "service",
12712
+ "title": "Service",
12713
+ "body": "With no `target`, the mask covers the viewport. `close()` plays the leave transition before unmounting, and `setText()` changes the caption. `useLoading()` closes automatically when the caller unmounts.\n\n```vue preview src=\"./demos/Service.en.vue\"\n```\n\n```ts\nconst instance = loading.service({\n text: 'Submitting',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('Almost done')\ninstance.close()\n```\n\nCover one node, or pass a custom indicator:\n\n```ts\nloading.service({\n target: '#panel',\n text: 'Loading',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: 'Custom',\n})\n```\n\n```ts\nconst { open, close } = useLoading({ effect: 'wave' })\nopen({ text: 'Saving' })\nclose()\n```"
12714
+ },
12715
+ {
12716
+ "id": "directive",
12717
+ "title": "Directive",
12718
+ "body": "| Form | Description |\n| --- | --- |\n| `v-loading` | A boolean, or an object with `text`, `effect`, `background`, `lock`, `delay`, `spinner`, and related fields. |\n| `v-loading.fullscreen` | Fullscreen mask. |\n| `v-loading.lock` | Lock page scrolling while open. |\n| `v-loading.body` | Mount the mask on `body`, positioned over the element (tracks size changes). |\n| `m-loading-text` | Caption. |\n| `m-loading-effect` | `circular` / `aurora` / `bounce` / `wave` / `pulse` / `stardust`. |\n| `m-loading-background` | Mask background. |\n| `m-loading-custom-class` | Extra class on the mask. |\n| `m-loading-delay` | Delay before showing (ms). |"
12719
+ },
12720
+ {
12721
+ "id": "props",
12722
+ "title": "Props",
12723
+ "body": "| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `loading` | `boolean` | `true` | Mask visibility when wrapping content or using `fullscreen`. A bare indicator is always shown. |\n| `effect` | `'circular' \\| 'aurora' \\| 'bounce' \\| 'wave' \\| 'pulse' \\| 'stardust'` | `'circular'` | Graphic. Override the default with `componentDefaults.Loading.effect`. |\n| `text` | `string` | — | Caption under the indicator. Hidden when omitted. |\n| `ariaLabel` | `string` | locale `loading` | Accessible name when there is no caption. A caption is used as the name when present. |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | — | Indicator scale. |\n| `background` | `string` | — | Mask background, any CSS color. |\n| `customClass` | `string` | — | Extra class on the mask. |\n| `fullscreen` | `boolean` | `false` | Cover the viewport (teleported to `body`). |\n| `lock` | `boolean` | `false` | Prevent page scrolling while visible. |\n| `delay` | `number` | `0` | Delay before showing (ms). |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |"
12724
+ },
12725
+ {
12726
+ "id": "events",
12727
+ "title": "Events",
12728
+ "body": "No custom events."
12729
+ },
12730
+ {
12731
+ "id": "slots",
12732
+ "title": "Slots",
12733
+ "body": "| Slot | Description |\n| --- | --- |\n| `default` | Content covered by the mask. |\n| `indicator` | Replaces the indicator inside the mask. Used when there is a default slot or `fullscreen`. |"
12734
+ },
12735
+ {
12736
+ "id": "service",
12737
+ "title": "Service",
12738
+ "body": "`loading.service(options)` returns `{ close, setText }`. `useLoading(defaults)` returns `{ open, close, setText }`.\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `target` | `string \\| HTMLElement` | — | Element or selector to cover. Omit for fullscreen. |\n| `fullscreen` | `boolean` | `true` when `target` is omitted | Cover the viewport. |\n| `body` | `boolean` | `false` | Mount the mask on `body`, positioned over `target`. |\n| `lock` | `boolean` | `false` | Lock page scrolling. |\n| `text` | `string` | — | Caption. |\n| `effect` | same as the component | `'circular'` | Graphic. |\n| `spinner` | `MRenderable` | — | Custom indicator; skips built-in effects when set. |\n| `background` | `string` | — | Mask background. |\n| `customClass` | `string` | — | Extra mask class. |\n| `size` | same as the component | — | Indicator size. |\n| `delay` | `number` | — | Delay before showing (ms). |"
12739
+ },
12740
+ {
12741
+ "id": "theme",
12742
+ "title": "Theme",
12743
+ "body": "Indicator colors use semantic tokens: `--m-color-primary`, `--m-color-success`, `--m-color-warning`, `--m-color-danger`, and `--m-color-text-muted`. The mask defaults to a translucent surface mix. Override it with `background` or `--m-loading-mask-bg`. Fullscreen stacking uses `--m-loading-z-index` (default `--m-z-base + 200`).\n\nLooping motion is disabled under `prefers-reduced-motion: reduce`."
12744
+ },
12745
+ {
12746
+ "id": "accessibility",
12747
+ "title": "Accessibility",
12748
+ "body": "- The indicator uses `role=\"status\"`.\n- The masked region sets `aria-busy`, and covered content is `inert`.\n- Do not rely on motion alone; pass `text` when the wait needs an explanation."
12749
+ }
12750
+ ],
12751
+ "markdown": "---\ntitle: Loading\ncategory: 05 / FEEDBACK\ndescription: Loading indicator and mask, with multiple effects, a region overlay, the v-loading directive, and an imperative service.\n---\n\n# Loading\n\nRegion or fullscreen loading feedback. Render an indicator on its own, cover a block of content, or open a mask on any node with the directive or service.\n\nBuilt-in graphics are a circular spinner, aurora ring, bouncing balls, wave bars, pulse rings, and stardust. The default is the circular spinner (`effect=\"circular\"`). Set `componentDefaults.Loading.effect` to change the global default.\n\nFullscreen masks teleport to `body` so parent `overflow` / `transform` cannot clip them. Only one fullscreen instance stays open at a time.\n\n## Import\n\n```ts\nimport { loading, MLoading, useLoading, vLoading } from 'morya-ui'\n```\n\n`app.use(MoryaUI)` registers `v-loading`. For on-demand usage, import `vLoading` in `<script setup>` and the template can use the directive.\n\n## Effects\n\n```vue preview src=\"./demos/Effects.vue\"\n```\n\n## Region\n\nWrap content with the component, or put `v-loading` on an element. Omit `text` to hide the caption; screen readers still get the locale `loading` string. Use `delay` to avoid a flash on short requests.\n\n```vue preview src=\"./demos/Region.en.vue\"\n```\n\n## Service\n\nWith no `target`, the mask covers the viewport. `close()` plays the leave transition before unmounting, and `setText()` changes the caption. `useLoading()` closes automatically when the caller unmounts.\n\n```vue preview src=\"./demos/Service.en.vue\"\n```\n\n```ts\nconst instance = loading.service({\n text: 'Submitting',\n effect: 'wave',\n lock: true,\n})\ninstance.setText('Almost done')\ninstance.close()\n```\n\nCover one node, or pass a custom indicator:\n\n```ts\nloading.service({\n target: '#panel',\n text: 'Loading',\n})\n\nloading.service({\n spinner: () => h('span', '…'),\n text: 'Custom',\n})\n```\n\n```ts\nconst { open, close } = useLoading({ effect: 'wave' })\nopen({ text: 'Saving' })\nclose()\n```\n\n## Directive\n\n| Form | Description |\n| --- | --- |\n| `v-loading` | A boolean, or an object with `text`, `effect`, `background`, `lock`, `delay`, `spinner`, and related fields. |\n| `v-loading.fullscreen` | Fullscreen mask. |\n| `v-loading.lock` | Lock page scrolling while open. |\n| `v-loading.body` | Mount the mask on `body`, positioned over the element (tracks size changes). |\n| `m-loading-text` | Caption. |\n| `m-loading-effect` | `circular` / `aurora` / `bounce` / `wave` / `pulse` / `stardust`. |\n| `m-loading-background` | Mask background. |\n| `m-loading-custom-class` | Extra class on the mask. |\n| `m-loading-delay` | Delay before showing (ms). |\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `loading` | `boolean` | `true` | Mask visibility when wrapping content or using `fullscreen`. A bare indicator is always shown. |\n| `effect` | `'circular' \\| 'aurora' \\| 'bounce' \\| 'wave' \\| 'pulse' \\| 'stardust'` | `'circular'` | Graphic. Override the default with `componentDefaults.Loading.effect`. |\n| `text` | `string` | — | Caption under the indicator. Hidden when omitted. |\n| `ariaLabel` | `string` | locale `loading` | Accessible name when there is no caption. A caption is used as the name when present. |\n| `size` | `'small' \\| 'large' \\| 'sm' \\| 'md' \\| 'lg'` | — | Indicator scale. |\n| `background` | `string` | — | Mask background, any CSS color. |\n| `customClass` | `string` | — | Extra class on the mask. |\n| `fullscreen` | `boolean` | `false` | Cover the viewport (teleported to `body`). |\n| `lock` | `boolean` | `false` | Prevent page scrolling while visible. |\n| `delay` | `number` | `0` | Delay before showing (ms). |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n## Events\n\nNo custom events.\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Content covered by the mask. |\n| `indicator` | Replaces the indicator inside the mask. Used when there is a default slot or `fullscreen`. |\n\n## Service\n\n`loading.service(options)` returns `{ close, setText }`. `useLoading(defaults)` returns `{ open, close, setText }`.\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `target` | `string \\| HTMLElement` | — | Element or selector to cover. Omit for fullscreen. |\n| `fullscreen` | `boolean` | `true` when `target` is omitted | Cover the viewport. |\n| `body` | `boolean` | `false` | Mount the mask on `body`, positioned over `target`. |\n| `lock` | `boolean` | `false` | Lock page scrolling. |\n| `text` | `string` | — | Caption. |\n| `effect` | same as the component | `'circular'` | Graphic. |\n| `spinner` | `MRenderable` | — | Custom indicator; skips built-in effects when set. |\n| `background` | `string` | — | Mask background. |\n| `customClass` | `string` | — | Extra mask class. |\n| `size` | same as the component | — | Indicator size. |\n| `delay` | `number` | — | Delay before showing (ms). |\n\n## Theme\n\nIndicator colors use semantic tokens: `--m-color-primary`, `--m-color-success`, `--m-color-warning`, `--m-color-danger`, and `--m-color-text-muted`. The mask defaults to a translucent surface mix. Override it with `background` or `--m-loading-mask-bg`. Fullscreen stacking uses `--m-loading-z-index` (default `--m-z-base + 200`).\n\nLooping motion is disabled under `prefers-reduced-motion: reduce`.\n\n## Accessibility\n\n- The indicator uses `role=\"status\"`.\n- The masked region sets `aria-busy`, and covered content is `inert`.\n- Do not rely on motion alone; pass `text` when the wait needs an explanation.\n"
12752
+ }
12753
+ }
12754
+ },
12403
12755
  {
12404
12756
  "id": "MegaMenu",
12405
12757
  "name": "MegaMenu",
@@ -12807,7 +13159,7 @@
12807
13159
  "sectionId": "导航选中",
12808
13160
  "lang": "vue",
12809
13161
  "preview": true,
12810
- "code": "<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: '仪表盘', icon: 'layout-dashboard' },\n { key: 'users', label: '用户', icon: 'users' },\n { key: 'settings', label: '设置', icon: 'settings', disabled: true },\n]\n</script>\n\n<template>\n <div>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n embedded\n @select=\"(item) => console.log('select', item.key)\"\n />\n </div>\n</template>",
13162
+ "code": "<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: '仪表盘', icon: 'layout-dashboard' },\n { key: 'users', label: '用户', icon: 'users' },\n { key: 'settings', label: '设置', icon: 'settings', disabled: true },\n]\n</script>\n\n<template>\n <div class=\"w-[15rem]\">\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n embedded\n @select=\"(item) => console.log('select', item.key)\"\n />\n </div>\n</template>",
12811
13163
  "locale": "zh-CN"
12812
13164
  },
12813
13165
  {
@@ -12843,7 +13195,7 @@
12843
13195
  "sectionId": "嵌入-layout-侧栏",
12844
13196
  "lang": "vue",
12845
13197
  "preview": true,
12846
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: '仪表盘', icon: 'layout-dashboard' },\n {\n key: 'system',\n label: '系统',\n icon: 'settings',\n items: [\n { key: 'users', label: '用户', icon: 'users' },\n { key: 'roles', label: '角色', icon: 'shield' },\n ],\n },\n]\n</script>\n\n<template>\n <MLayout\n style=\"\n height: 14rem;\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutHeader\n bordered\n style=\"\n padding: 0 var(--m-space-4);\n display: flex;\n align-items: center;\n min-height: var(--m-layout-header-height);\n \"\n >\n <strong style=\"color: var(--m-color-primary); font-size: var(--m-font-size-md)\">头部菜单</strong>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :collapsed-width=\"120\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n />\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding: var(--m-space-4)\">\n <p style=\"margin: 0; color: var(--m-color-text-muted); font-size: var(--m-font-size-sm)\">\n 当前选中:<strong style=\"color: var(--m-color-text)\">{{ selectedKey }}</strong>\n </p>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
13198
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: '仪表盘', icon: 'layout-dashboard' },\n {\n key: 'system',\n label: '系统',\n icon: 'settings',\n items: [\n { key: 'users', label: '用户', icon: 'users' },\n { key: 'roles', label: '角色', icon: 'shield' },\n ],\n },\n]\n</script>\n\n<template>\n <MLayout\n style=\"\n height: 14rem;\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutHeader\n bordered\n style=\"\n padding: 0 var(--m-space-4);\n display: flex;\n align-items: center;\n min-height: var(--m-layout-header-height);\n \"\n >\n <strong style=\"color: var(--m-color-primary); font-size: var(--m-font-size-md)\">头部菜单</strong>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :collapsed-width=\"120\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n />\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding: var(--m-space-4)\">\n <p style=\"margin: 0; color: var(--m-color-text-muted); font-size: var(--m-font-size-sm)\">\n 当前选中:<strong style=\"color: var(--m-color-text)\">{{ selectedKey }}</strong>\n </p>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
12847
13199
  "locale": "zh-CN"
12848
13200
  },
12849
13201
  {
@@ -12933,7 +13285,7 @@
12933
13285
  "sectionId": "embed-in-layout-sider",
12934
13286
  "lang": "vue",
12935
13287
  "preview": true,
12936
- "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n {\n key: 'system',\n label: 'System',\n icon: 'settings',\n items: [\n { key: 'users', label: 'Users', icon: 'users' },\n { key: 'roles', label: 'Roles', icon: 'shield' },\n ],\n },\n]\n</script>\n\n<template>\n <MLayout\n style=\"\n height: 14rem;\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutHeader\n bordered\n style=\"\n padding: 0 var(--m-space-4);\n display: flex;\n align-items: center;\n min-height: var(--m-layout-header-height);\n \"\n >\n <strong style=\"color: var(--m-color-primary); font-size: var(--m-font-size-md)\">Morya UI</strong>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :collapsed-width=\"64\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n accordion\n />\n </MLayoutSider>\n <MLayoutContent embedded content-style=\"padding: var(--m-space-4)\">\n <p style=\"margin: 0; color: var(--m-color-text-muted); font-size: var(--m-font-size-sm)\">\n Selected: <strong style=\"color: var(--m-color-text)\">{{ selectedKey }}</strong>\n </p>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
13288
+ "code": "<script setup lang=\"ts\">\nimport {\n MLayout,\n MLayoutContent,\n MLayoutHeader,\n MLayoutSider,\n MMenu,\n} from 'morya-ui'\nimport { ref } from 'vue'\n\nconst collapsed = ref(false)\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n {\n key: 'system',\n label: 'System',\n icon: 'settings',\n items: [\n { key: 'users', label: 'Users', icon: 'users' },\n { key: 'roles', label: 'Roles', icon: 'shield' },\n ],\n },\n]\n</script>\n\n<template>\n <MLayout\n style=\"\n height: 14rem;\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutHeader\n bordered\n style=\"\n padding: 0 var(--m-space-4);\n display: flex;\n align-items: center;\n min-height: var(--m-layout-header-height);\n \"\n >\n <strong style=\"color: var(--m-color-primary); font-size: var(--m-font-size-md)\">Morya UI</strong>\n </MLayoutHeader>\n <MLayout has-sider>\n <MLayoutSider\n v-model:collapsed=\"collapsed\"\n bordered\n show-trigger=\"arrow-circle\"\n collapse-mode=\"width\"\n :collapsed-width=\"64\"\n >\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"64\"\n accordion\n />\n </MLayoutSider>\n <MLayoutContent embedded style=\"padding: var(--m-space-4)\">\n <p style=\"margin: 0; color: var(--m-color-text-muted); font-size: var(--m-font-size-sm)\">\n Selected: <strong style=\"color: var(--m-color-text)\">{{ selectedKey }}</strong>\n </p>\n </MLayoutContent>\n </MLayout>\n </MLayout>\n</template>",
12937
13289
  "locale": "en-US"
12938
13290
  },
12939
13291
  {
@@ -13006,7 +13358,7 @@
13006
13358
  {
13007
13359
  "id": "折叠与飞出层",
13008
13360
  "title": "折叠与飞出层",
13009
- "body": "`collapsed` 隐藏文案,仅保留图标;**每个可折叠展示的菜单项必须提供 `icon`**(否则折叠后几乎空白)。悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。飞出层经 `MPopover` Teleport 到 `body`,不会被侧栏或 `MLayoutSider` 滚动区域裁剪。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n使用 `item.to` 时菜单项会渲染为 `RouterLink` / `<a>`;组件已重置链接的默认蓝色下划线,视觉与普通菜单项一致。\n\n```vue preview src=\"./demos/CollapsedAndFlyout.zh.vue\"\n```"
13361
+ "body": "`collapsed` 隐藏文案,仅保留图标;**每个可折叠展示的菜单项必须提供 `icon`**(否则折叠后几乎空白)。悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。飞出层经 `MPopover` Teleport 到 `body`,不会被侧栏裁剪。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n使用 `item.to` 时菜单项会渲染为 `RouterLink` / `<a>`;组件已重置链接的默认蓝色下划线,视觉与普通菜单项一致。\n\n```vue preview src=\"./demos/CollapsedAndFlyout.zh.vue\"\n```"
13010
13362
  },
13011
13363
  {
13012
13364
  "id": "嵌入-layout-侧栏",
@@ -13054,7 +13406,7 @@
13054
13406
  "body": "<h4 id=\"MenuItem\">MenuItem</h4>\n\n`model` 数组项,支持嵌套:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // 有 vue-router 时用 RouterLink\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\n`key` 未传时用 `label` 作为标识。`separator: true` 时渲染分隔线。更多见 [API 类型](/docs/types)。"
13055
13407
  }
13056
13408
  ],
13057
- "markdown": "---\ntitle: Menu\ncategory: 04 / NAVIGATION\ndescription: 垂直/水平导航菜单,支持多级嵌套、受控选中、手风琴展开与折叠侧栏飞出层。\n---\n\n# Menu\n\n基于 `model` 渲染的**导航菜单**,适合后台侧栏、顶栏导航等场景。支持:\n\n- 多级嵌套 `items` 与受控 `selectedKey`\n- 展开路径自动跟随选中项;`accordion` 手风琴\n- `collapsed` 图标模式 + 右侧飞出子菜单(Popover)\n- 非 popup 时默认 `embedded`,无边框铺满 `MLayoutSider`\n\n> 单层悬停子菜单见 [TieredMenu](/components/TieredMenu);顶栏菜单见 [Menubar](/components/Menubar);操作列表见 [Dropdown](/components/Dropdown)。\n\n## 引入\n\n```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```\n\n## 导航选中\n\n为叶子项设置稳定的 `key`,用 `v-model:selected-key` 与路由同步;点击时触发 `select`。\n\n```vue preview src=\"./demos/Selection.zh.vue\"\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。\n\n## 嵌套子菜单\n\n点击带子项的节点可展开/收起;选中子项时父级会显示 `child-active` 高亮。\n\n```vue preview src=\"./demos/NestedSubmenus.zh.vue\"\n```\n\n## 手风琴与展开控制\n\n`accordion` 同时只保留一个一级子菜单展开。`defaultExpandedKeys` / `v-model:expanded-keys` 可受控展开项;变更 `selectedKey` 时会自动展开其祖先路径。\n\n```vue preview src=\"./demos/AccordionAndExpandedKeys.zh.vue\"\n```\n\n## 折叠与飞出层\n\n`collapsed` 隐藏文案,仅保留图标;**每个可折叠展示的菜单项必须提供 `icon`**(否则折叠后几乎空白)。悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。飞出层经 `MPopover` Teleport 到 `body`,不会被侧栏或 `MLayoutSider` 滚动区域裁剪。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n使用 `item.to` 时菜单项会渲染为 `RouterLink` / `<a>`;组件已重置链接的默认蓝色下划线,视觉与普通菜单项一致。\n\n```vue preview src=\"./demos/CollapsedAndFlyout.zh.vue\"\n```\n\n## 嵌入 Layout 侧栏\n\n推荐结构:**全局 Header + 下方 `has-sider` Layout**。菜单放在 `MLayoutSider` 内,与 `v-model:collapsed` 联动。\n\n```vue preview src=\"./demos/EmbedInLayoutSider.zh.vue\"\n```\n\n## 水平菜单\n\n`mode=\"horizontal\"` 用于顶栏一级导航;子菜单经 `MPopover` 以下拉飞出层展示(Teleport + 主题滚动条),选中后自动关闭。`popup` 模式的主菜单列表同样内置 `MScrollbar`。\n\n```vue preview src=\"./demos/HorizontalMode.zh.vue\"\n```\n\n## 反色(深色侧栏)\n\n`inverted` 配合 `MLayoutSider` 的 `inverted`,用于深色背景侧栏。\n\n```vue preview src=\"./demos/InvertedDarkSider.zh.vue\"\n```\n\n## 弹出模式\n\n`popup` + `v-model` 将菜单作为浮层,默认 Teleport 到 `body` 并相对**默认插槽触发器**定位(无插槽时回退到最后一次指针位置)。点击外部或选中叶子项后关闭。\n\n```vue preview src=\"./demos/PopupMode.zh.vue\"\n```\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `model` | `MenuItem[]` | — | 菜单项,可嵌套 `items`。 |\n| `popup` | `boolean` | `false` | 浮层模式;配合 `v-model` 控制显隐。 |\n| `modelValue` | `boolean` | `false` | popup 可见性(`v-model`)。 |\n| `placement` | `'bottom-start' \\| 'bottom-end' \\| 'top-start' \\| 'top-end'` | `'bottom-start'` | popup 相对触发器的位置。 |\n| `selectedKey` | `string \\| null` | `null` | 当前选中项 key(`v-model:selected-key`)。 |\n| `collapsed` | `boolean` | `false` | 图标模式;子菜单以右侧飞出层展示。 |\n| `collapsedWidth` | `number` | `80` | 折叠宽度(px),用于居中图标。 |\n| `indent` | `number` | `12` | 每层额外左内边距(px)。 |\n| `rootIndent` | `number` | `16` | 根级左内边距(px)。 |\n| `accordion` | `boolean` | `false` | 手风琴:同时只展开一个一级子菜单。 |\n| `defaultExpandedKeys` | `string[]` | `[]` | 默认展开的 submenu keys。 |\n| `expandedKeys` | `string[]` | — | 受控展开 keys(`v-model:expanded-keys`)。 |\n| `defaultExpandAll` | `boolean` | `false` | 初始展开全部子菜单。 |\n| `mode` | `'vertical' \\| 'horizontal'` | `'vertical'` | 布局方向。 |\n| `inverted` | `boolean` | `false` | 反色样式,适合深色侧栏。 |\n| `embedded` | `boolean` | `!popup` | 嵌入布局:去边框与最小宽度。 |\n| `teleport` | `boolean` | `true` | popup 时 Teleport 到 `appendTo`。 |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Teleport 目标;未传时使用 ConfigProvider。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `update:modelValue` | `boolean` | popup 可见性变化。 |\n| `update:selectedKey` | `string \\| null` | 选中项变化。 |\n| `update:expandedKeys` | `string[]` | 展开项变化。 |\n| `select` | `MenuItem` | 点击叶子项(非 disabled / separator)。 |\n\n## Slots\n\n| 插槽 | 说明 |\n| --- | --- |\n| `default` | popup 模式的触发器锚点(如按钮);菜单相对其定位。 |\n\n## MenuItem\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `key` | `string` | 唯一标识;未传时使用 `label`。 |\n| `label` | `string` | 展示文本。 |\n| `icon` | `string` | [Tabler 图标名](/components/Icon) 或字符。 |\n| `command` | `() => void` | 点击回调(与 `select` 事件同时触发)。 |\n| `disabled` | `boolean` | 禁用。 |\n| `separator` | `boolean` | 分隔线(忽略其他字段)。 |\n| `items` | `MenuItem[]` | 子菜单。 |\n\n## 类型\n\n<h4 id=\"MenuItem\">MenuItem</h4>\n\n`model` 数组项,支持嵌套:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // 有 vue-router 时用 RouterLink\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\n`key` 未传时用 `label` 作为标识。`separator: true` 时渲染分隔线。更多见 [API 类型](/docs/types)。\n"
13409
+ "markdown": "---\ntitle: Menu\ncategory: 04 / NAVIGATION\ndescription: 垂直/水平导航菜单,支持多级嵌套、受控选中、手风琴展开与折叠侧栏飞出层。\n---\n\n# Menu\n\n基于 `model` 渲染的**导航菜单**,适合后台侧栏、顶栏导航等场景。支持:\n\n- 多级嵌套 `items` 与受控 `selectedKey`\n- 展开路径自动跟随选中项;`accordion` 手风琴\n- `collapsed` 图标模式 + 右侧飞出子菜单(Popover)\n- 非 popup 时默认 `embedded`,无边框铺满 `MLayoutSider`\n\n> 单层悬停子菜单见 [TieredMenu](/components/TieredMenu);顶栏菜单见 [Menubar](/components/Menubar);操作列表见 [Dropdown](/components/Dropdown)。\n\n## 引入\n\n```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```\n\n## 导航选中\n\n为叶子项设置稳定的 `key`,用 `v-model:selected-key` 与路由同步;点击时触发 `select`。\n\n```vue preview src=\"./demos/Selection.zh.vue\"\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。\n\n## 嵌套子菜单\n\n点击带子项的节点可展开/收起;选中子项时父级会显示 `child-active` 高亮。\n\n```vue preview src=\"./demos/NestedSubmenus.zh.vue\"\n```\n\n## 手风琴与展开控制\n\n`accordion` 同时只保留一个一级子菜单展开。`defaultExpandedKeys` / `v-model:expanded-keys` 可受控展开项;变更 `selectedKey` 时会自动展开其祖先路径。\n\n```vue preview src=\"./demos/AccordionAndExpandedKeys.zh.vue\"\n```\n\n## 折叠与飞出层\n\n`collapsed` 隐藏文案,仅保留图标;**每个可折叠展示的菜单项必须提供 `icon`**(否则折叠后几乎空白)。悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。飞出层经 `MPopover` Teleport 到 `body`,不会被侧栏裁剪。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n使用 `item.to` 时菜单项会渲染为 `RouterLink` / `<a>`;组件已重置链接的默认蓝色下划线,视觉与普通菜单项一致。\n\n```vue preview src=\"./demos/CollapsedAndFlyout.zh.vue\"\n```\n\n## 嵌入 Layout 侧栏\n\n推荐结构:**全局 Header + 下方 `has-sider` Layout**。菜单放在 `MLayoutSider` 内,与 `v-model:collapsed` 联动。\n\n```vue preview src=\"./demos/EmbedInLayoutSider.zh.vue\"\n```\n\n## 水平菜单\n\n`mode=\"horizontal\"` 用于顶栏一级导航;子菜单经 `MPopover` 以下拉飞出层展示(Teleport + 主题滚动条),选中后自动关闭。`popup` 模式的主菜单列表同样内置 `MScrollbar`。\n\n```vue preview src=\"./demos/HorizontalMode.zh.vue\"\n```\n\n## 反色(深色侧栏)\n\n`inverted` 配合 `MLayoutSider` 的 `inverted`,用于深色背景侧栏。\n\n```vue preview src=\"./demos/InvertedDarkSider.zh.vue\"\n```\n\n## 弹出模式\n\n`popup` + `v-model` 将菜单作为浮层,默认 Teleport 到 `body` 并相对**默认插槽触发器**定位(无插槽时回退到最后一次指针位置)。点击外部或选中叶子项后关闭。\n\n```vue preview src=\"./demos/PopupMode.zh.vue\"\n```\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `model` | `MenuItem[]` | — | 菜单项,可嵌套 `items`。 |\n| `popup` | `boolean` | `false` | 浮层模式;配合 `v-model` 控制显隐。 |\n| `modelValue` | `boolean` | `false` | popup 可见性(`v-model`)。 |\n| `placement` | `'bottom-start' \\| 'bottom-end' \\| 'top-start' \\| 'top-end'` | `'bottom-start'` | popup 相对触发器的位置。 |\n| `selectedKey` | `string \\| null` | `null` | 当前选中项 key(`v-model:selected-key`)。 |\n| `collapsed` | `boolean` | `false` | 图标模式;子菜单以右侧飞出层展示。 |\n| `collapsedWidth` | `number` | `80` | 折叠宽度(px),用于居中图标。 |\n| `indent` | `number` | `12` | 每层额外左内边距(px)。 |\n| `rootIndent` | `number` | `16` | 根级左内边距(px)。 |\n| `accordion` | `boolean` | `false` | 手风琴:同时只展开一个一级子菜单。 |\n| `defaultExpandedKeys` | `string[]` | `[]` | 默认展开的 submenu keys。 |\n| `expandedKeys` | `string[]` | — | 受控展开 keys(`v-model:expanded-keys`)。 |\n| `defaultExpandAll` | `boolean` | `false` | 初始展开全部子菜单。 |\n| `mode` | `'vertical' \\| 'horizontal'` | `'vertical'` | 布局方向。 |\n| `inverted` | `boolean` | `false` | 反色样式,适合深色侧栏。 |\n| `embedded` | `boolean` | `!popup` | 嵌入布局:去边框与最小宽度。 |\n| `teleport` | `boolean` | `true` | popup 时 Teleport 到 `appendTo`。 |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Teleport 目标;未传时使用 ConfigProvider。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `update:modelValue` | `boolean` | popup 可见性变化。 |\n| `update:selectedKey` | `string \\| null` | 选中项变化。 |\n| `update:expandedKeys` | `string[]` | 展开项变化。 |\n| `select` | `MenuItem` | 点击叶子项(非 disabled / separator)。 |\n\n## Slots\n\n| 插槽 | 说明 |\n| --- | --- |\n| `default` | popup 模式的触发器锚点(如按钮);菜单相对其定位。 |\n\n## MenuItem\n\n| 字段 | 类型 | 说明 |\n| --- | --- | --- |\n| `key` | `string` | 唯一标识;未传时使用 `label`。 |\n| `label` | `string` | 展示文本。 |\n| `icon` | `string` | [Tabler 图标名](/components/Icon) 或字符。 |\n| `command` | `() => void` | 点击回调(与 `select` 事件同时触发)。 |\n| `disabled` | `boolean` | 禁用。 |\n| `separator` | `boolean` | 分隔线(忽略其他字段)。 |\n| `items` | `MenuItem[]` | 子菜单。 |\n\n## 类型\n\n<h4 id=\"MenuItem\">MenuItem</h4>\n\n`model` 数组项,支持嵌套:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // 有 vue-router 时用 RouterLink\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\n`key` 未传时用 `label` 作为标识。`separator: true` 时渲染分隔线。更多见 [API 类型](/docs/types)。\n"
13058
13410
  },
13059
13411
  "en-US": {
13060
13412
  "title": "Menu",
@@ -13088,7 +13440,7 @@
13088
13440
  {
13089
13441
  "id": "collapsed-flyout",
13090
13442
  "title": "Collapsed & flyout",
13091
- "body": "`collapsed` hides labels and keeps icons. Hover shows an `MTooltip` with the label; groups also open a right flyout (`.m-menu--flyout`) via `MPopover` teleported to `body`, so it is not clipped by sider scroll regions. Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview src=\"./demos/CollapsedAndFlyout.en.vue\"\n```"
13443
+ "body": "`collapsed` hides labels and keeps icons. Hover shows an `MTooltip` with the label; groups also open a right flyout (`.m-menu--flyout`) via `MPopover` teleported to `body`, so it is not clipped by the sider. Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview src=\"./demos/CollapsedAndFlyout.en.vue\"\n```"
13092
13444
  },
13093
13445
  {
13094
13446
  "id": "embed-in-layout-sider",
@@ -13136,7 +13488,7 @@
13136
13488
  "body": "<h4 id=\"MenuItem\">MenuItem</h4>\n\nEach entry in `model`; supports nesting:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // RouterLink when vue-router is installed\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\nWhen `key` is omitted, `label` is used as the identifier. `separator: true` renders a divider. See also [API types](/docs/types)."
13137
13489
  }
13138
13490
  ],
13139
- "markdown": "---\ntitle: Menu\ncategory: 04 / NAVIGATION\ndescription: Vertical/horizontal navigation menu with nested items, controlled selection, accordion, and collapsed flyout submenus.\n---\n\n# Menu\n\nNavigation menu rendered from a `model`. Typical uses: admin sidebar, top navigation.\n\n- Nested `items` with controlled `selectedKey`\n- Auto-expand ancestor path when selection changes; optional `accordion`\n- `collapsed` icon rail with right-side flyout submenus (Popover)\n- Non-popup menus default to `embedded` (borderless, full-width in `MLayoutSider`)\n\n> One-level hover submenus: [TieredMenu](/components/TieredMenu). Top bar: [Menubar](/components/Menubar). Action lists: [Dropdown](/components/Dropdown).\n\n## Import\n\n```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```\n\n## Selection\n\nGive leaf items stable `key` values; sync with routing via `v-model:selected-key`. Emits `select` on click.\n\n```vue preview src=\"./demos/Selection.en.vue\"\n```\n\nIf `key` is omitted, `label` is used as fallback. Prefer explicit keys in production.\n\n## Nested submenus\n\nClick a group to expand/collapse. When a child is selected, the parent shows `child-active` styling.\n\n```vue preview src=\"./demos/NestedSubmenus.en.vue\"\n```\n\n## Accordion & expanded keys\n\n`accordion` keeps at most one top-level group open. Use `defaultExpandedKeys` or `v-model:expanded-keys` for controlled expansion. Changing `selectedKey` auto-expands its ancestor path.\n\n```vue preview src=\"./demos/AccordionAndExpandedKeys.en.vue\"\n```\n\n## Collapsed & flyout\n\n`collapsed` hides labels and keeps icons. Hover shows an `MTooltip` with the label; groups also open a right flyout (`.m-menu--flyout`) via `MPopover` teleported to `body`, so it is not clipped by sider scroll regions. Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview src=\"./demos/CollapsedAndFlyout.en.vue\"\n```\n\n## Embed in Layout sider\n\nRecommended shell: **global Header + inner `has-sider` Layout**. Bind menu `collapsed` to `MLayoutSider`.\n\n```vue preview src=\"./demos/EmbedInLayoutSider.en.vue\"\n```\n\n## Horizontal mode\n\n`mode=\"horizontal\"` for top nav bars. Submenus open in a `MPopover` dropdown flyout (teleported, themed scrollbar) and close after selection. Popup mode root menus also use built-in `MScrollbar`.\n\n```vue preview src=\"./demos/HorizontalMode.en.vue\"\n```\n\n## Inverted (dark sider)\n\nUse `inverted` with `MLayoutSider`'s `inverted` on dark backgrounds.\n\n```vue preview src=\"./demos/InvertedDarkSider.en.vue\"\n```\n\n## Popup mode\n\n`popup` + `v-model` renders a floating menu, teleported to `body` by default and positioned against the **default-slot trigger** (falls back to the last pointer position when no slot). Closes on outside click or leaf selection.\n\n```vue preview src=\"./demos/PopupMode.en.vue\"\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `model` | `MenuItem[]` | — | Menu items; may nest `items`. |\n| `popup` | `boolean` | `false` | Overlay mode; use with `v-model`. |\n| `modelValue` | `boolean` | `false` | Popup visibility (`v-model`). |\n| `placement` | `'bottom-start' \\| 'bottom-end' \\| 'top-start' \\| 'top-end'` | `'bottom-start'` | Popup position relative to the trigger. |\n| `selectedKey` | `string \\| null` | `null` | Selected item key (`v-model:selected-key`). |\n| `collapsed` | `boolean` | `false` | Icon-only; submenus in right flyout. |\n| `collapsedWidth` | `number` | `80` | Collapsed width (px) for icon centering. |\n| `indent` | `number` | `12` | Extra padding-left per level (px). |\n| `rootIndent` | `number` | `16` | Root item padding-left (px). |\n| `accordion` | `boolean` | `false` | Only one top-level submenu open at a time. |\n| `defaultExpandedKeys` | `string[]` | `[]` | Initially expanded submenu keys. |\n| `expandedKeys` | `string[]` | — | Controlled expanded keys (`v-model:expanded-keys`). |\n| `defaultExpandAll` | `boolean` | `false` | Expand all submenus initially. |\n| `mode` | `'vertical' \\| 'horizontal'` | `'vertical'` | Layout direction. |\n| `inverted` | `boolean` | `false` | Inverted colors for dark sider. |\n| `embedded` | `boolean` | `!popup` | Embed in layout (no border/min-width). |\n| `teleport` | `boolean` | `true` | Teleport popup to `appendTo`. |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Teleport target; falls back to ConfigProvider. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `update:modelValue` | `boolean` | Popup visibility changed. |\n| `update:selectedKey` | `string \\| null` | Selected item changed. |\n| `update:expandedKeys` | `string[]` | Expanded keys changed. |\n| `select` | `MenuItem` | Leaf clicked (not disabled / separator). |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Popup trigger anchor (e.g. a button); menu positions against it. |\n\n## MenuItem\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `key` | `string` | Unique id; falls back to `label`. |\n| `label` | `string` | Display text. |\n| `icon` | `string` | [Tabler icon name](/components/Icon) or character. |\n| `command` | `() => void` | Click handler (also emits `select`). |\n| `disabled` | `boolean` | Disabled state. |\n| `separator` | `boolean` | Separator line (ignores other fields). |\n| `items` | `MenuItem[]` | Child menu items. |\n\n## Types\n\n<h4 id=\"MenuItem\">MenuItem</h4>\n\nEach entry in `model`; supports nesting:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // RouterLink when vue-router is installed\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\nWhen `key` is omitted, `label` is used as the identifier. `separator: true` renders a divider. See also [API types](/docs/types).\n"
13491
+ "markdown": "---\ntitle: Menu\ncategory: 04 / NAVIGATION\ndescription: Vertical/horizontal navigation menu with nested items, controlled selection, accordion, and collapsed flyout submenus.\n---\n\n# Menu\n\nNavigation menu rendered from a `model`. Typical uses: admin sidebar, top navigation.\n\n- Nested `items` with controlled `selectedKey`\n- Auto-expand ancestor path when selection changes; optional `accordion`\n- `collapsed` icon rail with right-side flyout submenus (Popover)\n- Non-popup menus default to `embedded` (borderless, full-width in `MLayoutSider`)\n\n> One-level hover submenus: [TieredMenu](/components/TieredMenu). Top bar: [Menubar](/components/Menubar). Action lists: [Dropdown](/components/Dropdown).\n\n## Import\n\n```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```\n\n## Selection\n\nGive leaf items stable `key` values; sync with routing via `v-model:selected-key`. Emits `select` on click.\n\n```vue preview src=\"./demos/Selection.en.vue\"\n```\n\nIf `key` is omitted, `label` is used as fallback. Prefer explicit keys in production.\n\n## Nested submenus\n\nClick a group to expand/collapse. When a child is selected, the parent shows `child-active` styling.\n\n```vue preview src=\"./demos/NestedSubmenus.en.vue\"\n```\n\n## Accordion & expanded keys\n\n`accordion` keeps at most one top-level group open. Use `defaultExpandedKeys` or `v-model:expanded-keys` for controlled expansion. Changing `selectedKey` auto-expands its ancestor path.\n\n```vue preview src=\"./demos/AccordionAndExpandedKeys.en.vue\"\n```\n\n## Collapsed & flyout\n\n`collapsed` hides labels and keeps icons. Hover shows an `MTooltip` with the label; groups also open a right flyout (`.m-menu--flyout`) via `MPopover` teleported to `body`, so it is not clipped by the sider. Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview src=\"./demos/CollapsedAndFlyout.en.vue\"\n```\n\n## Embed in Layout sider\n\nRecommended shell: **global Header + inner `has-sider` Layout**. Bind menu `collapsed` to `MLayoutSider`.\n\n```vue preview src=\"./demos/EmbedInLayoutSider.en.vue\"\n```\n\n## Horizontal mode\n\n`mode=\"horizontal\"` for top nav bars. Submenus open in a `MPopover` dropdown flyout (teleported, themed scrollbar) and close after selection. Popup mode root menus also use built-in `MScrollbar`.\n\n```vue preview src=\"./demos/HorizontalMode.en.vue\"\n```\n\n## Inverted (dark sider)\n\nUse `inverted` with `MLayoutSider`'s `inverted` on dark backgrounds.\n\n```vue preview src=\"./demos/InvertedDarkSider.en.vue\"\n```\n\n## Popup mode\n\n`popup` + `v-model` renders a floating menu, teleported to `body` by default and positioned against the **default-slot trigger** (falls back to the last pointer position when no slot). Closes on outside click or leaf selection.\n\n```vue preview src=\"./demos/PopupMode.en.vue\"\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `model` | `MenuItem[]` | — | Menu items; may nest `items`. |\n| `popup` | `boolean` | `false` | Overlay mode; use with `v-model`. |\n| `modelValue` | `boolean` | `false` | Popup visibility (`v-model`). |\n| `placement` | `'bottom-start' \\| 'bottom-end' \\| 'top-start' \\| 'top-end'` | `'bottom-start'` | Popup position relative to the trigger. |\n| `selectedKey` | `string \\| null` | `null` | Selected item key (`v-model:selected-key`). |\n| `collapsed` | `boolean` | `false` | Icon-only; submenus in right flyout. |\n| `collapsedWidth` | `number` | `80` | Collapsed width (px) for icon centering. |\n| `indent` | `number` | `12` | Extra padding-left per level (px). |\n| `rootIndent` | `number` | `16` | Root item padding-left (px). |\n| `accordion` | `boolean` | `false` | Only one top-level submenu open at a time. |\n| `defaultExpandedKeys` | `string[]` | `[]` | Initially expanded submenu keys. |\n| `expandedKeys` | `string[]` | — | Controlled expanded keys (`v-model:expanded-keys`). |\n| `defaultExpandAll` | `boolean` | `false` | Expand all submenus initially. |\n| `mode` | `'vertical' \\| 'horizontal'` | `'vertical'` | Layout direction. |\n| `inverted` | `boolean` | `false` | Inverted colors for dark sider. |\n| `embedded` | `boolean` | `!popup` | Embed in layout (no border/min-width). |\n| `teleport` | `boolean` | `true` | Teleport popup to `appendTo`. |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Teleport target; falls back to ConfigProvider. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `update:modelValue` | `boolean` | Popup visibility changed. |\n| `update:selectedKey` | `string \\| null` | Selected item changed. |\n| `update:expandedKeys` | `string[]` | Expanded keys changed. |\n| `select` | `MenuItem` | Leaf clicked (not disabled / separator). |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Popup trigger anchor (e.g. a button); menu positions against it. |\n\n## MenuItem\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `key` | `string` | Unique id; falls back to `label`. |\n| `label` | `string` | Display text. |\n| `icon` | `string` | [Tabler icon name](/components/Icon) or character. |\n| `command` | `() => void` | Click handler (also emits `select`). |\n| `disabled` | `boolean` | Disabled state. |\n| `separator` | `boolean` | Separator line (ignores other fields). |\n| `items` | `MenuItem[]` | Child menu items. |\n\n## Types\n\n<h4 id=\"MenuItem\">MenuItem</h4>\n\nEach entry in `model`; supports nesting:\n\n```ts\ninterface MenuItem {\n key?: string\n label?: string\n icon?: string\n to?: string | RouteLocationRaw // RouterLink when vue-router is installed\n command?: () => void\n disabled?: boolean\n separator?: boolean\n items?: MenuItem[]\n}\n```\n\nWhen `key` is omitted, `label` is used as the identifier. `separator: true` renders a divider. See also [API types](/docs/types).\n"
13140
13492
  }
13141
13493
  }
13142
13494
  },
@@ -13447,7 +13799,7 @@
13447
13799
  {
13448
13800
  "id": "overview",
13449
13801
  "title": "",
13450
- "body": "# Message\n\n从窗口顶部正中滑入的轻量提示(可通过 `placement` 改到六向位置),适合简短操作反馈。推荐用 `message` API;也可挂载 `<MMessage />` 作为自定义挂载点。\n\n与 [Toast](/components/Toast) 的分工:\n\n- **Message(默认)**:轻量单行反馈,默认顶部居中,无标题/详情。**大多数 CRUD / 保存 / 删除回执应使用此项。**\n- **Toast**:四角通知,带 `summary` / `detail`;仅在有补充说明或异步通知感时使用。\n- **`<MMessage>` 组件**:页面内嵌条,用于表单区常驻错误(见下方「内嵌 Message」)。\n\n> AI / 业务代码选型细则见 [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md)。\n\n**快速判断**:只有一句话 → `message.success('已保存')`;有标题 + 详情 → `toast.success({ summary, detail })`。"
13802
+ "body": "# Message\n\n从窗口顶部正中滑入的轻量提示(可通过 `placement` 改到六向位置),适合简短操作反馈。推荐用 `message` API;也可挂载 `<MMessage />` 作为自定义挂载点。\n\n与 [Toast](/components/Toast) 的分工:\n\n- **Message(默认)**:轻量单行反馈,默认顶部居中,无标题/详情。**大多数 CRUD / 保存 / 删除回执应使用此项。**\n- **Toast**:四角通知,带 `summary` / `detail`;仅在有补充说明或异步通知感时使用。\n- **`<MMessage>` 组件**:可选的 message 服务宿主(自定义 `appendTo` / `placement`)。它不是页面内嵌 Alert;表单常驻错误用字段 `errorMessage`,或 token 样式的 `role=\"alert\"`。\n\n> AI / 业务代码选型细则见 [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md)。\n\n**快速判断**:只有一句话 → `message.success('已保存')`;有标题 + 详情 → `toast.success({ summary, detail })`。"
13451
13803
  },
13452
13804
  {
13453
13805
  "id": "引入",
@@ -13495,7 +13847,7 @@
13495
13847
  "body": "<h4 id=\"MessageItem\">MessageItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface MessageItem {\n id: string | number\n content: MRenderable\n severity?: MessageSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n icon?: boolean\n}\n```"
13496
13848
  }
13497
13849
  ],
13498
- "markdown": "---\ntitle: Message\ncategory: 05 / FEEDBACK\ndescription: 顶部居中浮层提示,支持 API 调用。\n---\n\n# Message\n\n从窗口顶部正中滑入的轻量提示(可通过 `placement` 改到六向位置),适合简短操作反馈。推荐用 `message` API;也可挂载 `<MMessage />` 作为自定义挂载点。\n\n与 [Toast](/components/Toast) 的分工:\n\n- **Message(默认)**:轻量单行反馈,默认顶部居中,无标题/详情。**大多数 CRUD / 保存 / 删除回执应使用此项。**\n- **Toast**:四角通知,带 `summary` / `detail`;仅在有补充说明或异步通知感时使用。\n- **`<MMessage>` 组件**:页面内嵌条,用于表单区常驻错误(见下方「内嵌 Message」)。\n\n> AI / 业务代码选型细则见 [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md)。\n\n**快速判断**:只有一句话 → `message.success('已保存')`;有标题 + 详情 → `toast.success({ summary, detail })`。\n\n## 引入\n\n```ts\nimport { message, MMessage, useMessage } from 'morya-ui'\n```\n\n## API\n\n首次调用时会自动挂载浮层容器,无需在模板里放置组件。\n\n```vue preview src=\"./demos/Api.zh.vue\"\n```\n\n## 自定义内容\n\n`content`(以及 Toast 的 `summary` / `detail`)支持字符串、`h()` 返回的 VNode、组件,或 `() => VNode` 工厂函数。\n\n```vue preview src=\"./demos/CustomContent.zh.vue\"\n```\n\n## Methods\n\n| 方法 | 说明 |\n| --- | --- |\n| `message.success(content \\| options)` | 成功提示 |\n| `message.info(content \\| options)` | 信息提示 |\n| `message.warn(content \\| options)` | 警告提示(`warning` 同义) |\n| `message.error(content \\| options)` | 错误提示 |\n| `message.open(content \\| options)` | 自定义打开 |\n| `message.close(id?)` | 关闭指定 / 全部 |\n| `message.closeAll()` / `message.destroyAll()` | 关闭全部(二者等价) |\n| `message.config({ placement, max })` | 宿主位置与并发上限 |\n\n返回值:`{ id, close }`。\n\n### MessageOptions\n\n| 字段 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `content` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | 正文;也可把可渲染值直接当作入参 |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| 'secondary' \\| 'contrast'` | `'info'` | 语义色 |\n| `closable` | `boolean` | `false` | 显示关闭按钮 |\n| `life` | `number` | `3000` | 自动关闭毫秒;`0` 不自动关闭 |\n| `icon` | `boolean` | `true` | 显示语义图标 |\n| `id` | `string \\| number` | 自动生成 | 唯一键 |\n\n## 可选宿主\n\n需要自定义 `appendTo` 时,可在应用根部放置:\n\n```vue\n<MMessage append-to=\"body\" />\n```\n\n存在手动宿主时,API 不会再自动挂载第二份。\n\n## Props(`MMessage`)\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `teleport` | `boolean` | `true` | 是否 Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | 挂载目标 |\n| `placement` | `'top' \\| 'top-left' \\| 'top-right' \\| 'bottom' \\| 'bottom-left' \\| 'bottom-right'` | `'top'` | 宿主位置 |\n| `max` | `number` | — | 同时可见条数;超出丢掉最旧一条 |\n| `auto` | `boolean` | — | — |\n| `messages` | `MessageItem[]` | — | — |\n\n## Events\n\n`<MMessage />` 宿主本身无 Vue 事件;请通过 `message.*` API 的返回值 `{ id, close }` 管理生命周期。\n\n## Slots\n\n无插槽;通过 `message.*` API 注入内容。\n\n## 类型\n\n<h4 id=\"MessageItem\">MessageItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface MessageItem {\n id: string | number\n content: MRenderable\n severity?: MessageSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n icon?: boolean\n}\n```\n"
13850
+ "markdown": "---\ntitle: Message\ncategory: 05 / FEEDBACK\ndescription: 顶部居中浮层提示,支持 API 调用。\n---\n\n# Message\n\n从窗口顶部正中滑入的轻量提示(可通过 `placement` 改到六向位置),适合简短操作反馈。推荐用 `message` API;也可挂载 `<MMessage />` 作为自定义挂载点。\n\n与 [Toast](/components/Toast) 的分工:\n\n- **Message(默认)**:轻量单行反馈,默认顶部居中,无标题/详情。**大多数 CRUD / 保存 / 删除回执应使用此项。**\n- **Toast**:四角通知,带 `summary` / `detail`;仅在有补充说明或异步通知感时使用。\n- **`<MMessage>` 组件**:可选的 message 服务宿主(自定义 `appendTo` / `placement`)。它不是页面内嵌 Alert;表单常驻错误用字段 `errorMessage`,或 token 样式的 `role=\"alert\"`。\n\n> AI / 业务代码选型细则见 [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md)。\n\n**快速判断**:只有一句话 → `message.success('已保存')`;有标题 + 详情 → `toast.success({ summary, detail })`。\n\n## 引入\n\n```ts\nimport { message, MMessage, useMessage } from 'morya-ui'\n```\n\n## API\n\n首次调用时会自动挂载浮层容器,无需在模板里放置组件。\n\n```vue preview src=\"./demos/Api.zh.vue\"\n```\n\n## 自定义内容\n\n`content`(以及 Toast 的 `summary` / `detail`)支持字符串、`h()` 返回的 VNode、组件,或 `() => VNode` 工厂函数。\n\n```vue preview src=\"./demos/CustomContent.zh.vue\"\n```\n\n## Methods\n\n| 方法 | 说明 |\n| --- | --- |\n| `message.success(content \\| options)` | 成功提示 |\n| `message.info(content \\| options)` | 信息提示 |\n| `message.warn(content \\| options)` | 警告提示(`warning` 同义) |\n| `message.error(content \\| options)` | 错误提示 |\n| `message.open(content \\| options)` | 自定义打开 |\n| `message.close(id?)` | 关闭指定 / 全部 |\n| `message.closeAll()` / `message.destroyAll()` | 关闭全部(二者等价) |\n| `message.config({ placement, max })` | 宿主位置与并发上限 |\n\n返回值:`{ id, close }`。\n\n### MessageOptions\n\n| 字段 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `content` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | 正文;也可把可渲染值直接当作入参 |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| 'secondary' \\| 'contrast'` | `'info'` | 语义色 |\n| `closable` | `boolean` | `false` | 显示关闭按钮 |\n| `life` | `number` | `3000` | 自动关闭毫秒;`0` 不自动关闭 |\n| `icon` | `boolean` | `true` | 显示语义图标 |\n| `id` | `string \\| number` | 自动生成 | 唯一键 |\n\n## 可选宿主\n\n需要自定义 `appendTo` 时,可在应用根部放置:\n\n```vue\n<MMessage append-to=\"body\" />\n```\n\n存在手动宿主时,API 不会再自动挂载第二份。\n\n## Props(`MMessage`)\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `teleport` | `boolean` | `true` | 是否 Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | 挂载目标 |\n| `placement` | `'top' \\| 'top-left' \\| 'top-right' \\| 'bottom' \\| 'bottom-left' \\| 'bottom-right'` | `'top'` | 宿主位置 |\n| `max` | `number` | — | 同时可见条数;超出丢掉最旧一条 |\n| `auto` | `boolean` | — | — |\n| `messages` | `MessageItem[]` | — | — |\n\n## Events\n\n`<MMessage />` 宿主本身无 Vue 事件;请通过 `message.*` API 的返回值 `{ id, close }` 管理生命周期。\n\n## Slots\n\n无插槽;通过 `message.*` API 注入内容。\n\n## 类型\n\n<h4 id=\"MessageItem\">MessageItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface MessageItem {\n id: string | number\n content: MRenderable\n severity?: MessageSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n icon?: boolean\n}\n```\n"
13499
13851
  },
13500
13852
  "en-US": {
13501
13853
  "title": "Message",
@@ -13504,7 +13856,7 @@
13504
13856
  {
13505
13857
  "id": "overview",
13506
13858
  "title": "",
13507
- "body": "# Message\n\nA lightweight notice that slides in from the top center by default (`placement` can move it). Prefer the `message` API; you can also mount `<MMessage />` as a custom host.\n\nVs [Toast](/components/Toast):\n\n- **Message (default)**: short single-line feedback; no title/detail. Use for most CRUD / save / delete confirmations.\n- **Toast**: corner notifications with `summary` / `detail`; use only when supplementary detail is needed.\n- **`<MMessage>` component**: inline banner for persistent form/auth errors.\n\n> Selection guide: [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md).\n\n**Rule of thumb**: one short sentence → `message.success('Saved')`; title + detail → `toast.success({ summary, detail })`."
13859
+ "body": "# Message\n\nA lightweight notice that slides in from the top center by default (`placement` can move it). Prefer the `message` API; you can also mount `<MMessage />` as a custom host.\n\nVs [Toast](/components/Toast):\n\n- **Message (default)**: short single-line feedback; no title/detail. Use for most CRUD / save / delete confirmations.\n- **Toast**: corner notifications with `summary` / `detail`; use only when supplementary detail is needed.\n- **`<MMessage>` component**: optional host for the `message` service (custom `appendTo` / `placement`). It is not an inline alert; persistent form errors use field `errorMessage` or a token-styled `role=\"alert\"`.\n\n> Selection guide: [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md).\n\n**Rule of thumb**: one short sentence → `message.success('Saved')`; title + detail → `toast.success({ summary, detail })`."
13508
13860
  },
13509
13861
  {
13510
13862
  "id": "import",
@@ -13547,7 +13899,7 @@
13547
13899
  "body": "No slots; content is injected through the `message.*` API."
13548
13900
  }
13549
13901
  ],
13550
- "markdown": "---\ntitle: Message\ncategory: 05 / FEEDBACK\ndescription: Top-center floating notice with an imperative API.\n---\n\n# Message\n\nA lightweight notice that slides in from the top center by default (`placement` can move it). Prefer the `message` API; you can also mount `<MMessage />` as a custom host.\n\nVs [Toast](/components/Toast):\n\n- **Message (default)**: short single-line feedback; no title/detail. Use for most CRUD / save / delete confirmations.\n- **Toast**: corner notifications with `summary` / `detail`; use only when supplementary detail is needed.\n- **`<MMessage>` component**: inline banner for persistent form/auth errors.\n\n> Selection guide: [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md).\n\n**Rule of thumb**: one short sentence → `message.success('Saved')`; title + detail → `toast.success({ summary, detail })`.\n\n## Import\n\n```ts\nimport { message, MMessage, useMessage } from 'morya-ui'\n```\n\n## API\n\nThe first call auto-mounts a floating host; no template component is required.\n\n```vue preview src=\"./demos/Api.en.vue\"\n```\n\n## Custom content\n\n`content` (and Toast `summary` / `detail`) accepts a string, a VNode from `h()`, a component, or a `() => VNode` factory.\n\n```vue preview src=\"./demos/CustomContent.en.vue\"\n```\n\n## Methods\n\n| Method | Description |\n| --- | --- |\n| `message.success(content \\| options)` | Success |\n| `message.info(content \\| options)` | Info |\n| `message.warn(content \\| options)` | Warn (`warning` alias) |\n| `message.error(content \\| options)` | Error |\n| `message.open(content \\| options)` | Open with options |\n| `message.close(id?)` | Close one / all |\n| `message.closeAll()` / `message.destroyAll()` | Close all (aliases of each other) |\n| `message.config({ placement, max })` | Host placement and concurrency cap |\n\nReturns `{ id, close }`.\n\n### MessageOptions\n\n| Field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `content` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | Body; a renderable value may also be passed directly |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| 'secondary' \\| 'contrast'` | `'info'` | Tone |\n| `closable` | `boolean` | `false` | Show close button |\n| `life` | `number` | `3000` | Auto-close ms; `0` keeps open |\n| `icon` | `boolean` | `true` | Show severity icon |\n| `id` | `string \\| number` | auto | Unique key |\n\n## Optional host\n\nFor a custom `appendTo`, place this at the app root:\n\n```vue\n<MMessage append-to=\"body\" />\n```\n\nWhen a manual host exists, the API will not mount a second one.\n\n## Props (`MMessage`)\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `teleport` | `boolean` | `true` | Whether to Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Mount target |\n| `placement` | `'top' \\| 'top-left' \\| 'top-right' \\| 'bottom' \\| 'bottom-left' \\| 'bottom-right'` | `'top'` | Host placement |\n| `max` | `number` | — | Max visible items; oldest is dropped |\n\n## Events\n\nThe `<MMessage />` host emits no Vue events. Use the `{ id, close }` return value from `message.*` APIs to control lifetime.\n\n## Slots\n\nNo slots; content is injected through the `message.*` API.\n"
13902
+ "markdown": "---\ntitle: Message\ncategory: 05 / FEEDBACK\ndescription: Top-center floating notice with an imperative API.\n---\n\n# Message\n\nA lightweight notice that slides in from the top center by default (`placement` can move it). Prefer the `message` API; you can also mount `<MMessage />` as a custom host.\n\nVs [Toast](/components/Toast):\n\n- **Message (default)**: short single-line feedback; no title/detail. Use for most CRUD / save / delete confirmations.\n- **Toast**: corner notifications with `summary` / `detail`; use only when supplementary detail is needed.\n- **`<MMessage>` component**: optional host for the `message` service (custom `appendTo` / `placement`). It is not an inline alert; persistent form errors use field `errorMessage` or a token-styled `role=\"alert\"`.\n\n> Selection guide: [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md).\n\n**Rule of thumb**: one short sentence → `message.success('Saved')`; title + detail → `toast.success({ summary, detail })`.\n\n## Import\n\n```ts\nimport { message, MMessage, useMessage } from 'morya-ui'\n```\n\n## API\n\nThe first call auto-mounts a floating host; no template component is required.\n\n```vue preview src=\"./demos/Api.en.vue\"\n```\n\n## Custom content\n\n`content` (and Toast `summary` / `detail`) accepts a string, a VNode from `h()`, a component, or a `() => VNode` factory.\n\n```vue preview src=\"./demos/CustomContent.en.vue\"\n```\n\n## Methods\n\n| Method | Description |\n| --- | --- |\n| `message.success(content \\| options)` | Success |\n| `message.info(content \\| options)` | Info |\n| `message.warn(content \\| options)` | Warn (`warning` alias) |\n| `message.error(content \\| options)` | Error |\n| `message.open(content \\| options)` | Open with options |\n| `message.close(id?)` | Close one / all |\n| `message.closeAll()` / `message.destroyAll()` | Close all (aliases of each other) |\n| `message.config({ placement, max })` | Host placement and concurrency cap |\n\nReturns `{ id, close }`.\n\n### MessageOptions\n\n| Field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `content` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | Body; a renderable value may also be passed directly |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| 'secondary' \\| 'contrast'` | `'info'` | Tone |\n| `closable` | `boolean` | `false` | Show close button |\n| `life` | `number` | `3000` | Auto-close ms; `0` keeps open |\n| `icon` | `boolean` | `true` | Show severity icon |\n| `id` | `string \\| number` | auto | Unique key |\n\n## Optional host\n\nFor a custom `appendTo`, place this at the app root:\n\n```vue\n<MMessage append-to=\"body\" />\n```\n\nWhen a manual host exists, the API will not mount a second one.\n\n## Props (`MMessage`)\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `teleport` | `boolean` | `true` | Whether to Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Mount target |\n| `placement` | `'top' \\| 'top-left' \\| 'top-right' \\| 'bottom' \\| 'bottom-left' \\| 'bottom-right'` | `'top'` | Host placement |\n| `max` | `number` | — | Max visible items; oldest is dropped |\n\n## Events\n\nThe `<MMessage />` host emits no Vue events. Use the `{ id, close }` return value from `message.*` APIs to control lifetime.\n\n## Slots\n\nNo slots; content is injected through the `message.*` API.\n"
13551
13903
  }
13552
13904
  }
13553
13905
  },
@@ -14003,7 +14355,7 @@
14003
14355
  {
14004
14356
  "id": "组合规则",
14005
14357
  "title": "组合规则",
14006
- "body": "| 场景 | 推荐组件 | 避免 |\n| --- | --- | --- |\n| 内容区垂直堆叠 | `MPageContent` | 手写 `gap` / `padding` |\n| 筛选区 | `MPageFilters` + `MSpace` / `MFlex` | 额外包一层 `MCard` |\n| 标题 + 主操作 | `MPageToolbar` | 裸 `div` + `justify-content` |\n| 页面说明 | `MPageHeader` | 无层级的裸 `h1` |\n| 表单主体 | `MPageSection variant=\"form\"` | 重复边框的 `MCard` 嵌套 |\n| 列表表格 | 直接放 `MTable` | `MCard` 再包 `MTable bordered` |\n| KPI | `MPageStat` | 每页自定义 stat CSS |\n| 图表占位 | `MPagePlaceholder` | dashed border 手写样式 |\n\n完整黄金样例见 `docs/golden-pages/`(MCP:`get_golden_page`)。**局部修改**时用 MCP `get_page_snippet`(如 `filters`、`toolbar`、`form-actions`)。"
14358
+ "body": "| 场景 | 推荐组件 | 避免 |\n| --- | --- | --- |\n| 内容区垂直堆叠 | `MPageContent` | 手写 `gap` / `padding` |\n| 筛选区 | `MPageFilters` + `MSpace` / `MFlex` | 额外包一层 `MCard` |\n| 标题 + 主操作 | `MPageToolbar` | 裸 `div` + `justify-content` |\n| 页面说明 | `MPageHeader` | 无层级的裸 `h1` |\n| 表单主体 | `MPageSection variant=\"form\"` | 重复边框的 `MCard` 嵌套 |\n| 列表表格 | 直接放 `MTable` | `MCard` 再包 `MTable bordered` |\n| KPI | `MPageStat` | 每页自定义 stat CSS |\n| 图表占位 | `MPagePlaceholder` | dashed border 手写样式 |\n\n完整黄金样例用 MCP `get_golden_page`。**局部修改**时用 MCP `get_page_snippet`(如 `filters`、`toolbar`、`form-actions`)。"
14007
14359
  },
14008
14360
  {
14009
14361
  "id": "api",
@@ -14011,7 +14363,7 @@
14011
14363
  "body": "### MPageContent\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `density` | `'default' \\| 'compact' \\| 'spacious'` | `'default'` | 子区块垂直间距。 |\n| `width` | `'full' \\| 'narrow'` | `'full'` | `narrow` 约 42rem,适合表单页。 |\n\n### MPageFilters\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `ariaLabel` | `string` | — | 筛选区无障碍名称。 |\n\n### MPageToolbar\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `default` | 无 `title` 时的左侧内容。 |\n| `actions` | 右侧操作区。 |\n\n### MPageHeader\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `description` | `string` | — | 副标题/说明。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `actions` | 右侧操作。 |\n\n### MPageSection\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `variant` | `'default' \\| 'muted' \\| 'form' \\| 'actions'` | `'default'` | 视觉变体。 |\n| `title` | `string` | — | 可选分组标题。 |\n\n### MPageStat\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `label` | `string` | — | 指标名称。 |\n| `value` | `string \\| number` | — | 主数值。 |\n| `trend` | `string` | — | 变化量或说明。 |\n| `trendSeverity` | `'primary' \\| 'success' \\| 'warn' \\| 'danger' \\| 'secondary'` | `'primary'` | 趋势色。 |\n| `icon` | `string` | — | 右侧图标名。 |\n\n### MPagePlaceholder\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `description` | `string` | — | 占位说明。 |\n| `ariaLabel` | `string` | `'Placeholder'` | 无障碍标签。 |\n| `minHeight` | `number \\| string` | `'12rem'` | 最小高度。 |"
14012
14364
  }
14013
14365
  ],
14014
- "markdown": "---\ntitle: Page\ncategory: 06 / LAYOUT\ndescription: 业务页面组合区块,封装间距、边框与标题层级,少写或不写页面 CSS。\n---\n\n# Page\n\n业务页面组合组件。与 `MLayout` 搭配使用,把列表页筛选区、工具栏、表单分组、KPI 卡片等常见区块的间距和边框内聚到组件内,**优先用 Page 组件拼装页面,而不是每页手写 scoped CSS**。\n\n## 引入\n\n```ts\nimport {\n MPageContent,\n MPageFilters,\n MPageHeader,\n MPagePlaceholder,\n MPageSection,\n MPageStat,\n MPageToolbar,\n} from 'morya-ui'\n```\n\n## 列表页组合\n\n`MPageContent` 负责内容区 **padding**(默认 `--m-space-6`)与子区块 **gap**(默认 `--m-space-4`),文档预览中外框仅模拟 `MLayoutContent` 边界。\n\n```vue preview src=\"./demos/ListPageStack.zh.vue\"\n```\n\n## 表单页组合\n\n`MPageContent width=\"narrow\"` 限制表单宽度;`MPageSection variant=\"form\"` 提供表单表面;`variant=\"actions\"` 用于底栏操作。\n\n```vue preview src=\"./demos/Demo2.vue\"\n```\n\n## 仪表盘 KPI\n\n```vue preview src=\"./demos/Kpi.vue\"\n```\n\n## 组合规则\n\n| 场景 | 推荐组件 | 避免 |\n| --- | --- | --- |\n| 内容区垂直堆叠 | `MPageContent` | 手写 `gap` / `padding` |\n| 筛选区 | `MPageFilters` + `MSpace` / `MFlex` | 额外包一层 `MCard` |\n| 标题 + 主操作 | `MPageToolbar` | 裸 `div` + `justify-content` |\n| 页面说明 | `MPageHeader` | 无层级的裸 `h1` |\n| 表单主体 | `MPageSection variant=\"form\"` | 重复边框的 `MCard` 嵌套 |\n| 列表表格 | 直接放 `MTable` | `MCard` 再包 `MTable bordered` |\n| KPI | `MPageStat` | 每页自定义 stat CSS |\n| 图表占位 | `MPagePlaceholder` | dashed border 手写样式 |\n\n完整黄金样例见 `docs/golden-pages/`(MCP:`get_golden_page`)。**局部修改**时用 MCP `get_page_snippet`(如 `filters`、`toolbar`、`form-actions`)。\n\n## API\n\n### MPageContent\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `density` | `'default' \\| 'compact' \\| 'spacious'` | `'default'` | 子区块垂直间距。 |\n| `width` | `'full' \\| 'narrow'` | `'full'` | `narrow` 约 42rem,适合表单页。 |\n\n### MPageFilters\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `ariaLabel` | `string` | — | 筛选区无障碍名称。 |\n\n### MPageToolbar\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `default` | 无 `title` 时的左侧内容。 |\n| `actions` | 右侧操作区。 |\n\n### MPageHeader\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `description` | `string` | — | 副标题/说明。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `actions` | 右侧操作。 |\n\n### MPageSection\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `variant` | `'default' \\| 'muted' \\| 'form' \\| 'actions'` | `'default'` | 视觉变体。 |\n| `title` | `string` | — | 可选分组标题。 |\n\n### MPageStat\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `label` | `string` | — | 指标名称。 |\n| `value` | `string \\| number` | — | 主数值。 |\n| `trend` | `string` | — | 变化量或说明。 |\n| `trendSeverity` | `'primary' \\| 'success' \\| 'warn' \\| 'danger' \\| 'secondary'` | `'primary'` | 趋势色。 |\n| `icon` | `string` | — | 右侧图标名。 |\n\n### MPagePlaceholder\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `description` | `string` | — | 占位说明。 |\n| `ariaLabel` | `string` | `'Placeholder'` | 无障碍标签。 |\n| `minHeight` | `number \\| string` | `'12rem'` | 最小高度。 |\n"
14366
+ "markdown": "---\ntitle: Page\ncategory: 06 / LAYOUT\ndescription: 业务页面组合区块,封装间距、边框与标题层级,少写或不写页面 CSS。\n---\n\n# Page\n\n业务页面组合组件。与 `MLayout` 搭配使用,把列表页筛选区、工具栏、表单分组、KPI 卡片等常见区块的间距和边框内聚到组件内,**优先用 Page 组件拼装页面,而不是每页手写 scoped CSS**。\n\n## 引入\n\n```ts\nimport {\n MPageContent,\n MPageFilters,\n MPageHeader,\n MPagePlaceholder,\n MPageSection,\n MPageStat,\n MPageToolbar,\n} from 'morya-ui'\n```\n\n## 列表页组合\n\n`MPageContent` 负责内容区 **padding**(默认 `--m-space-6`)与子区块 **gap**(默认 `--m-space-4`),文档预览中外框仅模拟 `MLayoutContent` 边界。\n\n```vue preview src=\"./demos/ListPageStack.zh.vue\"\n```\n\n## 表单页组合\n\n`MPageContent width=\"narrow\"` 限制表单宽度;`MPageSection variant=\"form\"` 提供表单表面;`variant=\"actions\"` 用于底栏操作。\n\n```vue preview src=\"./demos/Demo2.vue\"\n```\n\n## 仪表盘 KPI\n\n```vue preview src=\"./demos/Kpi.vue\"\n```\n\n## 组合规则\n\n| 场景 | 推荐组件 | 避免 |\n| --- | --- | --- |\n| 内容区垂直堆叠 | `MPageContent` | 手写 `gap` / `padding` |\n| 筛选区 | `MPageFilters` + `MSpace` / `MFlex` | 额外包一层 `MCard` |\n| 标题 + 主操作 | `MPageToolbar` | 裸 `div` + `justify-content` |\n| 页面说明 | `MPageHeader` | 无层级的裸 `h1` |\n| 表单主体 | `MPageSection variant=\"form\"` | 重复边框的 `MCard` 嵌套 |\n| 列表表格 | 直接放 `MTable` | `MCard` 再包 `MTable bordered` |\n| KPI | `MPageStat` | 每页自定义 stat CSS |\n| 图表占位 | `MPagePlaceholder` | dashed border 手写样式 |\n\n完整黄金样例用 MCP `get_golden_page`。**局部修改**时用 MCP `get_page_snippet`(如 `filters`、`toolbar`、`form-actions`)。\n\n## API\n\n### MPageContent\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `density` | `'default' \\| 'compact' \\| 'spacious'` | `'default'` | 子区块垂直间距。 |\n| `width` | `'full' \\| 'narrow'` | `'full'` | `narrow` 约 42rem,适合表单页。 |\n\n### MPageFilters\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `ariaLabel` | `string` | — | 筛选区无障碍名称。 |\n\n### MPageToolbar\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `default` | 无 `title` 时的左侧内容。 |\n| `actions` | 右侧操作区。 |\n\n### MPageHeader\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `title` | `string` | — | 页面标题。 |\n| `description` | `string` | — | 副标题/说明。 |\n| `headingLevel` | `1–6` | `1` | 标题层级。 |\n\n| Slot | 说明 |\n| --- | --- |\n| `actions` | 右侧操作。 |\n\n### MPageSection\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `variant` | `'default' \\| 'muted' \\| 'form' \\| 'actions'` | `'default'` | 视觉变体。 |\n| `title` | `string` | — | 可选分组标题。 |\n\n### MPageStat\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `label` | `string` | — | 指标名称。 |\n| `value` | `string \\| number` | — | 主数值。 |\n| `trend` | `string` | — | 变化量或说明。 |\n| `trendSeverity` | `'primary' \\| 'success' \\| 'warn' \\| 'danger' \\| 'secondary'` | `'primary'` | 趋势色。 |\n| `icon` | `string` | — | 右侧图标名。 |\n\n### MPagePlaceholder\n\n| Prop | 类型 | 默认 | 说明 |\n| --- | --- | --- | --- |\n| `description` | `string` | — | 占位说明。 |\n| `ariaLabel` | `string` | `'Placeholder'` | 无障碍标签。 |\n| `minHeight` | `number \\| string` | `'12rem'` | 最小高度。 |\n"
14015
14367
  },
14016
14368
  "en-US": {
14017
14369
  "title": "Page",
@@ -14040,10 +14392,10 @@
14040
14392
  {
14041
14393
  "id": "composition-rules",
14042
14394
  "title": "Composition rules",
14043
- "body": "| Scenario | Use | Avoid |\n| --- | --- | --- |\n| Vertical page stack | `MPageContent` | Hand-written `gap` / `padding` |\n| Filters | `MPageFilters` | Extra bordered `MCard` wrapper |\n| Title + actions | `MPageToolbar` | Raw flex divs |\n| Form surface | `MPageSection variant=\"form\"` | Nested bordered cards |\n| Data table | `MTable` directly | `MCard` around bordered table |\n| KPI metric | `MPageStat` | Custom stat CSS per page |\n\nGolden references: `docs/golden-pages/` (MCP: `get_golden_page`)."
14395
+ "body": "| Scenario | Use | Avoid |\n| --- | --- | --- |\n| Vertical page stack | `MPageContent` | Hand-written `gap` / `padding` |\n| Filters | `MPageFilters` | Extra bordered `MCard` wrapper |\n| Title + actions | `MPageToolbar` | Raw flex divs |\n| Form surface | `MPageSection variant=\"form\"` | Nested bordered cards |\n| Data table | `MTable` directly | `MCard` around bordered table |\n| KPI metric | `MPageStat` | Custom stat CSS per page |\n\nGolden references: MCP `get_golden_page`."
14044
14396
  }
14045
14397
  ],
14046
- "markdown": "---\ntitle: Page\ncategory: 06 / LAYOUT\ndescription: Composable page sections for spacing, borders, and headings with little or no custom CSS.\n---\n\n# Page\n\nPage composition components. Use them with `MLayout` to encode filter bars, toolbars, form surfaces, KPI cards, and other admin-page blocks **without rewriting scoped CSS on every page**.\n\n## Import\n\n```ts\nimport {\n MPageContent,\n MPageFilters,\n MPageHeader,\n MPagePlaceholder,\n MPageSection,\n MPageStat,\n MPageToolbar,\n} from 'morya-ui'\n```\n\n## List page stack\n\n`MPageContent` owns content **padding** (default `--m-space-6`) and section **gap** (default `--m-space-4`). The bordered frame in previews simulates `MLayoutContent` only.\n\n```vue preview src=\"./demos/ListPageStack.en.vue\"\n```\n\n## Form page stack\n\nUse `MPageContent width=\"narrow\"`, `MPageSection variant=\"form\"`, and `variant=\"actions\"` for the footer.\n\n## Composition rules\n\n| Scenario | Use | Avoid |\n| --- | --- | --- |\n| Vertical page stack | `MPageContent` | Hand-written `gap` / `padding` |\n| Filters | `MPageFilters` | Extra bordered `MCard` wrapper |\n| Title + actions | `MPageToolbar` | Raw flex divs |\n| Form surface | `MPageSection variant=\"form\"` | Nested bordered cards |\n| Data table | `MTable` directly | `MCard` around bordered table |\n| KPI metric | `MPageStat` | Custom stat CSS per page |\n\nGolden references: `docs/golden-pages/` (MCP: `get_golden_page`).\n"
14398
+ "markdown": "---\ntitle: Page\ncategory: 06 / LAYOUT\ndescription: Composable page sections for spacing, borders, and headings with little or no custom CSS.\n---\n\n# Page\n\nPage composition components. Use them with `MLayout` to encode filter bars, toolbars, form surfaces, KPI cards, and other admin-page blocks **without rewriting scoped CSS on every page**.\n\n## Import\n\n```ts\nimport {\n MPageContent,\n MPageFilters,\n MPageHeader,\n MPagePlaceholder,\n MPageSection,\n MPageStat,\n MPageToolbar,\n} from 'morya-ui'\n```\n\n## List page stack\n\n`MPageContent` owns content **padding** (default `--m-space-6`) and section **gap** (default `--m-space-4`). The bordered frame in previews simulates `MLayoutContent` only.\n\n```vue preview src=\"./demos/ListPageStack.en.vue\"\n```\n\n## Form page stack\n\nUse `MPageContent width=\"narrow\"`, `MPageSection variant=\"form\"`, and `variant=\"actions\"` for the footer.\n\n## Composition rules\n\n| Scenario | Use | Avoid |\n| --- | --- | --- |\n| Vertical page stack | `MPageContent` | Hand-written `gap` / `padding` |\n| Filters | `MPageFilters` | Extra bordered `MCard` wrapper |\n| Title + actions | `MPageToolbar` | Raw flex divs |\n| Form surface | `MPageSection variant=\"form\"` | Nested bordered cards |\n| Data table | `MTable` directly | `MCard` around bordered table |\n| KPI metric | `MPageStat` | Custom stat CSS per page |\n\nGolden references: MCP `get_golden_page`.\n"
14047
14399
  }
14048
14400
  }
14049
14401
  },
@@ -16067,7 +16419,7 @@
16067
16419
  "sectionId": "尺寸",
16068
16420
  "lang": "vue",
16069
16421
  "preview": true,
16070
- "code": "<script setup lang=\"ts\">\r\nimport { MButton, MResult } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-6\" style=\"grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\">\r\n <MResult\r\n size=\"small\"\r\n status=\"success\"\r\n title=\"保存成功\"\r\n >\r\n <template #footer>\r\n <MButton\r\n label=\"知道了\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n />\r\n </template>\r\n </MResult>\r\n <MResult\r\n size=\"small\"\r\n status=\"error\"\r\n title=\"上传失败\"\r\n >\r\n <template #footer>\r\n <MButton\r\n label=\"重试\"\r\n size=\"small\"\r\n />\r\n </template>\r\n </MResult>\r\n </div>\r\n</template>",
16422
+ "code": "<script setup lang=\"ts\">\nimport { MButton, MResult } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-6\" style=\"grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\">\n <MResult\n size=\"small\"\n status=\"success\"\n title=\"保存成功\"\n >\n <template #footer>\n <MButton\n label=\"知道了\"\n size=\"small\"\n severity=\"secondary\"\n />\n </template>\n </MResult>\n <MResult\n size=\"small\"\n status=\"error\"\n title=\"上传失败\"\n >\n <template #footer>\n <MButton\n label=\"重试\"\n size=\"small\"\n />\n </template>\n </MResult>\n </div>\n</template>",
16071
16423
  "locale": "zh-CN"
16072
16424
  },
16073
16425
  {
@@ -16112,7 +16464,7 @@
16112
16464
  "sectionId": "size",
16113
16465
  "lang": "vue",
16114
16466
  "preview": true,
16115
- "code": "<script setup lang=\"ts\">\r\nimport { MButton, MResult } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-6\" style=\"grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\">\r\n <MResult\r\n size=\"small\"\r\n status=\"success\"\r\n title=\"Saved\"\r\n >\r\n <template #footer>\r\n <MButton\r\n label=\"OK\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n />\r\n </template>\r\n </MResult>\r\n <MResult\r\n size=\"small\"\r\n status=\"error\"\r\n title=\"Upload failed\"\r\n >\r\n <template #footer>\r\n <MButton\r\n label=\"Retry\"\r\n size=\"small\"\r\n />\r\n </template>\r\n </MResult>\r\n </div>\r\n</template>",
16467
+ "code": "<script setup lang=\"ts\">\nimport { MButton, MResult } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-6\" style=\"grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\">\n <MResult\n size=\"small\"\n status=\"success\"\n title=\"Saved\"\n >\n <template #footer>\n <MButton\n label=\"OK\"\n size=\"small\"\n severity=\"secondary\"\n />\n </template>\n </MResult>\n <MResult\n size=\"small\"\n status=\"error\"\n title=\"Upload failed\"\n >\n <template #footer>\n <MButton\n label=\"Retry\"\n size=\"small\"\n />\n </template>\n </MResult>\n </div>\n</template>",
16116
16468
  "locale": "en-US"
16117
16469
  }
16118
16470
  ],
@@ -16444,7 +16796,7 @@
16444
16796
  {
16445
16797
  "id": "horizontal",
16446
16798
  "title": "Horizontal",
16447
- "body": "内容宽度超出容器时显示横向滚动条。`trigger=\"none\"` 与 `always` 都会常显滑块;默认 `trigger=\"hover\"` 在悬停时显示。\n\n`MLayout` / `MLayoutContent` / `MLayoutSider`、`MDialog`、`MConfirmDialog`、`MDrawer`、`MSplitter`、`MTable`、`MSelect`、`MTreeSelect`、`MDropdown`、`MContextMenu`、`MPopover`、`MConfirmPopup`、`MMenu`(popup)、`MMenubar`、`MTieredMenu`、`MTabs`、`MGallery`、`MTimeline`(horizontal)、`MTextarea`(autosize `maxRows`)、`MTerminal`、`MOrderList`、`MPickList`、`MTreeTable`、`MVirtualScroller` 等组件已内置本组件。\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```"
16799
+ "body": "内容宽度超出容器时显示横向滚动条。`trigger=\"none\"` 与 `always` 都会常显滑块;默认 `trigger=\"hover\"` 在悬停时显示。\n\n`MLayout`、`MDialog`、`MConfirmDialog`、`MDrawer`、`MSplitter`、`MTable`、`MSelect`、`MTreeSelect`、`MDropdown`、`MContextMenu`、`MPopover`、`MConfirmPopup`、`MMenu`(popup)、`MMenubar`、`MTieredMenu`、`MTabs`、`MGallery`、`MTimeline`(horizontal)、`MTextarea`(autosize `maxRows`)、`MTerminal`、`MOrderList`、`MPickList`、`MTreeTable`、`MVirtualScroller` 等组件已内置本组件。\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```"
16448
16800
  },
16449
16801
  {
16450
16802
  "id": "always-native",
@@ -16482,7 +16834,7 @@
16482
16834
  "body": "<h4 id=\"ScrollbarAriaOrientation\">ScrollbarAriaOrientation</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarAriaOrientation = 'horizontal' | 'vertical'\n```\n\n<h4 id=\"ScrollbarClassValue\">ScrollbarClassValue</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarClassValue = | string\n | string[]\n | Record<string, boolean>\n | Array<string | Record<string, boolean> | null | undefined | false>\n```"
16483
16835
  }
16484
16836
  ],
16485
- "markdown": "---\ntitle: Scrollbar\ncategory: 01 / BASIC\ndescription: 可换肤自定义滚动条,提供一致的滚动体验。\n---\n\n# Scrollbar\n\n用于替换浏览器原生滚动条,提供跨浏览器一致的可换肤滚动体验。\n\n## 引入\n\n```ts\nimport { MScrollbar } from 'morya-ui'\n```\n\n## 基础用法\n\n用 `height` 固定可视区域高度;不设时跟随父容器高度。\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Max height\n\n仅当内容超出 `max-height` 时出现滚动条。\n\n```vue preview src=\"./demos/MaxHeight.vue\"\n```\n\n## Horizontal\n\n内容宽度超出容器时显示横向滚动条。`trigger=\"none\"` 与 `always` 都会常显滑块;默认 `trigger=\"hover\"` 在悬停时显示。\n\n`MLayout` / `MLayoutContent` / `MLayoutSider`、`MDialog`、`MConfirmDialog`、`MDrawer`、`MSplitter`、`MTable`、`MSelect`、`MTreeSelect`、`MDropdown`、`MContextMenu`、`MPopover`、`MConfirmPopup`、`MMenu`(popup)、`MMenubar`、`MTieredMenu`、`MTabs`、`MGallery`、`MTimeline`(horizontal)、`MTextarea`(autosize `maxRows`)、`MTerminal`、`MOrderList`、`MPickList`、`MTreeTable`、`MVirtualScroller` 等组件已内置本组件。\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```\n\n## Always / Native\n\n`always` 常显自定义滑块;`native` 使用浏览器原生滚动条。\n\n```vue preview src=\"./demos/AlwaysNative.vue\"\n```\n\n## Manual scroll\n\n通过实例方法 `setScrollTop` / `setScrollLeft` / `scrollTo` / `update` 控制滚动。\n\n```vue preview src=\"./demos/ManualScroll.zh.vue\"\n```\n\n## Infinite scroll\n\n滚动到边缘时触发 `end-reached`,可用于无限加载。\n\n```vue preview src=\"./demos/InfiniteScroll.zh.vue\"\n```\n\n## API\n\n### Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `always` | `boolean` | — | — |\n| `ariaLabel` | `string` | — | — |\n| `ariaOrientation` | `ScrollbarAriaOrientation` | — | — |\n| `distance` | `number` | — | — |\n| `height` | `string \\| number` | — | — |\n| `id` | `string` | — | — |\n| `maxHeight` | `string \\| number` | — | — |\n| `minSize` | `number` | — | — |\n| `native` | `boolean` | — | — |\n| `noresize` | `boolean` | — | — |\n| `role` | `string` | — | — |\n| `tabindex` | `number \\| string` | — | — |\n| `tag` | `string` | — | — |\n| `trigger` | `'hover' \\| 'none'` | — | — |\n| `viewClass` | `ScrollbarClassValue` | — | — |\n| `viewStyle` | `StyleValue` | — | — |\n| `wrapClass` | `ScrollbarClassValue` | — | — |\n| `wrapStyle` | `StyleValue` | — | — |\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| height | `string \\| number` | — | 可视区域高度 |\n| maxHeight | `string \\| number` | — | 最大高度 |\n| fitContent | `boolean` | `false` | 随内容增高,配合根节点 CSS `max-height` 使用(下拉面板) |\n| native | `boolean` | `false` | 使用原生滚动条 |\n| wrapStyle / wrapClass | style / class | — | wrap 容器样式 |\n| viewStyle / viewClass | style / class | — | 内容区样式 |\n| noresize | `boolean` | `false` | 不监听尺寸变化 |\n| tag | `string` | `div` | 内容区标签 |\n| always | `boolean` | `false` | 始终显示滑块 |\n| trigger | `'hover' \\| 'none'` | `'hover'` | `none` 常显滑块;`always` 为 true 时仍常显 |\n| minSize | `number` | `20` | 滑块最小尺寸 |\n| id / role / ariaLabel / ariaOrientation | a11y | — | 内容区无障碍属性 |\n| tabindex | `number \\| string` | — | wrap 的 tabindex |\n| distance | `number` | `0` | 触发 `end-reached` 的边缘距离 |\n\n### Events\n\n| Name | Payload |\n| --- | --- |\n| scroll | `{ scrollTop, scrollLeft }` |\n| end-reached | `'top' \\| 'bottom' \\| 'left' \\| 'right'` |\n\n### Expose\n\n`wrapRef`、`update`、`scrollTo`、`setScrollTop`、`setScrollLeft`、`handleScroll`\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `scroll` | `{ scrollTop, scrollLeft }` | 滚动位置变化。 |\n| `end-reached` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | 滚动到边缘。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 可滚动内容。 |\n\n## 类型\n\n<h4 id=\"ScrollbarAriaOrientation\">ScrollbarAriaOrientation</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarAriaOrientation = 'horizontal' | 'vertical'\n```\n\n<h4 id=\"ScrollbarClassValue\">ScrollbarClassValue</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarClassValue = | string\n | string[]\n | Record<string, boolean>\n | Array<string | Record<string, boolean> | null | undefined | false>\n```\n"
16837
+ "markdown": "---\ntitle: Scrollbar\ncategory: 01 / BASIC\ndescription: 可换肤自定义滚动条,提供一致的滚动体验。\n---\n\n# Scrollbar\n\n用于替换浏览器原生滚动条,提供跨浏览器一致的可换肤滚动体验。\n\n## 引入\n\n```ts\nimport { MScrollbar } from 'morya-ui'\n```\n\n## 基础用法\n\n用 `height` 固定可视区域高度;不设时跟随父容器高度。\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Max height\n\n仅当内容超出 `max-height` 时出现滚动条。\n\n```vue preview src=\"./demos/MaxHeight.vue\"\n```\n\n## Horizontal\n\n内容宽度超出容器时显示横向滚动条。`trigger=\"none\"` 与 `always` 都会常显滑块;默认 `trigger=\"hover\"` 在悬停时显示。\n\n`MLayout`、`MDialog`、`MConfirmDialog`、`MDrawer`、`MSplitter`、`MTable`、`MSelect`、`MTreeSelect`、`MDropdown`、`MContextMenu`、`MPopover`、`MConfirmPopup`、`MMenu`(popup)、`MMenubar`、`MTieredMenu`、`MTabs`、`MGallery`、`MTimeline`(horizontal)、`MTextarea`(autosize `maxRows`)、`MTerminal`、`MOrderList`、`MPickList`、`MTreeTable`、`MVirtualScroller` 等组件已内置本组件。\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```\n\n## Always / Native\n\n`always` 常显自定义滑块;`native` 使用浏览器原生滚动条。\n\n```vue preview src=\"./demos/AlwaysNative.vue\"\n```\n\n## Manual scroll\n\n通过实例方法 `setScrollTop` / `setScrollLeft` / `scrollTo` / `update` 控制滚动。\n\n```vue preview src=\"./demos/ManualScroll.zh.vue\"\n```\n\n## Infinite scroll\n\n滚动到边缘时触发 `end-reached`,可用于无限加载。\n\n```vue preview src=\"./demos/InfiniteScroll.zh.vue\"\n```\n\n## API\n\n### Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `always` | `boolean` | — | — |\n| `ariaLabel` | `string` | — | — |\n| `ariaOrientation` | `ScrollbarAriaOrientation` | — | — |\n| `distance` | `number` | — | — |\n| `height` | `string \\| number` | — | — |\n| `id` | `string` | — | — |\n| `maxHeight` | `string \\| number` | — | — |\n| `minSize` | `number` | — | — |\n| `native` | `boolean` | — | — |\n| `noresize` | `boolean` | — | — |\n| `role` | `string` | — | — |\n| `tabindex` | `number \\| string` | — | — |\n| `tag` | `string` | — | — |\n| `trigger` | `'hover' \\| 'none'` | — | — |\n| `viewClass` | `ScrollbarClassValue` | — | — |\n| `viewStyle` | `StyleValue` | — | — |\n| `wrapClass` | `ScrollbarClassValue` | — | — |\n| `wrapStyle` | `StyleValue` | — | — |\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| height | `string \\| number` | — | 可视区域高度 |\n| maxHeight | `string \\| number` | — | 最大高度 |\n| fitContent | `boolean` | `false` | 随内容增高,配合根节点 CSS `max-height` 使用(下拉面板) |\n| native | `boolean` | `false` | 使用原生滚动条 |\n| wrapStyle / wrapClass | style / class | — | wrap 容器样式 |\n| viewStyle / viewClass | style / class | — | 内容区样式 |\n| noresize | `boolean` | `false` | 不监听尺寸变化 |\n| tag | `string` | `div` | 内容区标签 |\n| always | `boolean` | `false` | 始终显示滑块 |\n| trigger | `'hover' \\| 'none'` | `'hover'` | `none` 常显滑块;`always` 为 true 时仍常显 |\n| minSize | `number` | `20` | 滑块最小尺寸 |\n| id / role / ariaLabel / ariaOrientation | a11y | — | 内容区无障碍属性 |\n| tabindex | `number \\| string` | — | wrap 的 tabindex |\n| distance | `number` | `0` | 触发 `end-reached` 的边缘距离 |\n\n### Events\n\n| Name | Payload |\n| --- | --- |\n| scroll | `{ scrollTop, scrollLeft }` |\n| end-reached | `'top' \\| 'bottom' \\| 'left' \\| 'right'` |\n\n### Expose\n\n`wrapRef`、`update`、`scrollTo`、`setScrollTop`、`setScrollLeft`、`handleScroll`\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `scroll` | `{ scrollTop, scrollLeft }` | 滚动位置变化。 |\n| `end-reached` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | 滚动到边缘。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 可滚动内容。 |\n\n## 类型\n\n<h4 id=\"ScrollbarAriaOrientation\">ScrollbarAriaOrientation</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarAriaOrientation = 'horizontal' | 'vertical'\n```\n\n<h4 id=\"ScrollbarClassValue\">ScrollbarClassValue</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ntype ScrollbarClassValue = | string\n | string[]\n | Record<string, boolean>\n | Array<string | Record<string, boolean> | null | undefined | false>\n```\n"
16486
16838
  },
16487
16839
  "en-US": {
16488
16840
  "title": "Scrollbar",
@@ -16511,7 +16863,7 @@
16511
16863
  {
16512
16864
  "id": "horizontal",
16513
16865
  "title": "Horizontal",
16514
- "body": "A horizontal scrollbar appears when content is wider than the container. `trigger=\"none\"` and `always` keep the thumb visible; the default `trigger=\"hover\"` shows it on hover.\n\n`MLayout`, `MLayoutContent`, `MLayoutSider`, `MDialog`, `MConfirmDialog`, `MDrawer`, `MSplitter`, `MTable`, `MSelect`, `MTreeSelect`, `MDropdown`, `MContextMenu`, `MPopover`, `MConfirmPopup`, `MMenu` (popup), `MMenubar`, `MTieredMenu`, `MTabs`, `MGallery`, `MTimeline` (horizontal), `MTextarea` (autosize `maxRows`), `MTerminal`, `MOrderList`, `MPickList`, `MTreeTable`, and `MVirtualScroller` integrate this component internally.\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```"
16866
+ "body": "A horizontal scrollbar appears when content is wider than the container. `trigger=\"none\"` and `always` keep the thumb visible; the default `trigger=\"hover\"` shows it on hover.\n\n`MLayout`, `MDialog`, `MConfirmDialog`, `MDrawer`, `MSplitter`, `MTable`, `MSelect`, `MTreeSelect`, `MDropdown`, `MContextMenu`, `MPopover`, `MConfirmPopup`, `MMenu` (popup), `MMenubar`, `MTieredMenu`, `MTabs`, `MGallery`, `MTimeline` (horizontal), `MTextarea` (autosize `maxRows`), `MTerminal`, `MOrderList`, `MPickList`, `MTreeTable`, and `MVirtualScroller` integrate this component internally.\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```"
16515
16867
  },
16516
16868
  {
16517
16869
  "id": "always-native",
@@ -16544,7 +16896,7 @@
16544
16896
  "body": "| Slot | Description |\n| --- | --- |\n| `default` | Scrollable content. |"
16545
16897
  }
16546
16898
  ],
16547
- "markdown": "---\ntitle: Scrollbar\ncategory: 01 / BASIC\ndescription: Themeable custom scrollbar for a consistent scrolling experience.\n---\n\n# Scrollbar\n\nReplaces the native browser scrollbar with a themeable, cross-browser scrolling experience.\n\n## Import\n\n```ts\nimport { MScrollbar } from 'morya-ui'\n```\n\n## Basic\n\nUse `height` to fix the viewport height. If omitted, it follows the parent height.\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Max height\n\nThe scrollbar appears only when content exceeds `max-height`.\n\n```vue preview src=\"./demos/MaxHeight.vue\"\n```\n\n## Horizontal\n\nA horizontal scrollbar appears when content is wider than the container. `trigger=\"none\"` and `always` keep the thumb visible; the default `trigger=\"hover\"` shows it on hover.\n\n`MLayout`, `MLayoutContent`, `MLayoutSider`, `MDialog`, `MConfirmDialog`, `MDrawer`, `MSplitter`, `MTable`, `MSelect`, `MTreeSelect`, `MDropdown`, `MContextMenu`, `MPopover`, `MConfirmPopup`, `MMenu` (popup), `MMenubar`, `MTieredMenu`, `MTabs`, `MGallery`, `MTimeline` (horizontal), `MTextarea` (autosize `maxRows`), `MTerminal`, `MOrderList`, `MPickList`, `MTreeTable`, and `MVirtualScroller` integrate this component internally.\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```\n\n## Always / Native\n\n`always` keeps the custom thumb visible. `native` uses the browser scrollbar.\n\n```vue preview src=\"./demos/AlwaysNative.vue\"\n```\n\n## Manual scroll\n\nControl scrolling with instance methods `setScrollTop` / `setScrollLeft` / `scrollTo` / `update`.\n\n```vue preview src=\"./demos/ManualScroll.en.vue\"\n```\n\n## Infinite scroll\n\nEmits `end-reached` at the edge. Use it for infinite loading.\n\n```vue preview src=\"./demos/InfiniteScroll.en.vue\"\n```\n\n## API\n\n### Props\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| height | `string \\| number` | — | Viewport height |\n| maxHeight | `string \\| number` | — | Maximum height |\n| fitContent | `boolean` | `false` | Grow with content; pair with CSS `max-height` on the root (dropdown panels) |\n| native | `boolean` | `false` | Use the native scrollbar |\n| wrapStyle / wrapClass | style / class | — | Wrap container styles |\n| viewStyle / viewClass | style / class | — | Content area styles |\n| noresize | `boolean` | `false` | Do not listen for size changes |\n| tag | `string` | `div` | Content area tag |\n| always | `boolean` | `false` | Always show the thumb |\n| trigger | `'hover' \\| 'none'` | `'hover'` | `none` keeps thumbs visible; `always` still wins |\n| minSize | `number` | `20` | Minimum thumb size |\n| id / role / ariaLabel / ariaOrientation | a11y | — | Accessible attributes for the content area |\n| tabindex | `number \\| string` | — | tabindex on the wrap |\n| distance | `number` | `0` | Edge distance that triggers `end-reached` |\n\n### Events\n\n| Name | Payload |\n| --- | --- |\n| scroll | `{ scrollTop, scrollLeft }` |\n| end-reached | `'top' \\| 'bottom' \\| 'left' \\| 'right'` |\n\n### Expose\n\n`wrapRef`, `update`, `scrollTo`, `setScrollTop`, `setScrollLeft`, `handleScroll`\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `scroll` | `{ scrollTop, scrollLeft }` | Scroll position change. |\n| `end-reached` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | Scroll boundary reached. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Scrollable content. |\n"
16899
+ "markdown": "---\ntitle: Scrollbar\ncategory: 01 / BASIC\ndescription: Themeable custom scrollbar for a consistent scrolling experience.\n---\n\n# Scrollbar\n\nReplaces the native browser scrollbar with a themeable, cross-browser scrolling experience.\n\n## Import\n\n```ts\nimport { MScrollbar } from 'morya-ui'\n```\n\n## Basic\n\nUse `height` to fix the viewport height. If omitted, it follows the parent height.\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Max height\n\nThe scrollbar appears only when content exceeds `max-height`.\n\n```vue preview src=\"./demos/MaxHeight.vue\"\n```\n\n## Horizontal\n\nA horizontal scrollbar appears when content is wider than the container. `trigger=\"none\"` and `always` keep the thumb visible; the default `trigger=\"hover\"` shows it on hover.\n\n`MLayout`, `MDialog`, `MConfirmDialog`, `MDrawer`, `MSplitter`, `MTable`, `MSelect`, `MTreeSelect`, `MDropdown`, `MContextMenu`, `MPopover`, `MConfirmPopup`, `MMenu` (popup), `MMenubar`, `MTieredMenu`, `MTabs`, `MGallery`, `MTimeline` (horizontal), `MTextarea` (autosize `maxRows`), `MTerminal`, `MOrderList`, `MPickList`, `MTreeTable`, and `MVirtualScroller` integrate this component internally.\n\n```vue preview src=\"./demos/Horizontal.vue\"\n```\n\n## Always / Native\n\n`always` keeps the custom thumb visible. `native` uses the browser scrollbar.\n\n```vue preview src=\"./demos/AlwaysNative.vue\"\n```\n\n## Manual scroll\n\nControl scrolling with instance methods `setScrollTop` / `setScrollLeft` / `scrollTo` / `update`.\n\n```vue preview src=\"./demos/ManualScroll.en.vue\"\n```\n\n## Infinite scroll\n\nEmits `end-reached` at the edge. Use it for infinite loading.\n\n```vue preview src=\"./demos/InfiniteScroll.en.vue\"\n```\n\n## API\n\n### Props\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| height | `string \\| number` | — | Viewport height |\n| maxHeight | `string \\| number` | — | Maximum height |\n| fitContent | `boolean` | `false` | Grow with content; pair with CSS `max-height` on the root (dropdown panels) |\n| native | `boolean` | `false` | Use the native scrollbar |\n| wrapStyle / wrapClass | style / class | — | Wrap container styles |\n| viewStyle / viewClass | style / class | — | Content area styles |\n| noresize | `boolean` | `false` | Do not listen for size changes |\n| tag | `string` | `div` | Content area tag |\n| always | `boolean` | `false` | Always show the thumb |\n| trigger | `'hover' \\| 'none'` | `'hover'` | `none` keeps thumbs visible; `always` still wins |\n| minSize | `number` | `20` | Minimum thumb size |\n| id / role / ariaLabel / ariaOrientation | a11y | — | Accessible attributes for the content area |\n| tabindex | `number \\| string` | — | tabindex on the wrap |\n| distance | `number` | `0` | Edge distance that triggers `end-reached` |\n\n### Events\n\n| Name | Payload |\n| --- | --- |\n| scroll | `{ scrollTop, scrollLeft }` |\n| end-reached | `'top' \\| 'bottom' \\| 'left' \\| 'right'` |\n\n### Expose\n\n`wrapRef`, `update`, `scrollTo`, `setScrollTop`, `setScrollLeft`, `handleScroll`\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `scroll` | `{ scrollTop, scrollLeft }` | Scroll position change. |\n| `end-reached` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | Scroll boundary reached. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Scrollable content. |\n"
16548
16900
  }
16549
16901
  }
16550
16902
  },
@@ -19473,7 +19825,7 @@
19473
19825
  "sectionId": "标签-纯文字-自定义图标",
19474
19826
  "lang": "vue",
19475
19827
  "preview": true,
19476
- "code": "<script setup lang=\"ts\">\r\nimport { MStatus } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-4\">\r\n <div class=\"flex flex-wrap gap-4 items-center\">\r\n <MStatus label=\"已完成\" severity=\"success\" variant=\"tag\" />\r\n <MStatus label=\"运行中\" severity=\"info\" variant=\"tag\" processing />\r\n <MStatus label=\"待审核\" severity=\"warn\" variant=\"tag\" />\r\n <MStatus label=\"失败\" severity=\"danger\" variant=\"tag\" />\r\n <MStatus label=\"已归档\" variant=\"tag\" />\r\n <MStatus label=\"已禁用\" variant=\"tag\" disabled />\r\n </div>\r\n <div class=\"flex flex-wrap gap-4 items-center\">\r\n <MStatus label=\"自定义图标\" severity=\"success\" icon=\"check\" />\r\n <MStatus label=\"已完成\" severity=\"success\" variant=\"text\" />\r\n <MStatus label=\"同步中…\" severity=\"info\" variant=\"text\" />\r\n <MStatus label=\"—\" variant=\"text\" />\r\n </div>\r\n </div>\r\n</template>",
19828
+ "code": "<script setup lang=\"ts\">\nimport { MStatus } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <div class=\"flex flex-wrap gap-4 items-center\">\n <MStatus label=\"已完成\" severity=\"success\" variant=\"tag\" />\n <MStatus label=\"运行中\" severity=\"info\" variant=\"tag\" processing />\n <MStatus label=\"待审核\" severity=\"warn\" variant=\"tag\" />\n <MStatus label=\"失败\" severity=\"danger\" variant=\"tag\" />\n <MStatus label=\"已归档\" variant=\"tag\" />\n <MStatus label=\"已禁用\" variant=\"tag\" disabled />\n </div>\n <div class=\"flex flex-wrap gap-4 items-center\">\n <MStatus label=\"自定义图标\" severity=\"success\" icon=\"check\" />\n <MStatus label=\"已完成\" severity=\"success\" variant=\"text\" />\n <MStatus label=\"同步中…\" severity=\"info\" variant=\"text\" />\n <MStatus label=\"—\" variant=\"text\" />\n </div>\n </div>\n</template>",
19477
19829
  "locale": "zh-CN"
19478
19830
  },
19479
19831
  {
@@ -19518,7 +19870,7 @@
19518
19870
  "sectionId": "tag-text-custom-icon",
19519
19871
  "lang": "vue",
19520
19872
  "preview": true,
19521
- "code": "<script setup lang=\"ts\">\r\nimport { MStatus } from 'morya-ui'\r\n</script>\r\n\r\n<template>\r\n <div class=\"grid gap-4\">\r\n <div class=\"flex flex-wrap gap-4 items-center\">\r\n <MStatus label=\"已完成\" severity=\"success\" variant=\"tag\" />\r\n <MStatus label=\"运行中\" severity=\"info\" variant=\"tag\" processing />\r\n <MStatus label=\"待审核\" severity=\"warn\" variant=\"tag\" />\r\n <MStatus label=\"失败\" severity=\"danger\" variant=\"tag\" />\r\n <MStatus label=\"已归档\" variant=\"tag\" />\r\n <MStatus label=\"已禁用\" variant=\"tag\" disabled />\r\n </div>\r\n <div class=\"flex flex-wrap gap-4 items-center\">\r\n <MStatus label=\"自定义图标\" severity=\"success\" icon=\"check\" />\r\n <MStatus label=\"已完成\" severity=\"success\" variant=\"text\" />\r\n <MStatus label=\"同步中…\" severity=\"info\" variant=\"text\" />\r\n <MStatus label=\"—\" variant=\"text\" />\r\n </div>\r\n </div>\r\n</template>",
19873
+ "code": "<script setup lang=\"ts\">\nimport { MStatus } from 'morya-ui'\n</script>\n\n<template>\n <div class=\"grid gap-4\">\n <div class=\"flex flex-wrap gap-4 items-center\">\n <MStatus label=\"已完成\" severity=\"success\" variant=\"tag\" />\n <MStatus label=\"运行中\" severity=\"info\" variant=\"tag\" processing />\n <MStatus label=\"待审核\" severity=\"warn\" variant=\"tag\" />\n <MStatus label=\"失败\" severity=\"danger\" variant=\"tag\" />\n <MStatus label=\"已归档\" variant=\"tag\" />\n <MStatus label=\"已禁用\" variant=\"tag\" disabled />\n </div>\n <div class=\"flex flex-wrap gap-4 items-center\">\n <MStatus label=\"自定义图标\" severity=\"success\" icon=\"check\" />\n <MStatus label=\"已完成\" severity=\"success\" variant=\"text\" />\n <MStatus label=\"同步中…\" severity=\"info\" variant=\"text\" />\n <MStatus label=\"—\" variant=\"text\" />\n </div>\n </div>\n</template>",
19522
19874
  "locale": "en-US"
19523
19875
  }
19524
19876
  ],
@@ -21240,7 +21592,7 @@
21240
21592
  "body": "<h4 id=\"TabItem\">TabItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface TabItem {\n label: string\n value: string\n disabled?: boolean\n /** When set, overrides the Tabs `closable` prop for this item. */\n closable?: boolean\n}\n```"
21241
21593
  }
21242
21594
  ],
21243
- "markdown": "---\ntitle: Tabs\ncategory: 04 / NAVIGATION\ndescription: 标签页切换。支持 line/card、关闭/新增、extra 与溢出滚动。\n---\n\n# Tabs\n\n标签页用于在同一视图内切换内容分区。\n\n## 引入\n\n```ts\nimport { MTabs } from 'morya-ui'\n```\n\n## 基础用法\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Card / closable / extra\n\n```vue preview src=\"./demos/CardClosableExtra.zh.vue\"\n```\n\n标签过多超出容器时,两端会出现滚动按钮。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `modelValue` | `string` | — | 当前活动 tab。 |\n| `tabs` | `TabItem[]` | — | 标签列表;支持 `disabled` / `closable`。 |\n| `type` | `'line' \\| 'card'` | `'line'` | 外观。 |\n| `closable` | `boolean` | `false` | 显示关闭按钮;单项 `closable` 优先。 |\n| `addable` | `boolean` | `false` | 显示新增按钮。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `update:modelValue` | `string` | 活动项变化。 |\n| `change` | `string` | 切换完成。 |\n| `close` | `string` | 点击关闭。 |\n| `add` | — | 点击新增。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 面板内容,作用域 `{ activeValue }`。 |\n| `extra` | 标签栏右侧额外内容。 |\n\n## 类型\n\n<h4 id=\"TabItem\">TabItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface TabItem {\r\n label: string\r\n value: string\r\n disabled?: boolean\r\n /** When set, overrides the Tabs `closable` prop for this item. */\r\n closable?: boolean\r\n}\n```\n"
21595
+ "markdown": "---\ntitle: Tabs\ncategory: 04 / NAVIGATION\ndescription: 标签页切换。支持 line/card、关闭/新增、extra 与溢出滚动。\n---\n\n# Tabs\n\n标签页用于在同一视图内切换内容分区。\n\n## 引入\n\n```ts\nimport { MTabs } from 'morya-ui'\n```\n\n## 基础用法\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Card / closable / extra\n\n```vue preview src=\"./demos/CardClosableExtra.zh.vue\"\n```\n\n标签过多超出容器时,两端会出现滚动按钮。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `modelValue` | `string` | — | 当前活动 tab。 |\n| `tabs` | `TabItem[]` | — | 标签列表;支持 `disabled` / `closable`。 |\n| `type` | `'line' \\| 'card'` | `'line'` | 外观。 |\n| `closable` | `boolean` | `false` | 显示关闭按钮;单项 `closable` 优先。 |\n| `addable` | `boolean` | `false` | 显示新增按钮。 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `update:modelValue` | `string` | 活动项变化。 |\n| `change` | `string` | 切换完成。 |\n| `close` | `string` | 点击关闭。 |\n| `add` | — | 点击新增。 |\n\n## Slots\n\n| 插槽名 | 说明 |\n| --- | --- |\n| `default` | 面板内容,作用域 `{ activeValue }`。 |\n| `extra` | 标签栏右侧额外内容。 |\n\n## 类型\n\n<h4 id=\"TabItem\">TabItem</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface TabItem {\n label: string\n value: string\n disabled?: boolean\n /** When set, overrides the Tabs `closable` prop for this item. */\n closable?: boolean\n}\n```\n"
21244
21596
  },
21245
21597
  "en-US": {
21246
21598
  "title": "Tabs",
@@ -21287,7 +21639,7 @@
21287
21639
  "body": "<h4 id=\"TabItem\">TabItem</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface TabItem {\n label: string\n value: string\n disabled?: boolean\n /** When set, overrides the Tabs `closable` prop for this item. */\n closable?: boolean\n}\n```"
21288
21640
  }
21289
21641
  ],
21290
- "markdown": "---\ntitle: Tabs\ncategory: 04 / NAVIGATION\ndescription: Tab switcher with line/card types, closable/addable tabs, extra slot, and overflow scrolling.\n---\n\n# Tabs\n\nTabs switch content panels within the same view.\n\n## Import\n\n```ts\nimport { MTabs } from 'morya-ui'\n```\n\n## Basic\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Card / closable / extra\n\n```vue preview src=\"./demos/CardClosableExtra.en.vue\"\n```\n\nWhen tabs overflow the container, scroll buttons appear at both ends.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `modelValue` | `string` | — | Currently active tab. |\n| `tabs` | `TabItem[]` | — | Tab list; supports `disabled` / `closable`. |\n| `type` | `'line' \\| 'card'` | `'line'` | Appearance. |\n| `closable` | `boolean` | `false` | Show close buttons; per-item `closable` wins. |\n| `addable` | `boolean` | `false` | Show an add button. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Prop | Description |\n| --- | --- | --- |\n| `update:modelValue` | `string` | Emitted when the active item changes. |\n| `change` | `string` | Emitted after the switch completes. |\n| `close` | `string` | Emitted when a close button is clicked. |\n| `add` | — | Emitted when the add button is clicked. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Panel content; scoped slot `{ activeValue }`. |\n| `extra` | Extra content on the right of the tab bar. |\n\n## Types\n\n<h4 id=\"TabItem\">TabItem</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface TabItem {\r\n label: string\r\n value: string\r\n disabled?: boolean\r\n /** When set, overrides the Tabs `closable` prop for this item. */\r\n closable?: boolean\r\n}\n```\n"
21642
+ "markdown": "---\ntitle: Tabs\ncategory: 04 / NAVIGATION\ndescription: Tab switcher with line/card types, closable/addable tabs, extra slot, and overflow scrolling.\n---\n\n# Tabs\n\nTabs switch content panels within the same view.\n\n## Import\n\n```ts\nimport { MTabs } from 'morya-ui'\n```\n\n## Basic\n\n```vue preview src=\"./demos/Basic.vue\"\n```\n\n## Card / closable / extra\n\n```vue preview src=\"./demos/CardClosableExtra.en.vue\"\n```\n\nWhen tabs overflow the container, scroll buttons appear at both ends.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `modelValue` | `string` | — | Currently active tab. |\n| `tabs` | `TabItem[]` | — | Tab list; supports `disabled` / `closable`. |\n| `type` | `'line' \\| 'card'` | `'line'` | Appearance. |\n| `closable` | `boolean` | `false` | Show close buttons; per-item `closable` wins. |\n| `addable` | `boolean` | `false` | Show an add button. |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Prop | Description |\n| --- | --- | --- |\n| `update:modelValue` | `string` | Emitted when the active item changes. |\n| `change` | `string` | Emitted after the switch completes. |\n| `close` | `string` | Emitted when a close button is clicked. |\n| `add` | — | Emitted when the add button is clicked. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| `default` | Panel content; scoped slot `{ activeValue }`. |\n| `extra` | Extra content on the right of the tab bar. |\n\n## Types\n\n<h4 id=\"TabItem\">TabItem</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface TabItem {\n label: string\n value: string\n disabled?: boolean\n /** When set, overrides the Tabs `closable` prop for this item. */\n closable?: boolean\n}\n```\n"
21291
21643
  }
21292
21644
  }
21293
21645
  },
@@ -22815,7 +23167,7 @@
22815
23167
  {
22816
23168
  "id": "overview",
22817
23169
  "title": "",
22818
- "body": "# Toast\n\n带标题 / 详情的四角通知。可用 `toast` API,或继续用 `:messages` 受控渲染。\n\n与 [Message](/components/Message) 的分工:Message 是**默认**的轻量单行反馈;Toast 仅在需要 `summary` / `detail` 或角落通知时使用。受控 `:messages` 时请自行限制条数,`max` 只作用于服务队列。\n\n> AI / 业务代码选型细则见 [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md)。\n\n**不要**用 `toast.add({ summary: '已保存' })` 代替 `message.success('已保存')`。"
23170
+ "body": "# Toast\n\n带标题 / 详情的四角通知。可用 `toast` API,或继续用 `:messages` 受控渲染。\n\n与 [Message](/components/Message) 的分工:Message 是**默认**的轻量单行反馈;Toast 仅在需要 `summary` / `detail` 或角落通知时使用。受控 `:messages` 时请自行限制条数,`max` 只作用于服务队列。\n\n> AI / 业务代码选型细则见 [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md)。\n\n**不要**用 `toast.add({ summary: '已保存' })` 代替 `message.success('已保存')`。"
22819
23171
  },
22820
23172
  {
22821
23173
  "id": "引入",
@@ -22863,7 +23215,7 @@
22863
23215
  "body": "<h4 id=\"ToastMessage\">ToastMessage</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface ToastMessage {\n id: string | number\n summary: MRenderable\n detail?: MRenderable\n severity?: ToastSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n}\n```"
22864
23216
  }
22865
23217
  ],
22866
- "markdown": "---\ntitle: Toast\ncategory: 05 / FEEDBACK\ndescription: 四角浮层通知,支持 API 与受控列表。\n---\n\n# Toast\n\n带标题 / 详情的四角通知。可用 `toast` API,或继续用 `:messages` 受控渲染。\n\n与 [Message](/components/Message) 的分工:Message 是**默认**的轻量单行反馈;Toast 仅在需要 `summary` / `detail` 或角落通知时使用。受控 `:messages` 时请自行限制条数,`max` 只作用于服务队列。\n\n> AI / 业务代码选型细则见 [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md)。\n\n**不要**用 `toast.add({ summary: '已保存' })` 代替 `message.success('已保存')`。\n\n## 引入\n\n```ts\nimport { MToast, toast, useToast } from 'morya-ui'\n```\n\n## API\n\n```vue preview src=\"./demos/Api.zh.vue\"\n```\n\n## 自定义内容\n\n`summary` / `detail` 同样支持字符串、`h()`、组件或渲染工厂。\n\n```vue preview src=\"./demos/CustomContent.zh.vue\"\n```\n\n## Controlled\n\n仍可通过 `messages` + `close` 自行管理列表。\n\n```vue preview src=\"./demos/Controlled.vue\"\n```\n\n## Methods\n\n| 方法 | 说明 |\n| --- | --- |\n| `toast.success / info / warn / error` | 按语义添加 |\n| `toast.add(options)` | 添加一条 |\n| `toast.remove(id)` / `toast.close(id)` | 移除 |\n| `toast.clear()` / `toast.closeAll()` / `toast.destroyAll()` | 清空 |\n| `toast.setDefaults({ position, max })` | 默认角落位置与并发上限 |\n\n字符串入参视为 `summary`。默认 `life` 为 `3000`;`0` 表示不自动关闭。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `messages` | `ToastMessage[]` | — | 受控列表;省略则绑定 `toast` 服务队列 |\n| `position` | `'top-right' \\| 'top-left' \\| 'bottom-right' \\| 'bottom-left'` | `'top-right'` | 容器定位 |\n| `max` | `number` | — | 同时可见条数;超出丢掉最旧一条(仅服务队列) |\n| `teleport` | `boolean` | `true` | 浮层 Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | 挂载目标 |\n| `auto` | `boolean` | — | — |\n\n### ToastMessage\n\n| 字段 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `id` | `string \\| number` | — | 唯一键 |\n| `summary` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | 标题 |\n| `detail` | 同上 | — | 详情 |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| …` | `'info'` | 语义色 |\n| `closable` | `boolean` | `true` | 关闭按钮 |\n| `life` | `number` | API 默认 `3000` | 自动关闭毫秒 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `close` | `ToastMessage` | 点击关闭;受控模式下由调用方移除 |\n\n## Slots\n\n无插槽;通过 `messages` prop 或 toast API 驱动。\n\n## 类型\n\n<h4 id=\"ToastMessage\">ToastMessage</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface ToastMessage {\r\n id: string | number\r\n summary: MRenderable\r\n detail?: MRenderable\r\n severity?: ToastSeverity\r\n closable?: boolean\r\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\r\n life?: number\r\n}\n```\n"
23218
+ "markdown": "---\ntitle: Toast\ncategory: 05 / FEEDBACK\ndescription: 四角浮层通知,支持 API 与受控列表。\n---\n\n# Toast\n\n带标题 / 详情的四角通知。可用 `toast` API,或继续用 `:messages` 受控渲染。\n\n与 [Message](/components/Message) 的分工:Message 是**默认**的轻量单行反馈;Toast 仅在需要 `summary` / `detail` 或角落通知时使用。受控 `:messages` 时请自行限制条数,`max` 只作用于服务队列。\n\n> AI / 业务代码选型细则见 [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md)。\n\n**不要**用 `toast.add({ summary: '已保存' })` 代替 `message.success('已保存')`。\n\n## 引入\n\n```ts\nimport { MToast, toast, useToast } from 'morya-ui'\n```\n\n## API\n\n```vue preview src=\"./demos/Api.zh.vue\"\n```\n\n## 自定义内容\n\n`summary` / `detail` 同样支持字符串、`h()`、组件或渲染工厂。\n\n```vue preview src=\"./demos/CustomContent.zh.vue\"\n```\n\n## Controlled\n\n仍可通过 `messages` + `close` 自行管理列表。\n\n```vue preview src=\"./demos/Controlled.vue\"\n```\n\n## Methods\n\n| 方法 | 说明 |\n| --- | --- |\n| `toast.success / info / warn / error` | 按语义添加 |\n| `toast.add(options)` | 添加一条 |\n| `toast.remove(id)` / `toast.close(id)` | 移除 |\n| `toast.clear()` / `toast.closeAll()` / `toast.destroyAll()` | 清空 |\n| `toast.setDefaults({ position, max })` | 默认角落位置与并发上限 |\n\n字符串入参视为 `summary`。默认 `life` 为 `3000`;`0` 表示不自动关闭。\n\n## Props\n\n| 参数 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `messages` | `ToastMessage[]` | — | 受控列表;省略则绑定 `toast` 服务队列 |\n| `position` | `'top-right' \\| 'top-left' \\| 'bottom-right' \\| 'bottom-left'` | `'top-right'` | 容器定位 |\n| `max` | `number` | — | 同时可见条数;超出丢掉最旧一条(仅服务队列) |\n| `teleport` | `boolean` | `true` | 浮层 Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | 挂载目标 |\n| `auto` | `boolean` | — | — |\n\n### ToastMessage\n\n| 字段 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `id` | `string \\| number` | — | 唯一键 |\n| `summary` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | 标题 |\n| `detail` | 同上 | — | 详情 |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| …` | `'info'` | 语义色 |\n| `closable` | `boolean` | `true` | 关闭按钮 |\n| `life` | `number` | API 默认 `3000` | 自动关闭毫秒 |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | DOM 透传,见 [样式与 attrs](/docs/attrs). |\n\n\n## Events\n\n| 事件名 | 参数 | 说明 |\n| --- | --- | --- |\n| `close` | `ToastMessage` | 点击关闭;受控模式下由调用方移除 |\n\n## Slots\n\n无插槽;通过 `messages` prop 或 toast API 驱动。\n\n## 类型\n\n<h4 id=\"ToastMessage\">ToastMessage</h4>\n\n完整定义见源码 `types.ts`。\n\n```ts\ninterface ToastMessage {\n id: string | number\n summary: MRenderable\n detail?: MRenderable\n severity?: ToastSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n}\n```\n"
22867
23219
  },
22868
23220
  "en-US": {
22869
23221
  "title": "Toast",
@@ -22872,7 +23224,7 @@
22872
23224
  {
22873
23225
  "id": "overview",
22874
23226
  "title": "",
22875
- "body": "# Toast\n\nCorner notifications with a title and optional detail. Use the `toast` API, or keep rendering with a controlled `:messages` list.\n\nVs [Message](/components/Message): Message is the **default** for short single-line feedback; Toast is for `summary` / `detail` or corner notifications. `max` applies to the service queue only.\n\n> Selection guide: [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md).\n\nDo **not** use `toast.add({ summary: 'Saved' })` when `message.success('Saved')` is enough."
23227
+ "body": "# Toast\n\nCorner notifications with a title and optional detail. Use the `toast` API, or keep rendering with a controlled `:messages` list.\n\nVs [Message](/components/Message): Message is the **default** for short single-line feedback; Toast is for `summary` / `detail` or corner notifications. `max` applies to the service queue only.\n\n> Selection guide: [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md).\n\nDo **not** use `toast.add({ summary: 'Saved' })` when `message.success('Saved')` is enough."
22876
23228
  },
22877
23229
  {
22878
23230
  "id": "import",
@@ -22920,7 +23272,7 @@
22920
23272
  "body": "<h4 id=\"ToastMessage\">ToastMessage</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface ToastMessage {\n id: string | number\n summary: MRenderable\n detail?: MRenderable\n severity?: ToastSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n}\n```"
22921
23273
  }
22922
23274
  ],
22923
- "markdown": "---\ntitle: Toast\ncategory: 05 / FEEDBACK\ndescription: Corner floating notifications with API and controlled lists.\n---\n\n# Toast\n\nCorner notifications with a title and optional detail. Use the `toast` API, or keep rendering with a controlled `:messages` list.\n\nVs [Message](/components/Message): Message is the **default** for short single-line feedback; Toast is for `summary` / `detail` or corner notifications. `max` applies to the service queue only.\n\n> Selection guide: [`feedback-message-vs-toast.md`](../../../../design-kit/docs/feedback-message-vs-toast.md).\n\nDo **not** use `toast.add({ summary: 'Saved' })` when `message.success('Saved')` is enough.\n\n## Import\n\n```ts\nimport { MToast, toast, useToast } from 'morya-ui'\n```\n\n## API\n\n```vue preview src=\"./demos/Api.en.vue\"\n```\n\n## Custom content\n\n`summary` / `detail` also accept strings, `h()` VNodes, components, or render factories.\n\n```vue preview src=\"./demos/CustomContent.en.vue\"\n```\n\n## Controlled\n\nYou can still manage the list yourself with `messages` + `close`.\n\n```vue preview src=\"./demos/Controlled.vue\"\n```\n\n## Methods\n\n| Method | Description |\n| --- | --- |\n| `toast.success / info / warn / error` | Add by severity |\n| `toast.add(options)` | Add one |\n| `toast.remove(id)` / `toast.close(id)` | Remove |\n| `toast.clear()` / `toast.closeAll()` / `toast.destroyAll()` | Clear all |\n| `toast.setDefaults({ position, max })` | Default corner and concurrency cap |\n\nA string argument is treated as `summary`. Default `life` is `3000`; use `0` to keep open.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `messages` | `ToastMessage[]` | — | Controlled list; omit to bind the `toast` service queue |\n| `position` | `'top-right' \\| 'top-left' \\| 'bottom-right' \\| 'bottom-left'` | `'top-right'` | Container placement |\n| `max` | `number` | — | Max visible items; oldest is dropped (service queue only) |\n| `teleport` | `boolean` | `true` | Whether to Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Mount target |\n\n### ToastMessage\n\n| Field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `id` | `string \\| number` | — | Unique key |\n| `summary` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | Title |\n| `detail` | same as above | — | Detail |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| …` | `'info'` | Tone |\n| `closable` | `boolean` | `true` | Close button |\n| `life` | `number` | API default `3000` | Auto-close ms |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `close` | `ToastMessage` | Close clicked; remove it yourself in controlled mode |\n\n## Slots\n\nNo slots; driven by the `messages` prop or toast API.\n\n## Types\n\n<h4 id=\"ToastMessage\">ToastMessage</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface ToastMessage {\r\n id: string | number\r\n summary: MRenderable\r\n detail?: MRenderable\r\n severity?: ToastSeverity\r\n closable?: boolean\r\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\r\n life?: number\r\n}\n```\n"
23275
+ "markdown": "---\ntitle: Toast\ncategory: 05 / FEEDBACK\ndescription: Corner floating notifications with API and controlled lists.\n---\n\n# Toast\n\nCorner notifications with a title and optional detail. Use the `toast` API, or keep rendering with a controlled `:messages` list.\n\nVs [Message](/components/Message): Message is the **default** for short single-line feedback; Toast is for `summary` / `detail` or corner notifications. `max` applies to the service queue only.\n\n> Selection guide: [`feedback.md`](../../../../design-kit/.agents/skills/morya-ui-pages/references/feedback.md).\n\nDo **not** use `toast.add({ summary: 'Saved' })` when `message.success('Saved')` is enough.\n\n## Import\n\n```ts\nimport { MToast, toast, useToast } from 'morya-ui'\n```\n\n## API\n\n```vue preview src=\"./demos/Api.en.vue\"\n```\n\n## Custom content\n\n`summary` / `detail` also accept strings, `h()` VNodes, components, or render factories.\n\n```vue preview src=\"./demos/CustomContent.en.vue\"\n```\n\n## Controlled\n\nYou can still manage the list yourself with `messages` + `close`.\n\n```vue preview src=\"./demos/Controlled.vue\"\n```\n\n## Methods\n\n| Method | Description |\n| --- | --- |\n| `toast.success / info / warn / error` | Add by severity |\n| `toast.add(options)` | Add one |\n| `toast.remove(id)` / `toast.close(id)` | Remove |\n| `toast.clear()` / `toast.closeAll()` / `toast.destroyAll()` | Clear all |\n| `toast.setDefaults({ position, max })` | Default corner and concurrency cap |\n\nA string argument is treated as `summary`. Default `life` is `3000`; use `0` to keep open.\n\n## Props\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `messages` | `ToastMessage[]` | — | Controlled list; omit to bind the `toast` service queue |\n| `position` | `'top-right' \\| 'top-left' \\| 'bottom-right' \\| 'bottom-left'` | `'top-right'` | Container placement |\n| `max` | `number` | — | Max visible items; oldest is dropped (service queue only) |\n| `teleport` | `boolean` | `true` | Whether to Teleport |\n| `appendTo` | `string \\| HTMLElement \\| 'self' \\| false` | `'body'` | Mount target |\n\n### ToastMessage\n\n| Field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `id` | `string \\| number` | — | Unique key |\n| `summary` | `string \\| number \\| VNode \\| Component \\| (() => VNodeChild)` | — | Title |\n| `detail` | same as above | — | Detail |\n| `severity` | `'success' \\| 'info' \\| 'warn' \\| 'error' \\| …` | `'info'` | Tone |\n| `closable` | `boolean` | `true` | Close button |\n| `life` | `number` | API default `3000` | Auto-close ms |\n| `pt` | [RootPassThrough](/docs/types#RootPassThrough) `{ root? }` | — | Pass-through; see [Styling & attrs](/docs/attrs). |\n\n\n## Events\n\n| Event | Payload | Description |\n| --- | --- | --- |\n| `close` | `ToastMessage` | Close clicked; remove it yourself in controlled mode |\n\n## Slots\n\nNo slots; driven by the `messages` prop or toast API.\n\n## Types\n\n<h4 id=\"ToastMessage\">ToastMessage</h4>\n\nSee source `types.ts` for the full definition.\n\n```ts\ninterface ToastMessage {\n id: string | number\n summary: MRenderable\n detail?: MRenderable\n severity?: ToastSeverity\n closable?: boolean\n /** Auto-close delay in ms. `0` keeps it open. Default `3000` for API calls. */\n life?: number\n}\n```\n"
22924
23276
  }
22925
23277
  }
22926
23278
  },
@@ -24745,7 +25097,7 @@
24745
25097
  "zh-CN": {
24746
25098
  "title": "快速上手",
24747
25099
  "description": "安装依赖、引入样式,并渲染第一个组件。",
24748
- "markdown": "---\ntitle: 快速上手\norder: 2\ndescription: 安装依赖、引入样式,并渲染第一个组件。\n---\n\n# 快速上手\n\n> 在线文档:[morya-space.github.io/morya-ui](https://morya-space.github.io/morya-ui/) · 源码:[GitHub](https://github.com/morya-space/morya-ui) · npm:[`morya-ui`](https://www.npmjs.com/package/morya-ui)\n\n## 安装\n\n**在应用项目中(npm / pnpm / yarn):**\n\n```bash\npnpm add morya-ui\n```\n\n也可以用:\n\n```bash\nnpx @morya-ui/setup app\n```\n\n会安装依赖,并尽量在入口注入样式。更多命令与选项见 [一键接入](/docs/setup)。需要 Vue 3(推荐 3.5 及以上)。主题 token、亮暗切换与动效 API 均包含在 `morya-ui` 中。Agent Skill / MCP 见 [AI 接入](/docs/ai-setup)。\n\n## 选择使用方式\n\n本库同时支持**全量**与**按需**两种消费方式,按项目需求任选其一(同一应用内建议保持一致)。\n\n| | 全量 | 按需 |\n| --- | --- | --- |\n| 典型场景 | 组件用得较多、希望快速上手 | 打包体积敏感、只用少量组件 |\n| 组件来源 | `app.use(MoryaUI)` 或 `morya-ui` 按名导入 | `morya-ui/button` 等子路径,或 Vite 自动解析 |\n| 样式 | 入口引入 `morya-ui/styles.css` | 子路径自动带入(含 theme + 依赖组件样式) |\n| JS 体积 | 全量注册会打入完整组件;按名导入可 tree-shake | 仅打入用到的组件及其依赖 |\n\n## 全量用法\n\n### 1. 插件注册(推荐的全量方式)\n\n在应用入口引入**全量样式**,并通过插件一次注册所有组件:\n\n```ts\nimport MoryaUI from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).use(MoryaUI).mount('#app')\n```\n\n模板中可直接使用 `<MButton>`、`<MInput>` 等,无需逐个 import。\n\n### 2. 按名导入 + 全量样式\n\n不注册插件、在 SFC 中按需写 import,JS 可由构建工具 tree-shake,但样式仍需全量 CSS:\n\n```ts\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).mount('#app')\n```\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton, MInput } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst name = ref('')\n</script>\n\n<template>\n <div style=\"display: grid; gap: 1rem; max-width: 20rem\">\n <MInput v-model=\"name\" label=\"名称\" placeholder=\"输入名称\" />\n <MButton label=\"提交\" @click=\"() => undefined\" />\n </div>\n</template>\n```\n\n## 按需用法\n\n### 1. 子路径导入\n\n从 kebab-case 子路径导入(如 `button`、`input-password`、`tree-select`)。会带上组件 JS、内部依赖与对应样式,**无需**再引 `morya-ui/styles.css`:\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\n仅要样式时:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. 自动按需(Vite)\n\n安装 `unplugin-vue-components` 后,在 `vite.config.ts` 中配置解析器,模板里可直接写 `<MButton>`:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n按需模式下,`createMoryaUI({ components: false })` 仍可注入全局配置而不注册组件。\n\n## 可选:应用级全局配置\n\n`createMoryaUI` 会写入全局默认值,并默认注册全部组件:\n\n```ts\nimport { createMoryaUI } from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App)\n .use(\n createMoryaUI({\n appendTo: 'body',\n size: 'small',\n zIndex: 1100,\n }),\n )\n .mount('#app')\n```\n\n仅配置、不注册组件时使用 `components: false`。\n\n更多说明见 [全局配置](/docs/config)。\n\n## 主题 API\n\n亮暗切换等能力从同一包引入:\n\n```ts\nimport { useTheme } from 'morya-ui'\n\nconst { toggleTheme } = useTheme()\n```\n\n详见 [主题](/docs/theme)。\n\n## 启动本仓库文档站\n\n```bash\npnpm --filter morya-ui dev\n# http://localhost:5182\n\n# 构建静态文档站\npnpm --filter morya-ui build:docs\n```\n",
25100
+ "markdown": "---\ntitle: 快速上手\norder: 2\ndescription: 安装依赖、引入样式,并渲染第一个组件。\n---\n\n# 快速上手\n\n> 在线文档:[morya-space.github.io/morya-ui](https://morya-space.github.io/morya-ui/) · 源码:[GitHub](https://github.com/morya-space/morya-ui) · npm:[`morya-ui`](https://www.npmjs.com/package/morya-ui)\n\n## 安装\n\n**在应用项目中(npm / pnpm / yarn):**\n\n```bash\npnpm add morya-ui\n```\n\n也可以用:\n\n```bash\nnpx @morya-ui/setup app\n```\n\n会安装依赖,并尽量在入口注入样式。更多命令与选项见 [一键接入](/docs/setup)。需要 Vue 3(推荐 3.5 及以上)。主题 token、亮暗切换与动效 API 均包含在 `morya-ui` 中。Agent Skill / MCP 见 [AI 接入](/docs/ai-setup)。\n\n## 选择使用方式\n\n本库同时支持**全量**与**按需**两种消费方式,按项目需求任选其一(同一应用内建议保持一致)。\n\n| | 全量 | 按需 |\n| --- | --- | --- |\n| 典型场景 | 组件用得较多、希望快速上手 | 打包体积敏感、只用少量组件 |\n| 组件来源 | `app.use(MoryaUI)` 或 `morya-ui` 按名导入 | `morya-ui/button` 等子路径,或 Vite 自动解析 |\n| 样式 | 入口引入 `morya-ui/styles.css` | 子路径自动带入(含 theme + 依赖组件样式) |\n| JS 体积 | 全量注册会打入完整组件;按名导入可 tree-shake | 仅打入用到的组件及其依赖 |\n\n## 全量用法\n\n### 1. 插件注册(推荐的全量方式)\n\n在应用入口引入**全量样式**,并通过插件一次注册所有组件:\n\n```ts\nimport MoryaUI from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).use(MoryaUI).mount('#app')\n```\n\n模板中可直接使用 `<MButton>`、`<MInput>` 等,无需逐个 import。\n\n### 2. 按名导入 + 全量样式\n\n不注册插件、在 SFC 中按需写 import,JS 可由构建工具 tree-shake,但样式仍需全量 CSS:\n\n```ts\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).mount('#app')\n```\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton, MInput } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst name = ref('')\n</script>\n\n<template>\n <div style=\"display: grid; gap: 1rem; max-width: 20rem\">\n <MInput v-model=\"name\" label=\"名称\" placeholder=\"输入名称\" />\n <MButton label=\"提交\" @click=\"() => undefined\" />\n </div>\n</template>\n```\n\n## 按需用法\n\n### 1. 子路径导入\n\n从 kebab-case 子路径导入(如 `button`、`input-password`、`tree-select`)。会带上组件 JS、类型声明、内部依赖与对应样式,**无需**再引 `morya-ui/styles.css`。Props 等类型从同一路径导入,例如 `import type { ButtonProps } from 'morya-ui/button'`。\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\n仅要样式时:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. 自动按需(Vite)\n\n安装 `unplugin-vue-components` 后,在 `vite.config.ts` 中配置解析器,模板里可直接写 `<MButton>`:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n dts: 'src/components.d.ts',\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n`dts` 会写出组件声明,编辑器和 `vue-tsc` 据此识别模板里的组件;该文件需落在 `tsconfig.json` 的 `include` 中。按需模式下,`createMoryaUI({ components: false })` 仍可注入全局配置而不注册组件。\n\n## 可选:应用级全局配置\n\n`createMoryaUI` 会写入全局默认值,并默认注册全部组件:\n\n```ts\nimport { createMoryaUI } from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App)\n .use(\n createMoryaUI({\n appendTo: 'body',\n size: 'small',\n zIndex: 1100,\n }),\n )\n .mount('#app')\n```\n\n仅配置、不注册组件时使用 `components: false`。\n\n更多说明见 [全局配置](/docs/config)。\n\n## 主题 API\n\n亮暗切换等能力从同一包引入:\n\n```ts\nimport { useTheme } from 'morya-ui'\n\nconst { toggleTheme } = useTheme()\n```\n\n详见 [主题](/docs/theme)。\n\n## 启动本仓库文档站\n\n```bash\npnpm --filter morya-ui dev\n# http://localhost:5182\n\n# 构建静态文档站\npnpm --filter morya-ui build:docs\n```\n",
24749
25101
  "sections": [
24750
25102
  {
24751
25103
  "title": "",
@@ -24770,7 +25122,7 @@
24770
25122
  {
24771
25123
  "title": "按需用法",
24772
25124
  "id": "按需用法",
24773
- "body": "### 1. 子路径导入\n\n从 kebab-case 子路径导入(如 `button`、`input-password`、`tree-select`)。会带上组件 JS、内部依赖与对应样式,**无需**再引 `morya-ui/styles.css`:\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\n仅要样式时:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. 自动按需(Vite)\n\n安装 `unplugin-vue-components` 后,在 `vite.config.ts` 中配置解析器,模板里可直接写 `<MButton>`:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n按需模式下,`createMoryaUI({ components: false })` 仍可注入全局配置而不注册组件。"
25125
+ "body": "### 1. 子路径导入\n\n从 kebab-case 子路径导入(如 `button`、`input-password`、`tree-select`)。会带上组件 JS、类型声明、内部依赖与对应样式,**无需**再引 `morya-ui/styles.css`。Props 等类型从同一路径导入,例如 `import type { ButtonProps } from 'morya-ui/button'`。\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\n仅要样式时:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. 自动按需(Vite)\n\n安装 `unplugin-vue-components` 后,在 `vite.config.ts` 中配置解析器,模板里可直接写 `<MButton>`:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n dts: 'src/components.d.ts',\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n`dts` 会写出组件声明,编辑器和 `vue-tsc` 据此识别模板里的组件;该文件需落在 `tsconfig.json` 的 `include` 中。按需模式下,`createMoryaUI({ components: false })` 仍可注入全局配置而不注册组件。"
24774
25126
  },
24775
25127
  {
24776
25128
  "title": "可选:应用级全局配置",
@@ -24792,7 +25144,7 @@
24792
25144
  "en-US": {
24793
25145
  "title": "Quick start",
24794
25146
  "description": "Install the package, import styles, and render the first component.",
24795
- "markdown": "---\ntitle: Quick start\norder: 2\ndescription: Install the package, import styles, and render the first component.\n---\n\n# Quick start\n\n> Live docs: [morya-space.github.io/morya-ui](https://morya-space.github.io/morya-ui/) · Source: [GitHub](https://github.com/morya-space/morya-ui) · npm: [`morya-ui`](https://www.npmjs.com/package/morya-ui)\n\n## Install\n\n**In an application (npm / pnpm / yarn):**\n\n```bash\npnpm add morya-ui\n```\n\nOr:\n\n```bash\nnpx @morya-ui/setup app\n```\n\nThis installs the dependency and tries to inject styles at the app entry. More commands and options: [One-shot setup](/docs/setup). Requires Vue 3 (3.5+ recommended). Theme tokens, color-mode switching, and motion APIs are all included in `morya-ui`. For Agent skill / MCP, see [AI setup](/docs/ai-setup).\n\nAfter cloning this repository, run `pnpm install`. The docs playground resolves source via Vite aliases (see `playground/vite.config.ts`).\n\nTo debug from another app, use `link:` / `pnpm link` plus Vite aliases. A plain npm install always resolves `dist/`.\n\n## Choose an import mode\n\nThe library supports **full** and **on-demand** usage. Pick one per app (stay consistent within a project).\n\n| | Full | On-demand |\n| --- | --- | --- |\n| Best for | Many components, fastest setup | Bundle size, few components |\n| Components | `app.use(MoryaUI)` or named imports from `morya-ui` | `morya-ui/button` subpaths, or Vite auto-resolver |\n| Styles | Import `morya-ui/styles.css` at entry | Bundled with subpath imports (theme + deps) |\n| JS size | Full plugin bundles all components; named imports tree-shake | Only used components and their deps |\n\n## Full usage\n\n### 1. Plugin registration (recommended full mode)\n\nImport the **full stylesheet** and register all components once:\n\n```ts\nimport MoryaUI from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).use(MoryaUI).mount('#app')\n```\n\nTemplates can use `<MButton>`, `<MInput>`, etc. without per-file imports.\n\n### 2. Named imports + full CSS\n\nSkip the plugin; import components in SFCs. JS can tree-shake, but styles still need the full CSS file:\n\n```ts\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).mount('#app')\n```\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton, MInput } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst name = ref('')\n</script>\n\n<template>\n <div style=\"display: grid; gap: 1rem; max-width: 20rem\">\n <MInput v-model=\"name\" label=\"Name\" placeholder=\"Enter a name\" />\n <MButton label=\"Submit\" @click=\"() => undefined\" />\n </div>\n</template>\n```\n\n## On-demand usage\n\n### 1. Subpath imports\n\nImport from kebab-case subpaths (e.g. `button`, `input-password`, `tree-select`). Each entry bundles component JS, internal dependencies, and styles — **no** `morya-ui/styles.css` required:\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\nStyles only:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. Auto on-demand (Vite)\n\nWith `unplugin-vue-components`, add the resolver so templates can use `<MButton>` without manual imports:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({ resolvers: [MoryaUIResolver()] }),\n ],\n})\n```\n\nIn on-demand mode, `createMoryaUI({ components: false })` still applies global config without registering components.\n\n## Optional: app-level defaults\n\n`createMoryaUI` applies global defaults and registers all components by default:\n\n```ts\nimport { createMoryaUI } from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App)\n .use(\n createMoryaUI({\n appendTo: 'body',\n size: 'small',\n zIndex: 1100,\n }),\n )\n .mount('#app')\n```\n\nUse `components: false` for config-only install.\n\nSee [Configuration](/docs/config) for details.\n\n## Theme API\n\nColor-mode helpers come from the same package:\n\n```ts\nimport { useTheme } from 'morya-ui'\n\nconst { toggleTheme } = useTheme()\n```\n\nSee [Theme](/docs/theme).\n\n## Run this docs site\n\n```bash\npnpm --filter morya-ui dev\n# http://localhost:5182\n\n# Build the static docs site\npnpm --filter morya-ui build:docs\n```\n",
25147
+ "markdown": "---\ntitle: Quick start\norder: 2\ndescription: Install the package, import styles, and render the first component.\n---\n\n# Quick start\n\n> Live docs: [morya-space.github.io/morya-ui](https://morya-space.github.io/morya-ui/) · Source: [GitHub](https://github.com/morya-space/morya-ui) · npm: [`morya-ui`](https://www.npmjs.com/package/morya-ui)\n\n## Install\n\n**In an application (npm / pnpm / yarn):**\n\n```bash\npnpm add morya-ui\n```\n\nOr:\n\n```bash\nnpx @morya-ui/setup app\n```\n\nThis installs the dependency and tries to inject styles at the app entry. More commands and options: [One-shot setup](/docs/setup). Requires Vue 3 (3.5+ recommended). Theme tokens, color-mode switching, and motion APIs are all included in `morya-ui`. For Agent skill / MCP, see [AI setup](/docs/ai-setup).\n\nAfter cloning this repository, run `pnpm install`. The docs playground resolves source via Vite aliases (see `playground/vite.config.ts`).\n\nTo debug from another app, use `link:` / `pnpm link` plus Vite aliases. A plain npm install always resolves `dist/`.\n\n## Choose an import mode\n\nThe library supports **full** and **on-demand** usage. Pick one per app (stay consistent within a project).\n\n| | Full | On-demand |\n| --- | --- | --- |\n| Best for | Many components, fastest setup | Bundle size, few components |\n| Components | `app.use(MoryaUI)` or named imports from `morya-ui` | `morya-ui/button` subpaths, or Vite auto-resolver |\n| Styles | Import `morya-ui/styles.css` at entry | Bundled with subpath imports (theme + deps) |\n| JS size | Full plugin bundles all components; named imports tree-shake | Only used components and their deps |\n\n## Full usage\n\n### 1. Plugin registration (recommended full mode)\n\nImport the **full stylesheet** and register all components once:\n\n```ts\nimport MoryaUI from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).use(MoryaUI).mount('#app')\n```\n\nTemplates can use `<MButton>`, `<MInput>`, etc. without per-file imports.\n\n### 2. Named imports + full CSS\n\nSkip the plugin; import components in SFCs. JS can tree-shake, but styles still need the full CSS file:\n\n```ts\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App).mount('#app')\n```\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton, MInput } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst name = ref('')\n</script>\n\n<template>\n <div style=\"display: grid; gap: 1rem; max-width: 20rem\">\n <MInput v-model=\"name\" label=\"Name\" placeholder=\"Enter a name\" />\n <MButton label=\"Submit\" @click=\"() => undefined\" />\n </div>\n</template>\n```\n\n## On-demand usage\n\n### 1. Subpath imports\n\nImport from kebab-case subpaths (e.g. `button`, `input-password`, `tree-select`). Each entry bundles component JS, type declarations, internal dependencies, and styles — **no** `morya-ui/styles.css` required. Prop types come from the same path, for example `import type { ButtonProps } from 'morya-ui/button'`.\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\nStyles only:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. Auto on-demand (Vite)\n\nWith `unplugin-vue-components`, add the resolver so templates can use `<MButton>` without manual imports:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n dts: 'src/components.d.ts',\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n`dts` writes component declarations so the editor and `vue-tsc` can resolve components used in templates. That file must be covered by `include` in `tsconfig.json`. In on-demand mode, `createMoryaUI({ components: false })` still applies global config without registering components.\n\n## Optional: app-level defaults\n\n`createMoryaUI` applies global defaults and registers all components by default:\n\n```ts\nimport { createMoryaUI } from 'morya-ui'\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport 'morya-ui/styles.css'\n\ncreateApp(App)\n .use(\n createMoryaUI({\n appendTo: 'body',\n size: 'small',\n zIndex: 1100,\n }),\n )\n .mount('#app')\n```\n\nUse `components: false` for config-only install.\n\nSee [Configuration](/docs/config) for details.\n\n## Theme API\n\nColor-mode helpers come from the same package:\n\n```ts\nimport { useTheme } from 'morya-ui'\n\nconst { toggleTheme } = useTheme()\n```\n\nSee [Theme](/docs/theme).\n\n## Run this docs site\n\n```bash\npnpm --filter morya-ui dev\n# http://localhost:5182\n\n# Build the static docs site\npnpm --filter morya-ui build:docs\n```\n",
24796
25148
  "sections": [
24797
25149
  {
24798
25150
  "title": "",
@@ -24817,7 +25169,7 @@
24817
25169
  {
24818
25170
  "title": "On-demand usage",
24819
25171
  "id": "on-demand-usage",
24820
- "body": "### 1. Subpath imports\n\nImport from kebab-case subpaths (e.g. `button`, `input-password`, `tree-select`). Each entry bundles component JS, internal dependencies, and styles — **no** `morya-ui/styles.css` required:\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\nStyles only:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. Auto on-demand (Vite)\n\nWith `unplugin-vue-components`, add the resolver so templates can use `<MButton>` without manual imports:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({ resolvers: [MoryaUIResolver()] }),\n ],\n})\n```\n\nIn on-demand mode, `createMoryaUI({ components: false })` still applies global config without registering components."
25172
+ "body": "### 1. Subpath imports\n\nImport from kebab-case subpaths (e.g. `button`, `input-password`, `tree-select`). Each entry bundles component JS, type declarations, internal dependencies, and styles — **no** `morya-ui/styles.css` required. Prop types come from the same path, for example `import type { ButtonProps } from 'morya-ui/button'`.\n\n```ts\nimport { MButton } from 'morya-ui/button'\nimport { MInput } from 'morya-ui/input'\n```\n\nStyles only:\n\n```ts\nimport 'morya-ui/button/style'\nimport 'morya-ui/button/style.css'\n```\n\n### 2. Auto on-demand (Vite)\n\nWith `unplugin-vue-components`, add the resolver so templates can use `<MButton>` without manual imports:\n\n```ts\nimport { MoryaUIResolver } from 'morya-ui/resolver'\nimport Components from 'unplugin-vue-components/vite'\n\nexport default defineConfig({\n plugins: [\n vue(),\n Components({\n dts: 'src/components.d.ts',\n resolvers: [MoryaUIResolver()],\n }),\n ],\n})\n```\n\n`dts` writes component declarations so the editor and `vue-tsc` can resolve components used in templates. That file must be covered by `include` in `tsconfig.json`. In on-demand mode, `createMoryaUI({ components: false })` still applies global config without registering components."
24821
25173
  },
24822
25174
  {
24823
25175
  "title": "Optional: app-level defaults",
@@ -24849,7 +25201,7 @@
24849
25201
  "zh-CN": {
24850
25202
  "title": "一键接入",
24851
25203
  "description": "用 @morya-ui/setup 安装组件库,并按需写入样式、Agent 配置与 MCP。",
24852
- "markdown": "---\ntitle: 一键接入\norder: 3\ndescription: 用 @morya-ui/setup 安装组件库,并按需写入样式、Agent 配置与 MCP。\n---\n\n# 一键接入\n\n[`@morya-ui/setup`](https://www.npmjs.com/package/@morya-ui/setup) 用于在业务 Vue 项目中接入 `morya-ui`:安装依赖、注入样式,并可一并写入 Agent Skill、Cursor 规则与 MCP。手写安装见 [快速上手](/docs/quick-start);AI 生成页面的约定见 [AI 接入](/docs/ai-setup)。\n\n## 命令\n\n在业务项目根目录执行:\n\n```bash\nnpx @morya-ui/setup\n```\n\n默认会:\n\n1. 安装 `morya-ui`(按锁文件选用 pnpm / yarn / npm)\n2. 复制 `DESIGN.md`、Agent Skill、Cursor rules、黄金样例与检查脚本\n3. 合并 `.cursor/mcp.json`,接入 [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. 尝试在入口注入 `import 'morya-ui/styles.css'`,并写入 `morya-app-shell.css`\n5. 若缺失则追加 `check:colors` 脚本\n\n也可以按场景选用:\n\n```bash\n# 只安装组件库并注入样式\nnpx @morya-ui/setup app\n\n# 已装库时,只写入 AI 配置与 MCP\nnpx @morya-ui/setup ai\n```\n\n完成后若写入了 MCP,请 **重启 Cursor**(或重载 MCP)。生成页面前让 Agent 先读 `DESIGN.md`。\n\n## 选项\n\n| Flag | 说明 |\n| --- | --- |\n| `--cwd <dir>` | 目标项目根(默认当前目录) |\n| `--pm pnpm\\|yarn\\|npm` | 指定包管理器 |\n| `--force` | 覆盖已有模板文件与 `morya-ui` MCP 条目 |\n| `--dry-run` | 只打印将要执行的操作 |\n| `--skip-install` | 不安装依赖 |\n| `--skip-template` | 不复制 skill / rules / docs |\n| `--skip-mcp` | 不写 MCP 配置 |\n| `--skip-styles` | 不注入样式 import |\n| `--skip-scripts` | 不改 `package.json` scripts |\n\n默认 **不覆盖** 已有文件;只有 `--force` 才会覆盖模板与 MCP 条目。\n\n示例:只补 MCP:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```\n\n## 会落到项目里的内容\n\n| 路径 | 作用 |\n| --- | --- |\n| `DESIGN.md` | AI 设计第一信源 |\n| `.agents/skills/morya-ui-pages/` | 页面生成 Agent Skill(见 [Agent Skill](/docs/agent-skill)) |\n| `.cursor/rules/` | Cursor 常驻规则 |\n| `docs/`、`design-tokens/`、`src/examples/` | 组件索引、黄金样例、令牌 |\n| `scripts/check-raw-colors.mjs` | 裸色值扫描 |\n| `.cursor/mcp.json` | Cursor MCP(`npx -y @morya-ui/mcp`) |\n| `src/styles/morya-app-shell.css` | 页面高度链(默认命令或 `app` 写入) |\n\n模板源在仓库 [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit)。CLI 不调用 `app.use(MoryaUI)`,也不改 `App.vue`。\n\n## 冲突策略\n\n- 模板文件与 `.cursor/rules/*`:目标已存在则跳过(除非 `--force`)\n- `.cursor/mcp.json`:合并其它 server;已有 `morya-ui` 条目则跳过(除非 `--force`)\n- `check:colors`:仅在缺失时追加(除非 `--force`)\n- 样式:找到入口且尚未引入时才注入\n\n## 下一步\n\n- [快速上手](/docs/quick-start):组件用法与最小示例 \n- [AI 接入](/docs/ai-setup):用 AI 生成业务页面时如何配合 Skill / MCP \n- [Agent Skill](/docs/agent-skill) · [Agent MCP](/docs/mcp) \n- [组件](/components):浏览 API 与预览\n",
25204
+ "markdown": "---\ntitle: 一键接入\norder: 3\ndescription: 用 @morya-ui/setup 安装组件库,并按需写入样式、Agent 配置与 MCP。\n---\n\n# 一键接入\n\n[`@morya-ui/setup`](https://www.npmjs.com/package/@morya-ui/setup) 用于在业务 Vue 项目中接入 `morya-ui`:安装依赖、注入样式,并可一并写入 Agent Skill、Cursor 规则与 MCP。手写安装见 [快速上手](/docs/quick-start);AI 生成页面的约定见 [AI 接入](/docs/ai-setup)。\n\n## 命令\n\n在业务项目根目录执行:\n\n```bash\nnpx @morya-ui/setup\n```\n\n默认会:\n\n1. 安装 `morya-ui`(按锁文件选用 pnpm / yarn / npm)\n2. 复制 `DESIGN.md`、Agent Skill、Cursor rules 与检查脚本\n3. 合并 `.cursor/mcp.json`,接入 [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. 尝试在入口注入 `import 'morya-ui/styles.css'`\n5. 若缺失则追加 `check:colors` 脚本\n\n也可以按场景选用:\n\n```bash\n# 只安装组件库并注入样式\nnpx @morya-ui/setup app\n\n# 已装库时,只写入 AI 配置与 MCP\nnpx @morya-ui/setup ai\n\n# 非交互:默认 skill / 指定 / 全部\nnpx @morya-ui/setup ai --yes\nnpx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design\nnpx @morya-ui/setup ai --skills=all\n```\n\n TTY 下,`full` / `ai` 会提示勾选可选 Agent Skill(必选 `morya-ui-pages` 始终写入)。完成后若写入了 MCP,请 **重启 Cursor**(或重载 MCP)。生成页面前让 Agent 先读 `DESIGN.md`。\n\n## 选项\n\n| Flag | 说明 |\n| --- | --- |\n| `--cwd <dir>` | 目标项目根(默认当前目录) |\n| `--pm pnpm\\|yarn\\|npm` | 指定包管理器 |\n| `--skills <list>` | 逗号分隔的 skill id,或 `all`(跳过交互提示) |\n| `--yes` / `-y` | 使用默认 skill,不提示 |\n| `--force` | 覆盖已有模板文件与 `morya-ui` MCP 条目 |\n| `--dry-run` | 只打印将要执行的操作 |\n| `--skip-install` | 不安装依赖 |\n| `--skip-template` | 不复制 skill / rules / docs |\n| `--skip-mcp` | 不写 MCP 配置 |\n| `--skip-styles` | 不注入样式 import |\n| `--skip-scripts` | 不改 `package.json` scripts |\n\n默认 **不覆盖** 已有文件;只有 `--force` 才会覆盖模板与 MCP 条目。\n\n### Skills\n\n| Id | 默认 | 作用 |\n| --- | --- | --- |\n| `morya-ui-pages` | 必选 | 用 `M*` + 黄金布局生成页面 |\n| `frontend-design` | 可选 | Express / 品牌向视觉味觉 |\n| `fixing-accessibility` | 可选 | 无障碍审计与定向修复 |\n\n目录:[`packages/setup/catalog/skills.json`](https://github.com/morya-space/morya-ui/blob/main/packages/setup/catalog/skills.json)。\n\n示例:只补 MCP:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```\n\n## 会落到项目里的内容\n\n| 路径 | 作用 |\n| --- | --- |\n| `DESIGN.md` | AI 设计第一信源(原则、应用根、令牌摘要、禁止项) |\n| `.agents/skills/morya-ui-pages/` | 页面生成 Agent Skill(见 [Agent Skill](/docs/agent-skill)) |\n| `.agents/skills/<optional>/` | 勾选时写入的 companion skill |\n| `.cursor/rules/` | Cursor 常驻规则 |\n| `scripts/check-raw-colors.mjs` | 裸色值扫描 |\n| `.cursor/mcp.json` | Cursor MCP(`npx -y @morya-ui/mcp`) |\n\n模板源在仓库 [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit)。CLI 不调用 `app.use(MoryaUI)`,也不改 `App.vue`。\n\n## 冲突策略\n\n- 模板文件与 `.cursor/rules/*`:目标已存在则跳过(除非 `--force`)\n- `.cursor/mcp.json`:合并其它 server;已有 `morya-ui` 条目则跳过(除非 `--force`)\n- `check:colors`:仅在缺失时追加(除非 `--force`)\n- 样式:找到入口且尚未引入时才注入\n\n## 下一步\n\n- [快速上手](/docs/quick-start):组件用法与最小示例 \n- [AI 接入](/docs/ai-setup):用 AI 生成业务页面时如何配合 Skill / MCP \n- [Agent Skill](/docs/agent-skill) · [Agent MCP](/docs/mcp) \n- [组件](/components):浏览 API 与预览\n",
24853
25205
  "sections": [
24854
25206
  {
24855
25207
  "title": "",
@@ -24859,17 +25211,17 @@
24859
25211
  {
24860
25212
  "title": "命令",
24861
25213
  "id": "命令",
24862
- "body": "在业务项目根目录执行:\n\n```bash\nnpx @morya-ui/setup\n```\n\n默认会:\n\n1. 安装 `morya-ui`(按锁文件选用 pnpm / yarn / npm)\n2. 复制 `DESIGN.md`、Agent Skill、Cursor rules、黄金样例与检查脚本\n3. 合并 `.cursor/mcp.json`,接入 [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. 尝试在入口注入 `import 'morya-ui/styles.css'`,并写入 `morya-app-shell.css`\n5. 若缺失则追加 `check:colors` 脚本\n\n也可以按场景选用:\n\n```bash\n# 只安装组件库并注入样式\nnpx @morya-ui/setup app\n\n# 已装库时,只写入 AI 配置与 MCP\nnpx @morya-ui/setup ai\n```\n\n完成后若写入了 MCP,请 **重启 Cursor**(或重载 MCP)。生成页面前让 Agent 先读 `DESIGN.md`。"
25214
+ "body": "在业务项目根目录执行:\n\n```bash\nnpx @morya-ui/setup\n```\n\n默认会:\n\n1. 安装 `morya-ui`(按锁文件选用 pnpm / yarn / npm)\n2. 复制 `DESIGN.md`、Agent Skill、Cursor rules 与检查脚本\n3. 合并 `.cursor/mcp.json`,接入 [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. 尝试在入口注入 `import 'morya-ui/styles.css'`\n5. 若缺失则追加 `check:colors` 脚本\n\n也可以按场景选用:\n\n```bash\n# 只安装组件库并注入样式\nnpx @morya-ui/setup app\n\n# 已装库时,只写入 AI 配置与 MCP\nnpx @morya-ui/setup ai\n\n# 非交互:默认 skill / 指定 / 全部\nnpx @morya-ui/setup ai --yes\nnpx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design\nnpx @morya-ui/setup ai --skills=all\n```\n\n TTY 下,`full` / `ai` 会提示勾选可选 Agent Skill(必选 `morya-ui-pages` 始终写入)。完成后若写入了 MCP,请 **重启 Cursor**(或重载 MCP)。生成页面前让 Agent 先读 `DESIGN.md`。"
24863
25215
  },
24864
25216
  {
24865
25217
  "title": "选项",
24866
25218
  "id": "选项",
24867
- "body": "| Flag | 说明 |\n| --- | --- |\n| `--cwd <dir>` | 目标项目根(默认当前目录) |\n| `--pm pnpm\\|yarn\\|npm` | 指定包管理器 |\n| `--force` | 覆盖已有模板文件与 `morya-ui` MCP 条目 |\n| `--dry-run` | 只打印将要执行的操作 |\n| `--skip-install` | 不安装依赖 |\n| `--skip-template` | 不复制 skill / rules / docs |\n| `--skip-mcp` | 不写 MCP 配置 |\n| `--skip-styles` | 不注入样式 import |\n| `--skip-scripts` | 不改 `package.json` scripts |\n\n默认 **不覆盖** 已有文件;只有 `--force` 才会覆盖模板与 MCP 条目。\n\n示例:只补 MCP:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```"
25219
+ "body": "| Flag | 说明 |\n| --- | --- |\n| `--cwd <dir>` | 目标项目根(默认当前目录) |\n| `--pm pnpm\\|yarn\\|npm` | 指定包管理器 |\n| `--skills <list>` | 逗号分隔的 skill id,或 `all`(跳过交互提示) |\n| `--yes` / `-y` | 使用默认 skill,不提示 |\n| `--force` | 覆盖已有模板文件与 `morya-ui` MCP 条目 |\n| `--dry-run` | 只打印将要执行的操作 |\n| `--skip-install` | 不安装依赖 |\n| `--skip-template` | 不复制 skill / rules / docs |\n| `--skip-mcp` | 不写 MCP 配置 |\n| `--skip-styles` | 不注入样式 import |\n| `--skip-scripts` | 不改 `package.json` scripts |\n\n默认 **不覆盖** 已有文件;只有 `--force` 才会覆盖模板与 MCP 条目。\n\n### Skills\n\n| Id | 默认 | 作用 |\n| --- | --- | --- |\n| `morya-ui-pages` | 必选 | 用 `M*` + 黄金布局生成页面 |\n| `frontend-design` | 可选 | Express / 品牌向视觉味觉 |\n| `fixing-accessibility` | 可选 | 无障碍审计与定向修复 |\n\n目录:[`packages/setup/catalog/skills.json`](https://github.com/morya-space/morya-ui/blob/main/packages/setup/catalog/skills.json)。\n\n示例:只补 MCP:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```"
24868
25220
  },
24869
25221
  {
24870
25222
  "title": "会落到项目里的内容",
24871
25223
  "id": "会落到项目里的内容",
24872
- "body": "| 路径 | 作用 |\n| --- | --- |\n| `DESIGN.md` | AI 设计第一信源 |\n| `.agents/skills/morya-ui-pages/` | 页面生成 Agent Skill(见 [Agent Skill](/docs/agent-skill)) |\n| `.cursor/rules/` | Cursor 常驻规则 |\n| `docs/`、`design-tokens/`、`src/examples/` | 组件索引、黄金样例、令牌 |\n| `scripts/check-raw-colors.mjs` | 裸色值扫描 |\n| `.cursor/mcp.json` | Cursor MCP(`npx -y @morya-ui/mcp`) |\n| `src/styles/morya-app-shell.css` | 页面高度链(默认命令或 `app` 写入) |\n\n模板源在仓库 [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit)。CLI 不调用 `app.use(MoryaUI)`,也不改 `App.vue`。"
25224
+ "body": "| 路径 | 作用 |\n| --- | --- |\n| `DESIGN.md` | AI 设计第一信源(原则、应用根、令牌摘要、禁止项) |\n| `.agents/skills/morya-ui-pages/` | 页面生成 Agent Skill(见 [Agent Skill](/docs/agent-skill)) |\n| `.agents/skills/<optional>/` | 勾选时写入的 companion skill |\n| `.cursor/rules/` | Cursor 常驻规则 |\n| `scripts/check-raw-colors.mjs` | 裸色值扫描 |\n| `.cursor/mcp.json` | Cursor MCP(`npx -y @morya-ui/mcp`) |\n\n模板源在仓库 [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit)。CLI 不调用 `app.use(MoryaUI)`,也不改 `App.vue`。"
24873
25225
  },
24874
25226
  {
24875
25227
  "title": "冲突策略",
@@ -24886,7 +25238,7 @@
24886
25238
  "en-US": {
24887
25239
  "title": "One-shot setup",
24888
25240
  "description": "Use @morya-ui/setup to install the library and optionally write styles, Agent config, and MCP.",
24889
- "markdown": "---\ntitle: One-shot setup\norder: 3\ndescription: Use @morya-ui/setup to install the library and optionally write styles, Agent config, and MCP.\n---\n\n# One-shot setup\n\n[`@morya-ui/setup`](https://www.npmjs.com/package/@morya-ui/setup) onboards a consumer Vue app to `morya-ui`: install the dependency, inject styles, and optionally write the Agent skill, Cursor rules, and MCP. For manual install see [Quick start](/docs/quick-start). For AI page-generation workflow see [AI setup](/docs/ai-setup).\n\n## Commands\n\nFrom the app project root:\n\n```bash\nnpx @morya-ui/setup\n```\n\nBy default this will:\n\n1. Install `morya-ui` (pnpm / yarn / npm from the lockfile)\n2. Copy `DESIGN.md`, Agent skill, Cursor rules, golden pages, and check scripts\n3. Merge `.cursor/mcp.json` for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. Try to inject `import 'morya-ui/styles.css'` and write `morya-app-shell.css`\n5. Add a `check:colors` script when missing\n\nOther common commands:\n\n```bash\n# Library + styles only\nnpx @morya-ui/setup app\n\n# AI config + MCP only (library already installed)\nnpx @morya-ui/setup ai\n```\n\nIf MCP was written, **restart Cursor** (or reload MCP). Have the agent read `DESIGN.md` before generating pages.\n\n## Options\n\n| Flag | Meaning |\n| --- | --- |\n| `--cwd <dir>` | Target project root (default: cwd) |\n| `--pm pnpm\\|yarn\\|npm` | Package manager |\n| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |\n| `--dry-run` | Print actions only |\n| `--skip-install` | Skip dependency install |\n| `--skip-template` | Skip copying skill / rules / docs |\n| `--skip-mcp` | Skip writing MCP config |\n| `--skip-styles` | Skip styles import injection |\n| `--skip-scripts` | Skip `package.json` scripts |\n\nBy default **existing files are not overwritten**; use `--force` to overwrite templates and the MCP entry.\n\nExample: MCP only:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```\n\n## What lands in the project\n\n| Path | Role |\n| --- | --- |\n| `DESIGN.md` | Primary design brief for AI |\n| `.agents/skills/morya-ui-pages/` | Page-generation Agent skill (see [Agent Skill](/docs/agent-skill)) |\n| `.cursor/rules/` | Cursor always-on rules |\n| `docs/`, `design-tokens/`, `src/examples/` | Index, golden pages, tokens |\n| `scripts/check-raw-colors.mjs` | Raw color scan |\n| `.cursor/mcp.json` | Cursor MCP (`npx -y @morya-ui/mcp`) |\n| `src/styles/morya-app-shell.css` | Height chain (default command or `app`) |\n\nTemplate source: [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit). The CLI does not call `app.use(MoryaUI)` or edit `App.vue`.\n\n## Conflict policy\n\n- Template files and `.cursor/rules/*`: skip if the destination exists (unless `--force`)\n- `.cursor/mcp.json`: merge other servers; skip an existing `morya-ui` entry unless `--force`\n- `check:colors`: add only if missing (unless `--force`)\n- Styles: inject only when an entry is found and the import is not already present\n\n## Next steps\n\n- [Quick start](/docs/quick-start): component usage and a minimal example \n- [AI setup](/docs/ai-setup): how setup relates to Skill / MCP for AI page generation \n- [Agent Skill](/docs/agent-skill) · [Agent MCP](/docs/mcp) \n- [Components](/components): browse APIs and previews\n",
25241
+ "markdown": "---\ntitle: One-shot setup\norder: 3\ndescription: Use @morya-ui/setup to install the library and optionally write styles, Agent config, and MCP.\n---\n\n# One-shot setup\n\n[`@morya-ui/setup`](https://www.npmjs.com/package/@morya-ui/setup) onboards a consumer Vue app to `morya-ui`: install the dependency, inject styles, and optionally write the Agent skill, Cursor rules, and MCP. For manual install see [Quick start](/docs/quick-start). For AI page-generation workflow see [AI setup](/docs/ai-setup).\n\n## Commands\n\nFrom the app project root:\n\n```bash\nnpx @morya-ui/setup\n```\n\nBy default this will:\n\n1. Install `morya-ui` (pnpm / yarn / npm from the lockfile)\n2. Copy `DESIGN.md`, Agent skill, Cursor rules, and check scripts\n3. Merge `.cursor/mcp.json` for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. Try to inject `import 'morya-ui/styles.css'`\n5. Add a `check:colors` script when missing\n\nOther common commands:\n\n```bash\n# Library + styles only\nnpx @morya-ui/setup app\n\n# AI config + MCP only (library already installed)\nnpx @morya-ui/setup ai\n\n# Non-interactive skill selection\nnpx @morya-ui/setup ai --yes\nnpx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design\nnpx @morya-ui/setup ai --skills=all\n```\n\nOn a TTY, `full` / `ai` prompts for optional Agent skills (required `morya-ui-pages` is always included). If MCP was written, **restart Cursor** (or reload MCP). Have the agent read `DESIGN.md` before generating pages.\n\n## Options\n\n| Flag | Meaning |\n| --- | --- |\n| `--cwd <dir>` | Target project root (default: cwd) |\n| `--pm pnpm\\|yarn\\|npm` | Package manager |\n| `--skills <list>` | Comma-separated skill ids, or `all` (skips the prompt) |\n| `--yes` / `-y` | Use default skills without prompting |\n| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |\n| `--dry-run` | Print actions only |\n| `--skip-install` | Skip dependency install |\n| `--skip-template` | Skip copying skill / rules / docs |\n| `--skip-mcp` | Skip writing MCP config |\n| `--skip-styles` | Skip styles import injection |\n| `--skip-scripts` | Skip `package.json` scripts |\n\nBy default **existing files are not overwritten**; use `--force` to overwrite templates and the MCP entry.\n\n### Skills\n\n| Id | Default | Role |\n| --- | --- | --- |\n| `morya-ui-pages` | required | Page generation with `M*` + golden layouts |\n| `frontend-design` | optional | Express / brand visual taste |\n| `fixing-accessibility` | optional | A11y audit and targeted fixes |\n\nCatalog: [`packages/setup/catalog/skills.json`](https://github.com/morya-space/morya-ui/blob/main/packages/setup/catalog/skills.json).\n\nExample: MCP only:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```\n\n## What lands in the project\n\n| Path | Role |\n| --- | --- |\n| `DESIGN.md` | Primary design brief (principles, app root, token summary, bans) |\n| `.agents/skills/morya-ui-pages/` | Page-generation Agent skill (see [Agent Skill](/docs/agent-skill)) |\n| `.agents/skills/<optional>/` | Companion skills when selected |\n| `.cursor/rules/` | Cursor always-on rules |\n| `scripts/check-raw-colors.mjs` | Raw color scan |\n| `.cursor/mcp.json` | Cursor MCP (`npx -y @morya-ui/mcp`) |\n\nTemplate source: [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit). The CLI does not call `app.use(MoryaUI)` or edit `App.vue`.\n\n## Conflict policy\n\n- Template files and `.cursor/rules/*`: skip if the destination exists (unless `--force`)\n- `.cursor/mcp.json`: merge other servers; skip an existing `morya-ui` entry unless `--force`\n- `check:colors`: add only if missing (unless `--force`)\n- Styles: inject only when an entry is found and the import is not already present\n\n## Next steps\n\n- [Quick start](/docs/quick-start): component usage and a minimal example \n- [AI setup](/docs/ai-setup): how setup relates to Skill / MCP for AI page generation \n- [Agent Skill](/docs/agent-skill) · [Agent MCP](/docs/mcp) \n- [Components](/components): browse APIs and previews\n",
24890
25242
  "sections": [
24891
25243
  {
24892
25244
  "title": "",
@@ -24896,17 +25248,17 @@
24896
25248
  {
24897
25249
  "title": "Commands",
24898
25250
  "id": "commands",
24899
- "body": "From the app project root:\n\n```bash\nnpx @morya-ui/setup\n```\n\nBy default this will:\n\n1. Install `morya-ui` (pnpm / yarn / npm from the lockfile)\n2. Copy `DESIGN.md`, Agent skill, Cursor rules, golden pages, and check scripts\n3. Merge `.cursor/mcp.json` for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. Try to inject `import 'morya-ui/styles.css'` and write `morya-app-shell.css`\n5. Add a `check:colors` script when missing\n\nOther common commands:\n\n```bash\n# Library + styles only\nnpx @morya-ui/setup app\n\n# AI config + MCP only (library already installed)\nnpx @morya-ui/setup ai\n```\n\nIf MCP was written, **restart Cursor** (or reload MCP). Have the agent read `DESIGN.md` before generating pages."
25251
+ "body": "From the app project root:\n\n```bash\nnpx @morya-ui/setup\n```\n\nBy default this will:\n\n1. Install `morya-ui` (pnpm / yarn / npm from the lockfile)\n2. Copy `DESIGN.md`, Agent skill, Cursor rules, and check scripts\n3. Merge `.cursor/mcp.json` for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp)\n4. Try to inject `import 'morya-ui/styles.css'`\n5. Add a `check:colors` script when missing\n\nOther common commands:\n\n```bash\n# Library + styles only\nnpx @morya-ui/setup app\n\n# AI config + MCP only (library already installed)\nnpx @morya-ui/setup ai\n\n# Non-interactive skill selection\nnpx @morya-ui/setup ai --yes\nnpx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design\nnpx @morya-ui/setup ai --skills=all\n```\n\nOn a TTY, `full` / `ai` prompts for optional Agent skills (required `morya-ui-pages` is always included). If MCP was written, **restart Cursor** (or reload MCP). Have the agent read `DESIGN.md` before generating pages."
24900
25252
  },
24901
25253
  {
24902
25254
  "title": "Options",
24903
25255
  "id": "options",
24904
- "body": "| Flag | Meaning |\n| --- | --- |\n| `--cwd <dir>` | Target project root (default: cwd) |\n| `--pm pnpm\\|yarn\\|npm` | Package manager |\n| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |\n| `--dry-run` | Print actions only |\n| `--skip-install` | Skip dependency install |\n| `--skip-template` | Skip copying skill / rules / docs |\n| `--skip-mcp` | Skip writing MCP config |\n| `--skip-styles` | Skip styles import injection |\n| `--skip-scripts` | Skip `package.json` scripts |\n\nBy default **existing files are not overwritten**; use `--force` to overwrite templates and the MCP entry.\n\nExample: MCP only:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```"
25256
+ "body": "| Flag | Meaning |\n| --- | --- |\n| `--cwd <dir>` | Target project root (default: cwd) |\n| `--pm pnpm\\|yarn\\|npm` | Package manager |\n| `--skills <list>` | Comma-separated skill ids, or `all` (skips the prompt) |\n| `--yes` / `-y` | Use default skills without prompting |\n| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |\n| `--dry-run` | Print actions only |\n| `--skip-install` | Skip dependency install |\n| `--skip-template` | Skip copying skill / rules / docs |\n| `--skip-mcp` | Skip writing MCP config |\n| `--skip-styles` | Skip styles import injection |\n| `--skip-scripts` | Skip `package.json` scripts |\n\nBy default **existing files are not overwritten**; use `--force` to overwrite templates and the MCP entry.\n\n### Skills\n\n| Id | Default | Role |\n| --- | --- | --- |\n| `morya-ui-pages` | required | Page generation with `M*` + golden layouts |\n| `frontend-design` | optional | Express / brand visual taste |\n| `fixing-accessibility` | optional | A11y audit and targeted fixes |\n\nCatalog: [`packages/setup/catalog/skills.json`](https://github.com/morya-space/morya-ui/blob/main/packages/setup/catalog/skills.json).\n\nExample: MCP only:\n\n```bash\nnpx @morya-ui/setup ai --skip-template --skip-scripts\n```"
24905
25257
  },
24906
25258
  {
24907
25259
  "title": "What lands in the project",
24908
25260
  "id": "what-lands-in-the-project",
24909
- "body": "| Path | Role |\n| --- | --- |\n| `DESIGN.md` | Primary design brief for AI |\n| `.agents/skills/morya-ui-pages/` | Page-generation Agent skill (see [Agent Skill](/docs/agent-skill)) |\n| `.cursor/rules/` | Cursor always-on rules |\n| `docs/`, `design-tokens/`, `src/examples/` | Index, golden pages, tokens |\n| `scripts/check-raw-colors.mjs` | Raw color scan |\n| `.cursor/mcp.json` | Cursor MCP (`npx -y @morya-ui/mcp`) |\n| `src/styles/morya-app-shell.css` | Height chain (default command or `app`) |\n\nTemplate source: [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit). The CLI does not call `app.use(MoryaUI)` or edit `App.vue`."
25261
+ "body": "| Path | Role |\n| --- | --- |\n| `DESIGN.md` | Primary design brief (principles, app root, token summary, bans) |\n| `.agents/skills/morya-ui-pages/` | Page-generation Agent skill (see [Agent Skill](/docs/agent-skill)) |\n| `.agents/skills/<optional>/` | Companion skills when selected |\n| `.cursor/rules/` | Cursor always-on rules |\n| `scripts/check-raw-colors.mjs` | Raw color scan |\n| `.cursor/mcp.json` | Cursor MCP (`npx -y @morya-ui/mcp`) |\n\nTemplate source: [`design-kit/`](https://github.com/morya-space/morya-ui/tree/main/design-kit). The CLI does not call `app.use(MoryaUI)` or edit `App.vue`."
24910
25262
  },
24911
25263
  {
24912
25264
  "title": "Conflict policy",
@@ -25645,7 +25997,7 @@
25645
25997
  "zh-CN": {
25646
25998
  "title": "Agent Skill",
25647
25999
  "description": "消费方 morya-ui-pages skill:何时触发、与 rules/MCP 分工、页面类型地图。",
25648
- "markdown": "---\ntitle: Agent Skill\norder: 12\ndescription: 消费方 morya-ui-pages skill:何时触发、与 rules/MCP 分工、页面类型地图。\n---\n\n# Agent Skill\n\n消费方用 AI 生成 **基于 `morya-ui` 的业务页面** 时,应加载 **`morya-ui-pages`** skill。它规定组件契约、页面类型与工作流;**不是**组件库源码里写新组件用的 skill。\n\n安装方式见 [一键接入](/docs/setup)(`npx @morya-ui/setup` 会复制到项目);AI 侧流程见 [AI 接入](/docs/ai-setup)。本文说明 skill **是什么、何时用、和其它配置怎么分工**。\n\n## 装到哪里\n\n```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # 布局、表面、令牌、反馈、检查清单等\n```\n\n支持 Agent Skills 自动发现的客户端(如 Cursor)会从 `.agents/skills` 读取。生成列表 / 表单 / 登录 / 落地等页面前,应优先匹配本 skill。\n\n源文件在仓库 [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages),随 `@morya-ui/setup` 的 template 同步。\n\n## 何时触发\n\n典型话术或主题:\n\n- `morya-ui`、`M*` 组件、`--m-*` 令牌、黄金样例\n- 后台 / 列表 / 表单 / 仪表盘 / 详情 / 设置\n- 登录 / 注册 / 空状态 / 向导 / 落地页 / 官网\n\n**优先于**通用 `frontend-design`、Impeccable、UI-UX-Pro-Max 等:那些只能当审美参考;栈是 morya-ui 时以本 skill 为准。\n\n**不要**用于:纯后端、或在本仓库 `src/components` 里新增组件库组件。\n\n## 与其它配置的分工\n\n| 层 | 角色 |\n| --- | --- |\n| [一键接入](/docs/setup) / `@morya-ui/setup` | 一次性把库 + skill + rules + MCP 装进项目 |\n| [AI 接入](/docs/ai-setup) | 装好后如何配合 Agent 生成页面 |\n| **`morya-ui-pages` skill** | 按需工作流:选表面、读黄金样例、组 `M*`、自检 |\n| `.cursor/rules/` | 编辑器常驻短规则(设计系统、组件用法、布局) |\n| `DESIGN.md` | 项目设计第一信源;与 skill 冲突时以项目 `DESIGN.md` 为准 |\n| [Agent MCP](/docs/mcp) | 运行时查真实 Props / Events / 示例,禁止臆造 API |\n\n两层始终生效:\n\n1. **契约** — 只用 `M*` 与 `--m-*`,API 以 MCP / 文档为准 \n2. **工艺** — 先定表面类型,再做视觉;后台偏克制,落地 / 品牌向可有意表达,但仍上令牌、上组件\n\n## 页面类型(Surface)地图\n\n| 车道 | 典型表面 | 优先参考 |\n| --- | --- | --- |\n| **Ops** | 列表、表单、仪表盘、详情、设置、筛选抽屉 | 黄金样例 + skill `page-layouts` |\n| **Account** | 登录、注册、邀请、重置密码、个人资料 | skill `surfaces` § Account |\n| **Flow** | 引导、空状态、向导、成功页 | skill `surfaces` § Flow |\n| **System** | 404、无权限、维护中 | skill `surfaces` § System |\n| **Express** | 营销落地、定价、功能展示 | skill `surfaces` + `visual-craft` |\n| **Overlay** | 以 Dialog / Drawer / CommandMenu 为主界面 | skill `surfaces` § Overlay |\n\n不确定时:后台默认 Ops → 最近黄金样例;对外营销 → Express。\n\n## Agent 推荐工作流(摘要)\n\n1. 钉死主体、受众、表面、第一屏单一任务 \n2. 优先 MCP:`recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. 无 MCP 时读项目内 `docs/golden-pages/` 与 skill `references/` \n4. 反馈默认 `message`;`toast` 仅 summary+detail / 异步感(见项目 `docs/feedback-message-vs-toast.md`) \n5. 交付前对照 skill 检查清单;有 MCP 时跑 `validate_page`\n\n细节与硬边界以项目内 `SKILL.md` 为准,本文不重复全文。\n\n## 下一步\n\n- [一键接入](/docs/setup):安装 skill 与其它配置 \n- [AI 接入](/docs/ai-setup):用 AI 生成页面时的流程 \n- [Agent MCP](/docs/mcp):工具与客户端配置 \n- [快速上手](/docs/quick-start):手写安装组件库 \n- [组件](/components):浏览 API\n",
26000
+ "markdown": "---\ntitle: Agent Skill\norder: 12\ndescription: 消费方 morya-ui-pages skill:何时触发、与 rules/MCP 分工、页面类型地图。\n---\n\n# Agent Skill\n\n消费方用 AI 生成 **基于 `morya-ui` 的业务页面** 时,应加载 **`morya-ui-pages`** skill。它规定组件契约、页面类型与工作流;**不是**组件库源码里写新组件用的 skill。\n\n安装方式见 [一键接入](/docs/setup)(`npx @morya-ui/setup` 会复制到项目);AI 侧流程见 [AI 接入](/docs/ai-setup)。本文说明 skill **是什么、何时用、和其它配置怎么分工**。\n\n## 装到哪里\n\n```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # 布局、表面、令牌、反馈、检查清单等\n```\n\n支持 Agent Skills 自动发现的客户端(如 Cursor)会从 `.agents/skills` 读取。生成列表 / 表单 / 登录 / 落地等页面前,应优先匹配本 skill。\n\n源文件在仓库 [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages),随 `@morya-ui/setup` 的 template 同步。可选 companion(`frontend-design`、`fixing-accessibility`)可用 `npx @morya-ui/setup ai --skills=…` 一并写入,见 [一键接入](/docs/setup)。\n\n## 何时触发\n\n典型话术或主题:\n\n- `morya-ui`、`M*` 组件、`--m-*` 令牌、黄金样例\n- 后台 / 列表 / 表单 / 仪表盘 / 详情 / 设置\n- 登录 / 注册 / 空状态 / 向导 / 落地页 / 官网\n\n**优先于**通用 `frontend-design`、Impeccable、UI-UX-Pro-Max 等:那些只能当审美参考;栈是 morya-ui 时以本 skill 为准。\n\n**不要**用于:纯后端、或在本仓库 `src/components` 里新增组件库组件。\n\n## 与其它配置的分工\n\n| 层 | 角色 |\n| --- | --- |\n| [一键接入](/docs/setup) / `@morya-ui/setup` | 一次性把库 + skill + rules + MCP 装进项目 |\n| [AI 接入](/docs/ai-setup) | 装好后如何配合 Agent 生成页面 |\n| **`morya-ui-pages` skill** | 按需工作流:选表面、读黄金样例、组 `M*`、自检 |\n| `.cursor/rules/` | 编辑器常驻短规则(设计系统、组件用法、布局) |\n| `DESIGN.md` | 项目设计第一信源;与 skill 冲突时以项目 `DESIGN.md` 为准 |\n| [Agent MCP](/docs/mcp) | 运行时查真实 Props / Events / 示例,禁止臆造 API |\n\n两层始终生效:\n\n1. **契约** — 只用 `M*` 与 `--m-*`,API 以 MCP / 文档为准 \n2. **工艺** — 先定表面类型,再做视觉;后台偏克制,落地 / 品牌向可有意表达,但仍上令牌、上组件\n\n## 页面类型(Surface)地图\n\n| 车道 | 典型表面 | 优先参考 |\n| --- | --- | --- |\n| **Ops** | 列表、表单、仪表盘、详情、设置、筛选抽屉 | 黄金样例 + skill `page-layouts` |\n| **Account** | 登录、注册、邀请、重置密码、个人资料 | skill `surfaces` § Account |\n| **Flow** | 引导、空状态、向导、成功页 | skill `surfaces` § Flow |\n| **System** | 404、无权限、维护中 | skill `surfaces` § System |\n| **Express** | 营销落地、定价、功能展示 | skill `surfaces` + `visual-craft` |\n| **Overlay** | 以 Dialog / Drawer / CommandMenu 为主界面 | skill `surfaces` § Overlay |\n\n不确定时:后台默认 Ops → 最近黄金样例;对外营销 → Express。\n\n## Agent 推荐工作流(摘要)\n\n1. 钉死主体、受众、表面、第一屏单一任务 \n2. 优先 MCP:`recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. 无 MCP 时读 skill `references/`(布局、表面、反馈) \n4. 反馈默认 `message`;`toast` 仅 summary+detail / 异步感。表单常驻错误用字段 `errorMessage` 或 token 样式的 `role=\"alert\"`,不要把 `<MMessage>` 当成内嵌 Alert。表格行数据用 `rows`。交付前默认做一轮 craft(Ops polish / 氛围配方,见 skill `visual-craft`)。 \n5. 交付前对照 skill 检查清单;有 MCP 时跑 `validate_page`\n\n细节与硬边界以项目内 `SKILL.md` 为准,本文不重复全文。\n\n## 下一步\n\n- [一键接入](/docs/setup):安装 skill 与其它配置 \n- [AI 接入](/docs/ai-setup):用 AI 生成页面时的流程 \n- [Agent MCP](/docs/mcp):工具与客户端配置 \n- [快速上手](/docs/quick-start):手写安装组件库 \n- [组件](/components):浏览 API\n",
25649
26001
  "sections": [
25650
26002
  {
25651
26003
  "title": "",
@@ -25655,7 +26007,7 @@
25655
26007
  {
25656
26008
  "title": "装到哪里",
25657
26009
  "id": "装到哪里",
25658
- "body": "```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # 布局、表面、令牌、反馈、检查清单等\n```\n\n支持 Agent Skills 自动发现的客户端(如 Cursor)会从 `.agents/skills` 读取。生成列表 / 表单 / 登录 / 落地等页面前,应优先匹配本 skill。\n\n源文件在仓库 [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages),随 `@morya-ui/setup` 的 template 同步。"
26010
+ "body": "```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # 布局、表面、令牌、反馈、检查清单等\n```\n\n支持 Agent Skills 自动发现的客户端(如 Cursor)会从 `.agents/skills` 读取。生成列表 / 表单 / 登录 / 落地等页面前,应优先匹配本 skill。\n\n源文件在仓库 [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages),随 `@morya-ui/setup` 的 template 同步。可选 companion(`frontend-design`、`fixing-accessibility`)可用 `npx @morya-ui/setup ai --skills=…` 一并写入,见 [一键接入](/docs/setup)。"
25659
26011
  },
25660
26012
  {
25661
26013
  "title": "何时触发",
@@ -25675,7 +26027,7 @@
25675
26027
  {
25676
26028
  "title": "Agent 推荐工作流(摘要)",
25677
26029
  "id": "agent-推荐工作流-摘要",
25678
- "body": "1. 钉死主体、受众、表面、第一屏单一任务 \n2. 优先 MCP:`recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. 无 MCP 时读项目内 `docs/golden-pages/` 与 skill `references/` \n4. 反馈默认 `message`;`toast` 仅 summary+detail / 异步感(见项目 `docs/feedback-message-vs-toast.md`) \n5. 交付前对照 skill 检查清单;有 MCP 时跑 `validate_page`\n\n细节与硬边界以项目内 `SKILL.md` 为准,本文不重复全文。"
26030
+ "body": "1. 钉死主体、受众、表面、第一屏单一任务 \n2. 优先 MCP:`recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. 无 MCP 时读 skill `references/`(布局、表面、反馈) \n4. 反馈默认 `message`;`toast` 仅 summary+detail / 异步感。表单常驻错误用字段 `errorMessage` 或 token 样式的 `role=\"alert\"`,不要把 `<MMessage>` 当成内嵌 Alert。表格行数据用 `rows`。交付前默认做一轮 craft(Ops polish / 氛围配方,见 skill `visual-craft`)。 \n5. 交付前对照 skill 检查清单;有 MCP 时跑 `validate_page`\n\n细节与硬边界以项目内 `SKILL.md` 为准,本文不重复全文。"
25679
26031
  },
25680
26032
  {
25681
26033
  "title": "下一步",
@@ -25687,7 +26039,7 @@
25687
26039
  "en-US": {
25688
26040
  "title": "Agent Skill",
25689
26041
  "description": "Consumer morya-ui-pages skill — when it triggers, vs rules/MCP, and the surface map.",
25690
- "markdown": "---\ntitle: Agent Skill\norder: 12\ndescription: Consumer morya-ui-pages skill — when it triggers, vs rules/MCP, and the surface map.\n---\n\n# Agent Skill\n\nWhen AI generates **morya-ui consumer pages**, load the **`morya-ui-pages`** skill. It defines the component contract, surface types, and workflow. It is **not** for authoring new components inside the library source.\n\nInstall via [One-shot setup](/docs/setup) (`npx @morya-ui/setup` copies it into the project); AI workflow: [AI setup](/docs/ai-setup). This page explains **what it is, when to use it, and how it relates to other config**.\n\n## Where it lives\n\n```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # layouts, surfaces, tokens, feedback, checklist, …\n```\n\nClients that auto-discover Agent Skills (e.g. Cursor) read `.agents/skills`. Prefer this skill before generating list / form / login / landing pages.\n\nSource: [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages), synced into the `@morya-ui/setup` template.\n\n## When it triggers\n\nTypical topics:\n\n- `morya-ui`, `M*` components, `--m-*` tokens, golden pages\n- Admin list / form / dashboard / detail / settings\n- Login / register / empty state / wizard / landing / marketing site\n\n**Prefer over** generic `frontend-design`, Impeccable, or UI-UX-Pro-Max when the stack is morya-ui — those may inform taste only.\n\n**Do not** use for backend-only work or for adding components under this repo’s `src/components`.\n\n## How it relates to other config\n\n| Layer | Role |\n| --- | --- |\n| [One-shot setup](/docs/setup) / `@morya-ui/setup` | One-shot install of library + skill + rules + MCP |\n| [AI setup](/docs/ai-setup) | How to use the Agent after install |\n| **`morya-ui-pages` skill** | On-demand workflow: pick surface, golden pages, compose `M*`, review |\n| `.cursor/rules/` | Always-on short editor rules |\n| `DESIGN.md` | Project design source of truth; wins over skill on conflict |\n| [Agent MCP](/docs/mcp) | Runtime lookup of real props / events / examples |\n\nTwo layers always apply:\n\n1. **Contract** — only `M*` and `--m-*`; APIs from MCP / docs \n2. **Craft** — pick the surface first; Ops stays restrained; Express may take intentional aesthetic risk on-token and on-component\n\n## Surface map\n\n| Lane | Surfaces | Prefer |\n| --- | --- | --- |\n| **Ops** | list, form, dashboard, detail, settings, filter drawer | Golden pages + skill `page-layouts` |\n| **Account** | login, register, invite, reset password, profile | skill `surfaces` § Account |\n| **Flow** | onboarding, empty, wizard, success | skill `surfaces` § Flow |\n| **System** | 404, permission denied, maintenance | skill `surfaces` § System |\n| **Express** | marketing landing, pricing, feature showcase | skill `surfaces` + `visual-craft` |\n| **Overlay** | Dialog / Drawer / CommandMenu as the main UI | skill `surfaces` § Overlay |\n\nUnclear brief → Ops → nearest golden page; public marketing → Express.\n\n## Recommended agent workflow (summary)\n\n1. Pin subject, audience, surface, and the first viewport’s single job \n2. Prefer MCP: `recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. Without MCP, read project `docs/golden-pages/` and skill `references/` \n4. Feedback defaults to `message`; `toast` only for summary+detail / async feel \n5. Review with the skill checklist; run MCP `validate_page` when available \n\nFull rules and hard boundaries live in the project’s `SKILL.md` — this page does not duplicate it.\n\n## Next steps\n\n- [One-shot setup](/docs/setup): install the skill and related config \n- [AI setup](/docs/ai-setup): AI page-generation workflow \n- [Agent MCP](/docs/mcp): tools and client config \n- [Quick start](/docs/quick-start): manual library install \n- [Components](/components): browse APIs\n",
26042
+ "markdown": "---\ntitle: Agent Skill\norder: 12\ndescription: Consumer morya-ui-pages skill — when it triggers, vs rules/MCP, and the surface map.\n---\n\n# Agent Skill\n\nWhen AI generates **morya-ui consumer pages**, load the **`morya-ui-pages`** skill. It defines the component contract, surface types, and workflow. It is **not** for authoring new components inside the library source.\n\nInstall via [One-shot setup](/docs/setup) (`npx @morya-ui/setup` copies it into the project); AI workflow: [AI setup](/docs/ai-setup). This page explains **what it is, when to use it, and how it relates to other config**.\n\n## Where it lives\n\n```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # layouts, surfaces, tokens, feedback, checklist, …\n```\n\nClients that auto-discover Agent Skills (e.g. Cursor) read `.agents/skills`. Prefer this skill before generating list / form / login / landing pages.\n\nSource: [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages), synced into the `@morya-ui/setup` template. Optional companions (`frontend-design`, `fixing-accessibility`) can be installed with `npx @morya-ui/setup ai --skills=…` — see [One-shot setup](/docs/setup).\n\n## When it triggers\n\nTypical topics:\n\n- `morya-ui`, `M*` components, `--m-*` tokens, golden pages\n- Admin list / form / dashboard / detail / settings\n- Login / register / empty state / wizard / landing / marketing site\n\n**Prefer over** generic `frontend-design`, Impeccable, or UI-UX-Pro-Max when the stack is morya-ui — those may inform taste only.\n\n**Do not** use for backend-only work or for adding components under this repo’s `src/components`.\n\n## How it relates to other config\n\n| Layer | Role |\n| --- | --- |\n| [One-shot setup](/docs/setup) / `@morya-ui/setup` | One-shot install of library + skill + rules + MCP |\n| [AI setup](/docs/ai-setup) | How to use the Agent after install |\n| **`morya-ui-pages` skill** | On-demand workflow: pick surface, golden pages, compose `M*`, review |\n| `.cursor/rules/` | Always-on short editor rules |\n| `DESIGN.md` | Project design source of truth; wins over skill on conflict |\n| [Agent MCP](/docs/mcp) | Runtime lookup of real props / events / examples |\n\nTwo layers always apply:\n\n1. **Contract** — only `M*` and `--m-*`; APIs from MCP / docs \n2. **Craft** — pick the surface first; Ops stays restrained; Express may take intentional aesthetic risk on-token and on-component\n\n## Surface map\n\n| Lane | Surfaces | Prefer |\n| --- | --- | --- |\n| **Ops** | list, form, dashboard, detail, settings, filter drawer | Golden pages + skill `page-layouts` |\n| **Account** | login, register, invite, reset password, profile | skill `surfaces` § Account |\n| **Flow** | onboarding, empty, wizard, success | skill `surfaces` § Flow |\n| **System** | 404, permission denied, maintenance | skill `surfaces` § System |\n| **Express** | marketing landing, pricing, feature showcase | skill `surfaces` + `visual-craft` |\n| **Overlay** | Dialog / Drawer / CommandMenu as the main UI | skill `surfaces` § Overlay |\n\nUnclear brief → Ops → nearest golden page; public marketing → Express.\n\n## Recommended agent workflow (summary)\n\n1. Pin subject, audience, surface, and the first viewport’s single job \n2. Prefer MCP: `recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. Without MCP, read skill `references/` (layouts, surfaces, feedback) \n4. Feedback defaults to `message`; `toast` only for summary+detail / async feel. Persistent form errors use field `errorMessage` or a token-styled `role=\"alert\"` — `<MMessage>` is not an inline alert. Table rows use `rows`. Always run a light craft pass before delivery (Ops polish / atmosphere — see skill `visual-craft`). \n5. Review with the skill checklist; run MCP `validate_page` when available \n\nFull rules and hard boundaries live in the project’s `SKILL.md` — this page does not duplicate it.\n\n## Next steps\n\n- [One-shot setup](/docs/setup): install the skill and related config \n- [AI setup](/docs/ai-setup): AI page-generation workflow \n- [Agent MCP](/docs/mcp): tools and client config \n- [Quick start](/docs/quick-start): manual library install \n- [Components](/components): browse APIs\n",
25691
26043
  "sections": [
25692
26044
  {
25693
26045
  "title": "",
@@ -25697,7 +26049,7 @@
25697
26049
  {
25698
26050
  "title": "Where it lives",
25699
26051
  "id": "where-it-lives",
25700
- "body": "```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # layouts, surfaces, tokens, feedback, checklist, …\n```\n\nClients that auto-discover Agent Skills (e.g. Cursor) read `.agents/skills`. Prefer this skill before generating list / form / login / landing pages.\n\nSource: [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages), synced into the `@morya-ui/setup` template."
26052
+ "body": "```text\n.agents/skills/morya-ui-pages/\n├── SKILL.md\n└── references/ # layouts, surfaces, tokens, feedback, checklist, …\n```\n\nClients that auto-discover Agent Skills (e.g. Cursor) read `.agents/skills`. Prefer this skill before generating list / form / login / landing pages.\n\nSource: [`design-kit/.agents/skills/morya-ui-pages/`](https://github.com/morya-space/morya-ui/tree/main/design-kit/.agents/skills/morya-ui-pages), synced into the `@morya-ui/setup` template. Optional companions (`frontend-design`, `fixing-accessibility`) can be installed with `npx @morya-ui/setup ai --skills=…` — see [One-shot setup](/docs/setup)."
25701
26053
  },
25702
26054
  {
25703
26055
  "title": "When it triggers",
@@ -25717,7 +26069,7 @@
25717
26069
  {
25718
26070
  "title": "Recommended agent workflow (summary)",
25719
26071
  "id": "recommended-agent-workflow-summary",
25720
- "body": "1. Pin subject, audience, surface, and the first viewport’s single job \n2. Prefer MCP: `recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. Without MCP, read project `docs/golden-pages/` and skill `references/` \n4. Feedback defaults to `message`; `toast` only for summary+detail / async feel \n5. Review with the skill checklist; run MCP `validate_page` when available \n\nFull rules and hard boundaries live in the project’s `SKILL.md` — this page does not duplicate it."
26072
+ "body": "1. Pin subject, audience, surface, and the first viewport’s single job \n2. Prefer MCP: `recommend_page` → `get_golden_page` → `get_component` / `get_example` \n3. Without MCP, read skill `references/` (layouts, surfaces, feedback) \n4. Feedback defaults to `message`; `toast` only for summary+detail / async feel. Persistent form errors use field `errorMessage` or a token-styled `role=\"alert\"` — `<MMessage>` is not an inline alert. Table rows use `rows`. Always run a light craft pass before delivery (Ops polish / atmosphere — see skill `visual-craft`). \n5. Review with the skill checklist; run MCP `validate_page` when available \n\nFull rules and hard boundaries live in the project’s `SKILL.md` — this page does not duplicate it."
25721
26073
  },
25722
26074
  {
25723
26075
  "title": "Next steps",
@@ -25739,7 +26091,7 @@
25739
26091
  "zh-CN": {
25740
26092
  "title": "Agent MCP",
25741
26093
  "description": "可选的 MCP 服务,供支持 Model Context Protocol 的 AI 客户端检索本库文档。",
25742
- "markdown": "---\ntitle: Agent MCP\norder: 13\ndescription: 可选的 MCP 服务,供支持 Model Context Protocol 的 AI 客户端检索本库文档。\n---\n\n# Agent MCP\n\n[`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp) 是可选的 [Model Context Protocol](https://modelcontextprotocol.io/)(stdio)服务。它把本站组件文档、示例与指南做成可检索工具,方便 **支持 MCP 的 AI 客户端** 按真实 API 生成代码。\n\n日常使用组件库 **不需要** 安装或配置 MCP。应用里仍然只依赖:\n\n```bash\npnpm add morya-ui\n```\n\n```ts\nimport 'morya-ui/styles.css'\n```\n\n若要连同 Agent Skill、Cursor 规则一起装好,见 [一键接入](/docs/setup);AI 流程见 [AI 接入](/docs/ai-setup);Skill 本身说明见 [Agent Skill](/docs/agent-skill)。\n\n## 接入方式\n\nMCP 客户端通过 stdio 启动本包即可:\n\n```bash\nnpx -y @morya-ui/mcp\n```\n\n通用写法:\n\n```json\n{\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n}\n```\n\n字段名因客户端而异,只要支持 MCP stdio 即可接入。\n\n### 常见客户端配置示例\n\n以下为常见产品的配置片段,键名可能随版本变化,以各产品官方文档为准。\n\n**Cursor**(`.cursor/mcp.json` 或用户级 MCP 配置):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop / Claude Code**(`claude_desktop_config.json` 等):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Windsurf**(MCP 设置中的 servers 配置):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Cline**(VS Code 扩展设置中的 MCP servers):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Zed**(`settings.json` → `context_servers`):\n\n```json\n{\n \"context_servers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Continue**(`config.json` / YAML 中的 MCP servers,字段名以当前版本为准):\n\n```json\n{\n \"mcpServers\": [\n {\n \"name\": \"morya-ui\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n ]\n}\n```\n\n## 可用工具\n\n### 基础 — 查组件文档\n\n| 工具 | 作用 |\n| --- | --- |\n| `list` | 列出组件 / 指南 / 示例 / 分类 / 页面模式 |\n| `search` | 搜索文档、示例、页面模式与组件选型指南 |\n| `get_component` | 读取组件说明与 API |\n| `get_example` | 获取源码示例 |\n| `get_guide` | 读取指南 |\n| `get_setup` | 安装与初始化说明 |\n| `validate_usage` | 对照文档粗检 props / events 用法 |\n| `version` | 版本与目录状态 |\n\n### 高级 — 页面组合(可选)\n\n| 工具 | 作用 |\n| --- | --- |\n| `list_patterns` | 列出可复用的页面组合模式 |\n| `get_pattern` | 读取模式的结构、布局与交互规则 |\n| `recommend_page` | 根据页面意图推荐模式;可附带 starter 脚手架 |\n| `get_design_rules` | 设计令牌与 MPage* 组合配方 |\n| `recommend_component` | 列出、阅读或推荐组件选型指南 |\n| `list_golden_pages` | 列出黄金样例页面 |\n| `get_golden_page` | 读取黄金样例 Vue 源码 |\n| `list_page_snippets` | 列出可复用的页面区块 snippet |\n| `get_page_snippet` | 读取局部区块 snippet(筛选区、工具栏等) |\n| `validate_page` | 校验页面组合、间距与双边框问题 |\n\n多数工具支持 `mode`:`zh`(默认)或 `en`。\n\n### 推荐工作流\n\n**查单个组件:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**规划整页:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`\n\n**改局部区块:** `get_page_snippet(section)` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\n需要 starter 代码时,给 `recommend_page` 传 `includeScaffold: true`:\n\n```json\n{\n \"intent\": \"油井管理列表\",\n \"pageType\": \"list\",\n \"features\": [\"筛选\", \"新增\", \"分页\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` 用法:\n\n- 不传 `query` 和 `decision` → 列出全部选型指南\n- 只传 `decision`(如 `overlay-choice`)→ 阅读某一指南\n- 传 `query` → 根据问题推荐组件\n\n## 对话示例\n\n接入后,可直接让助手调用本服务,例如:\n\n> 用 morya-ui 的 MCP 查一下 Dialog 的 props,并给一个带确认 / 取消按钮的示例。\n\n> 搜索和「日期」相关的组件,选一个适合表单的,按文档写出最小用法。\n\n> 根据 MCP 里 Button 的文档,写一个 `severity=\"danger\"` 的删除按钮,并校验 props 是否合法。\n\n助手应先调用工具,再基于返回内容生成类似:\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton } from 'morya-ui'\n</script>\n\n<template>\n <MButton label=\"删除\" severity=\"danger\" />\n</template>\n```\n\n## 与文档站的关系\n\n目录与本站同源(组件 `docs/` + 指南 Markdown)。官网文档更新后,维护者重新发布 `@morya-ui/mcp`,客户端通过 `npx -y` 即可拿到新版本。\n\n更多实现细节见仓库内 [packages/ui-mcp/README.md](https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp)。\n\n## 下一步\n\n- [AI 接入](/docs/ai-setup):`npx @morya-ui/setup`、skill 与 Cursor MCP\n- [Agent Skill](/docs/agent-skill):`morya-ui-pages` 何时用、表面地图\n- [快速上手](/docs/quick-start):在应用中安装并使用组件\n- [组件](/components):浏览全部组件与交互示例\n",
26094
+ "markdown": "---\ntitle: Agent MCP\norder: 13\ndescription: 可选的 MCP 服务,供支持 Model Context Protocol 的 AI 客户端检索本库文档。\n---\n\n# Agent MCP\n\n[`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp) 是可选的 [Model Context Protocol](https://modelcontextprotocol.io/)(stdio)服务。它把本站组件文档、示例与指南做成可检索工具,方便 **支持 MCP 的 AI 客户端** 按真实 API 生成代码。\n\n日常使用组件库 **不需要** 安装或配置 MCP。应用里仍然只依赖:\n\n```bash\npnpm add morya-ui\n```\n\n```ts\nimport 'morya-ui/styles.css'\n```\n\n若要连同 Agent Skill、Cursor 规则一起装好,见 [一键接入](/docs/setup);AI 流程见 [AI 接入](/docs/ai-setup);Skill 本身说明见 [Agent Skill](/docs/agent-skill)。\n\n## 接入方式\n\nMCP 客户端通过 stdio 启动本包即可:\n\n```bash\nnpx -y @morya-ui/mcp\n```\n\n通用写法:\n\n```json\n{\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n}\n```\n\n字段名因客户端而异,只要支持 MCP stdio 即可接入。\n\n### 常见客户端配置示例\n\n以下为常见产品的配置片段,键名可能随版本变化,以各产品官方文档为准。\n\n**Cursor**(`.cursor/mcp.json` 或用户级 MCP 配置):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop / Claude Code**(`claude_desktop_config.json` 等):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Windsurf**(MCP 设置中的 servers 配置):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Cline**(VS Code 扩展设置中的 MCP servers):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Zed**(`settings.json` → `context_servers`):\n\n```json\n{\n \"context_servers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Continue**(`config.json` / YAML 中的 MCP servers,字段名以当前版本为准):\n\n```json\n{\n \"mcpServers\": [\n {\n \"name\": \"morya-ui\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n ]\n}\n```\n\n## 可用工具\n\n### 基础 — 查组件文档\n\n| 工具 | 作用 |\n| --- | --- |\n| `list` | 列出组件 / 指南 / 示例 / 分类 / 页面模式 |\n| `search` | 搜索文档、示例、页面模式与组件选型指南 |\n| `get_component` | 读取组件说明与 API |\n| `get_example` | 获取源码示例 |\n| `get_guide` | 读取指南 |\n| `get_setup` | 安装与初始化说明 |\n| `validate_usage` | 对照文档粗检 props / events 用法 |\n| `version` | 版本与目录状态 |\n\n### 高级 — 页面组合(可选)\n\n| 工具 | 作用 |\n| --- | --- |\n| `list_patterns` | 列出可复用的页面组合模式 |\n| `get_pattern` | 读取模式的结构、布局与交互规则 |\n| `recommend_page` | 根据页面意图推荐模式;可附带 starter 脚手架 |\n| `get_design_rules` | 设计令牌与 MPage* 组合配方 |\n| `recommend_component` | 列出、阅读或推荐组件选型指南 |\n| `list_golden_pages` | 列出黄金样例页面 |\n| `get_golden_page` | 读取黄金样例 Vue 源码 |\n| `list_page_snippets` | 列出可复用的页面区块 snippet |\n| `get_page_snippet` | 读取局部区块 snippet(筛选区、工具栏等) |\n| `validate_page` | 校验页面组合、间距与双边框问题 |\n\n多数工具支持 `mode`:`zh`(默认)或 `en`。\n\n### 推荐工作流\n\n**查单个组件:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**规划整页:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`\n\n**改局部区块:** `get_page_snippet(section)` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\n需要 starter 代码时,给 `recommend_page` 传 `includeScaffold: true`:\n\n```json\n{\n \"intent\": \"油井管理列表\",\n \"pageType\": \"list\",\n \"features\": [\"筛选\", \"新增\", \"分页\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` 用法:\n\n- 不传 `query` 和 `decision` → 列出全部选型指南\n- 只传 `decision` 阅读某一指南\n- 传 `query` → 根据问题推荐组件\n\n当前指南包括:`form-surface-choice`、`overlay-choice`、`data-display-choice`、`selection-choice`(含 Select / TreeSelect / CascadeSelect / Listbox / SelectButton / Radio / AutoComplete)、`status-label-choice`、`empty-result-choice`、`action-menu-choice`、`loading-choice`、`page-scroll-choice`、`surface-choice`、`page-section-choice`、`layout-spacing-choice`、`surface-nesting-choice`。\n\n## 对话示例\n\n接入后,可直接让助手调用本服务,例如:\n\n> 用 morya-ui 的 MCP 查一下 Dialog 的 props,并给一个带确认 / 取消按钮的示例。\n\n> 搜索和「日期」相关的组件,选一个适合表单的,按文档写出最小用法。\n\n> 根据 MCP 里 Button 的文档,写一个 `severity=\"danger\"` 的删除按钮,并校验 props 是否合法。\n\n助手应先调用工具,再基于返回内容生成类似:\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton } from 'morya-ui'\n</script>\n\n<template>\n <MButton label=\"删除\" severity=\"danger\" />\n</template>\n```\n\n## 与文档站的关系\n\n目录与本站同源(组件 `docs/` + 指南 Markdown)。官网文档更新后,维护者重新发布 `@morya-ui/mcp`,客户端通过 `npx -y` 即可拿到新版本。\n\n更多实现细节见仓库内 [packages/ui-mcp/README.md](https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp)。\n\n## 下一步\n\n- [AI 接入](/docs/ai-setup):`npx @morya-ui/setup`、skill 与 Cursor MCP\n- [Agent Skill](/docs/agent-skill):`morya-ui-pages` 何时用、表面地图\n- [快速上手](/docs/quick-start):在应用中安装并使用组件\n- [组件](/components):浏览全部组件与交互示例\n",
25743
26095
  "sections": [
25744
26096
  {
25745
26097
  "title": "",
@@ -25754,7 +26106,7 @@
25754
26106
  {
25755
26107
  "title": "可用工具",
25756
26108
  "id": "可用工具",
25757
- "body": "### 基础 — 查组件文档\n\n| 工具 | 作用 |\n| --- | --- |\n| `list` | 列出组件 / 指南 / 示例 / 分类 / 页面模式 |\n| `search` | 搜索文档、示例、页面模式与组件选型指南 |\n| `get_component` | 读取组件说明与 API |\n| `get_example` | 获取源码示例 |\n| `get_guide` | 读取指南 |\n| `get_setup` | 安装与初始化说明 |\n| `validate_usage` | 对照文档粗检 props / events 用法 |\n| `version` | 版本与目录状态 |\n\n### 高级 — 页面组合(可选)\n\n| 工具 | 作用 |\n| --- | --- |\n| `list_patterns` | 列出可复用的页面组合模式 |\n| `get_pattern` | 读取模式的结构、布局与交互规则 |\n| `recommend_page` | 根据页面意图推荐模式;可附带 starter 脚手架 |\n| `get_design_rules` | 设计令牌与 MPage* 组合配方 |\n| `recommend_component` | 列出、阅读或推荐组件选型指南 |\n| `list_golden_pages` | 列出黄金样例页面 |\n| `get_golden_page` | 读取黄金样例 Vue 源码 |\n| `list_page_snippets` | 列出可复用的页面区块 snippet |\n| `get_page_snippet` | 读取局部区块 snippet(筛选区、工具栏等) |\n| `validate_page` | 校验页面组合、间距与双边框问题 |\n\n多数工具支持 `mode`:`zh`(默认)或 `en`。\n\n### 推荐工作流\n\n**查单个组件:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**规划整页:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`\n\n**改局部区块:** `get_page_snippet(section)` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\n需要 starter 代码时,给 `recommend_page` 传 `includeScaffold: true`:\n\n```json\n{\n \"intent\": \"油井管理列表\",\n \"pageType\": \"list\",\n \"features\": [\"筛选\", \"新增\", \"分页\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` 用法:\n\n- 不传 `query` 和 `decision` → 列出全部选型指南\n- 只传 `decision`(如 `overlay-choice`)→ 阅读某一指南\n- 传 `query` → 根据问题推荐组件"
26109
+ "body": "### 基础 — 查组件文档\n\n| 工具 | 作用 |\n| --- | --- |\n| `list` | 列出组件 / 指南 / 示例 / 分类 / 页面模式 |\n| `search` | 搜索文档、示例、页面模式与组件选型指南 |\n| `get_component` | 读取组件说明与 API |\n| `get_example` | 获取源码示例 |\n| `get_guide` | 读取指南 |\n| `get_setup` | 安装与初始化说明 |\n| `validate_usage` | 对照文档粗检 props / events 用法 |\n| `version` | 版本与目录状态 |\n\n### 高级 — 页面组合(可选)\n\n| 工具 | 作用 |\n| --- | --- |\n| `list_patterns` | 列出可复用的页面组合模式 |\n| `get_pattern` | 读取模式的结构、布局与交互规则 |\n| `recommend_page` | 根据页面意图推荐模式;可附带 starter 脚手架 |\n| `get_design_rules` | 设计令牌与 MPage* 组合配方 |\n| `recommend_component` | 列出、阅读或推荐组件选型指南 |\n| `list_golden_pages` | 列出黄金样例页面 |\n| `get_golden_page` | 读取黄金样例 Vue 源码 |\n| `list_page_snippets` | 列出可复用的页面区块 snippet |\n| `get_page_snippet` | 读取局部区块 snippet(筛选区、工具栏等) |\n| `validate_page` | 校验页面组合、间距与双边框问题 |\n\n多数工具支持 `mode`:`zh`(默认)或 `en`。\n\n### 推荐工作流\n\n**查单个组件:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**规划整页:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`\n\n**改局部区块:** `get_page_snippet(section)` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\n需要 starter 代码时,给 `recommend_page` 传 `includeScaffold: true`:\n\n```json\n{\n \"intent\": \"油井管理列表\",\n \"pageType\": \"list\",\n \"features\": [\"筛选\", \"新增\", \"分页\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` 用法:\n\n- 不传 `query` 和 `decision` → 列出全部选型指南\n- 只传 `decision` 阅读某一指南\n- 传 `query` → 根据问题推荐组件\n\n当前指南包括:`form-surface-choice`、`overlay-choice`、`data-display-choice`、`selection-choice`(含 Select / TreeSelect / CascadeSelect / Listbox / SelectButton / Radio / AutoComplete)、`status-label-choice`、`empty-result-choice`、`action-menu-choice`、`loading-choice`、`page-scroll-choice`、`surface-choice`、`page-section-choice`、`layout-spacing-choice`、`surface-nesting-choice`。"
25758
26110
  },
25759
26111
  {
25760
26112
  "title": "对话示例",
@@ -25776,7 +26128,7 @@
25776
26128
  "en-US": {
25777
26129
  "title": "Agent MCP",
25778
26130
  "description": "Optional MCP server for AI clients that support the Model Context Protocol.",
25779
- "markdown": "---\ntitle: Agent MCP\norder: 13\ndescription: Optional MCP server for AI clients that support the Model Context Protocol.\n---\n\n# Agent MCP\n\n[`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp) is an optional [Model Context Protocol](https://modelcontextprotocol.io/) (stdio) server. It indexes this site’s component docs, examples, and guides so **any MCP-capable AI client** can look up the real API.\n\nYou do **not** need MCP to use the component library. Apps still only depend on:\n\n```bash\npnpm add morya-ui\n```\n\n```ts\nimport 'morya-ui/styles.css'\n```\n\nFor Agent skill, Cursor rules, and writing MCP in one step, see [One-shot setup](/docs/setup). AI workflow: [AI setup](/docs/ai-setup). Skill behavior: [Agent Skill](/docs/agent-skill).\n\n## How to connect\n\nMCP clients start the package over stdio:\n\n```bash\nnpx -y @morya-ui/mcp\n```\n\nGeneric shape:\n\n```json\n{\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n}\n```\n\nField names differ by client. Any client that supports MCP stdio can connect.\n\n### Common client config examples\n\nSnippets for popular products. Key names may change across versions — check each product’s docs.\n\n**Cursor** (`.cursor/mcp.json` or user-level MCP settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop / Claude Code** (`claude_desktop_config.json`, etc.):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Windsurf** (MCP servers in settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Cline** (MCP servers in the VS Code extension settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Zed** (`settings.json` → `context_servers`):\n\n```json\n{\n \"context_servers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Continue** (`config.json` / YAML MCP servers — follow the current schema):\n\n```json\n{\n \"mcpServers\": [\n {\n \"name\": \"morya-ui\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n ]\n}\n```\n\n## Tools\n\n### Core — component docs\n\n| Tool | Purpose |\n| --- | --- |\n| `list` | List components / guides / examples / categories / patterns |\n| `search` | Search docs, examples, patterns, and decision guides |\n| `get_component` | Read component docs and API |\n| `get_example` | Return a source example |\n| `get_guide` | Read a guide |\n| `get_setup` | Install and setup guidance |\n| `validate_usage` | Soft-check usage against documented props/events |\n| `version` | Version and catalog status |\n\n### Advanced — page composition (optional)\n\n| Tool | Purpose |\n| --- | --- |\n| `list_patterns` | List reusable page composition patterns |\n| `get_pattern` | Read a pattern's structure, layout, and rules |\n| `recommend_page` | Recommend a pattern from page intent; optional starter scaffold |\n| `get_design_rules` | Design-token and composition rules |\n| `recommend_component` | List, read, or recommend component selection guides |\n\nMost tools accept `mode`: `zh` (default) or `en`.\n\n### Recommended workflow\n\n**Look up a component:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**Plan a page:** `recommend_page` → `get_pattern` → `get_component` / `get_example` → `get_design_rules`; use `recommend_component` when choosing between similar components\n\nPass `includeScaffold: true` to `recommend_page` for starter Vue code:\n\n```json\n{\n \"intent\": \"Oil well management list\",\n \"pageType\": \"list\",\n \"features\": [\"filters\", \"create\", \"pagination\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` modes:\n\n- omit `query` and `decision` → list decision guides\n- `decision` only (e.g. `overlay-choice`) → read one guide\n- `query` → recommend a component for a UI question\n\n## Prompt examples\n\nAfter connecting, you can ask the assistant to use this server, for example:\n\n> Use the morya-ui MCP to look up Dialog props and give an example with confirm / cancel actions.\n\n> Search for date-related components, pick one suitable for forms, and write a minimal usage from the docs.\n\n> Following the Button docs from MCP, write a delete button with `severity=\"danger\"` and validate the props.\n\nThe assistant should call tools first, then produce something like:\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton } from 'morya-ui'\n</script>\n\n<template>\n <MButton label=\"Delete\" severity=\"danger\" />\n</template>\n```\n\n## Relation to this site\n\nThe catalog is generated from the same sources as this site (component `docs/` + guide Markdown). After docs change, maintainers republish `@morya-ui/mcp`; clients using `npx -y` pick up the new release.\n\nImplementation notes live in [packages/ui-mcp/README.md](https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp).\n\n## Next steps\n\n- [One-shot setup](/docs/setup): `npx @morya-ui/setup`\n- [AI setup](/docs/ai-setup): Agent skill and MCP workflow\n- [Agent Skill](/docs/agent-skill): when to use `morya-ui-pages`\n- [Quick start](/docs/quick-start): install and use components in an app\n- [Components](/components): browse live examples and APIs\n",
26131
+ "markdown": "---\ntitle: Agent MCP\norder: 13\ndescription: Optional MCP server for AI clients that support the Model Context Protocol.\n---\n\n# Agent MCP\n\n[`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp) is an optional [Model Context Protocol](https://modelcontextprotocol.io/) (stdio) server. It indexes this site’s component docs, examples, and guides so **any MCP-capable AI client** can look up the real API.\n\nYou do **not** need MCP to use the component library. Apps still only depend on:\n\n```bash\npnpm add morya-ui\n```\n\n```ts\nimport 'morya-ui/styles.css'\n```\n\nFor Agent skill, Cursor rules, and writing MCP in one step, see [One-shot setup](/docs/setup). AI workflow: [AI setup](/docs/ai-setup). Skill behavior: [Agent Skill](/docs/agent-skill).\n\n## How to connect\n\nMCP clients start the package over stdio:\n\n```bash\nnpx -y @morya-ui/mcp\n```\n\nGeneric shape:\n\n```json\n{\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n}\n```\n\nField names differ by client. Any client that supports MCP stdio can connect.\n\n### Common client config examples\n\nSnippets for popular products. Key names may change across versions — check each product’s docs.\n\n**Cursor** (`.cursor/mcp.json` or user-level MCP settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop / Claude Code** (`claude_desktop_config.json`, etc.):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Windsurf** (MCP servers in settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Cline** (MCP servers in the VS Code extension settings):\n\n```json\n{\n \"mcpServers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Zed** (`settings.json` → `context_servers`):\n\n```json\n{\n \"context_servers\": {\n \"morya-ui\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n }\n}\n```\n\n**Continue** (`config.json` / YAML MCP servers — follow the current schema):\n\n```json\n{\n \"mcpServers\": [\n {\n \"name\": \"morya-ui\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@morya-ui/mcp\"]\n }\n ]\n}\n```\n\n## Tools\n\n### Core — component docs\n\n| Tool | Purpose |\n| --- | --- |\n| `list` | List components / guides / examples / categories / patterns |\n| `search` | Search docs, examples, patterns, and decision guides |\n| `get_component` | Read component docs and API |\n| `get_example` | Return a source example |\n| `get_guide` | Read a guide |\n| `get_setup` | Install and setup guidance |\n| `validate_usage` | Soft-check usage against documented props/events |\n| `version` | Version and catalog status |\n\n### Advanced — page composition (optional)\n\n| Tool | Purpose |\n| --- | --- |\n| `list_patterns` | List reusable page composition patterns |\n| `get_pattern` | Read a pattern's structure, layout, and rules |\n| `recommend_page` | Recommend a pattern from page intent; optional starter scaffold |\n| `get_design_rules` | Design-token and MPage* composition rules |\n| `recommend_component` | List, read, or recommend component selection guides |\n| `list_golden_pages` | List golden page samples |\n| `get_golden_page` | Read a golden page Vue source (`list-page`, `form-page`, `dashboard-page`, `login-page`, `landing-page`, `empty-state`) |\n| `list_page_snippets` | List reusable page-section snippets |\n| `get_page_snippet` | Read one snippet (filters, toolbar, form actions, …) |\n| `validate_page` | Check page composition, spacing, and double-border issues |\n\nMost tools accept `mode`: `zh` (default) or `en`.\n\nComponent lookup accepts common aliases such as `DataTable`, `数据表格`, `Pager`, and `确认弹窗`.\n\n### Recommended workflow\n\n**Look up a component:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**Plan a page:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`. Use `recommend_component` when choosing between similar components.\n\n**Edit one section:** `list_page_snippets` → `get_page_snippet` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\nPass `includeScaffold: true` to `recommend_page` for starter Vue code:\n\n```json\n{\n \"intent\": \"Oil well management list\",\n \"pageType\": \"list\",\n \"features\": [\"filters\", \"create\", \"pagination\"],\n \"mode\": \"en\",\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` modes:\n\n- omit `query` and `decision` → list decision guides\n- `decision` only → read one guide\n- `query` → recommend a component for a UI question\n\nCurrent guides include `form-surface-choice`, `overlay-choice`, `data-display-choice`, `selection-choice` (Select / TreeSelect / CascadeSelect / Listbox / SelectButton / Radio / AutoComplete), `status-label-choice`, `empty-result-choice`, `action-menu-choice`, `loading-choice`, `page-scroll-choice`, `surface-choice`, `page-section-choice`, `layout-spacing-choice`, and `surface-nesting-choice`.\n\n## Prompt examples\n\nAfter connecting, you can ask the assistant to use this server, for example:\n\n> Use the morya-ui MCP to look up Dialog props and give an example with confirm / cancel actions.\n\n> Search for date-related components, pick one suitable for forms, and write a minimal usage from the docs.\n\n> Following the Button docs from MCP, write a delete button with `severity=\"danger\"` and validate the props.\n\nThe assistant should call tools first, then produce something like:\n\n```vue\n<script setup lang=\"ts\">\nimport { MButton } from 'morya-ui'\n</script>\n\n<template>\n <MButton label=\"Delete\" severity=\"danger\" />\n</template>\n```\n\n## Relation to this site\n\nThe catalog is generated from the same sources as this site (component `docs/` + guide Markdown). After docs change, maintainers republish `@morya-ui/mcp`; clients using `npx -y` pick up the new release.\n\nImplementation notes live in [packages/ui-mcp/README.md](https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp).\n\n## Next steps\n\n- [One-shot setup](/docs/setup): `npx @morya-ui/setup`\n- [AI setup](/docs/ai-setup): Agent skill and MCP workflow\n- [Agent Skill](/docs/agent-skill): when to use `morya-ui-pages`\n- [Quick start](/docs/quick-start): install and use components in an app\n- [Components](/components): browse live examples and APIs\n",
25780
26132
  "sections": [
25781
26133
  {
25782
26134
  "title": "",
@@ -25791,7 +26143,7 @@
25791
26143
  {
25792
26144
  "title": "Tools",
25793
26145
  "id": "tools",
25794
- "body": "### Core — component docs\n\n| Tool | Purpose |\n| --- | --- |\n| `list` | List components / guides / examples / categories / patterns |\n| `search` | Search docs, examples, patterns, and decision guides |\n| `get_component` | Read component docs and API |\n| `get_example` | Return a source example |\n| `get_guide` | Read a guide |\n| `get_setup` | Install and setup guidance |\n| `validate_usage` | Soft-check usage against documented props/events |\n| `version` | Version and catalog status |\n\n### Advanced — page composition (optional)\n\n| Tool | Purpose |\n| --- | --- |\n| `list_patterns` | List reusable page composition patterns |\n| `get_pattern` | Read a pattern's structure, layout, and rules |\n| `recommend_page` | Recommend a pattern from page intent; optional starter scaffold |\n| `get_design_rules` | Design-token and composition rules |\n| `recommend_component` | List, read, or recommend component selection guides |\n\nMost tools accept `mode`: `zh` (default) or `en`.\n\n### Recommended workflow\n\n**Look up a component:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**Plan a page:** `recommend_page` → `get_pattern` → `get_component` / `get_example` → `get_design_rules`; use `recommend_component` when choosing between similar components\n\nPass `includeScaffold: true` to `recommend_page` for starter Vue code:\n\n```json\n{\n \"intent\": \"Oil well management list\",\n \"pageType\": \"list\",\n \"features\": [\"filters\", \"create\", \"pagination\"],\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` modes:\n\n- omit `query` and `decision` → list decision guides\n- `decision` only (e.g. `overlay-choice`) → read one guide\n- `query` → recommend a component for a UI question"
26146
+ "body": "### Core — component docs\n\n| Tool | Purpose |\n| --- | --- |\n| `list` | List components / guides / examples / categories / patterns |\n| `search` | Search docs, examples, patterns, and decision guides |\n| `get_component` | Read component docs and API |\n| `get_example` | Return a source example |\n| `get_guide` | Read a guide |\n| `get_setup` | Install and setup guidance |\n| `validate_usage` | Soft-check usage against documented props/events |\n| `version` | Version and catalog status |\n\n### Advanced — page composition (optional)\n\n| Tool | Purpose |\n| --- | --- |\n| `list_patterns` | List reusable page composition patterns |\n| `get_pattern` | Read a pattern's structure, layout, and rules |\n| `recommend_page` | Recommend a pattern from page intent; optional starter scaffold |\n| `get_design_rules` | Design-token and MPage* composition rules |\n| `recommend_component` | List, read, or recommend component selection guides |\n| `list_golden_pages` | List golden page samples |\n| `get_golden_page` | Read a golden page Vue source (`list-page`, `form-page`, `dashboard-page`, `login-page`, `landing-page`, `empty-state`) |\n| `list_page_snippets` | List reusable page-section snippets |\n| `get_page_snippet` | Read one snippet (filters, toolbar, form actions, …) |\n| `validate_page` | Check page composition, spacing, and double-border issues |\n\nMost tools accept `mode`: `zh` (default) or `en`.\n\nComponent lookup accepts common aliases such as `DataTable`, `数据表格`, `Pager`, and `确认弹窗`.\n\n### Recommended workflow\n\n**Look up a component:** `search` / `get_component` → `get_example` → `validate_usage`\n\n**Plan a page:** `recommend_page` → `get_golden_page` → `get_pattern` → `get_design_rules` → `get_component` / `get_example` → `validate_page`. Use `recommend_component` when choosing between similar components.\n\n**Edit one section:** `list_page_snippets` → `get_page_snippet` → `get_component` / `get_example` → `validate_usage` → `validate_page`\n\nPass `includeScaffold: true` to `recommend_page` for starter Vue code:\n\n```json\n{\n \"intent\": \"Oil well management list\",\n \"pageType\": \"list\",\n \"features\": [\"filters\", \"create\", \"pagination\"],\n \"mode\": \"en\",\n \"includeScaffold\": true\n}\n```\n\n`recommend_component` modes:\n\n- omit `query` and `decision` → list decision guides\n- `decision` only → read one guide\n- `query` → recommend a component for a UI question\n\nCurrent guides include `form-surface-choice`, `overlay-choice`, `data-display-choice`, `selection-choice` (Select / TreeSelect / CascadeSelect / Listbox / SelectButton / Radio / AutoComplete), `status-label-choice`, `empty-result-choice`, `action-menu-choice`, `loading-choice`, `page-scroll-choice`, `surface-choice`, `page-section-choice`, `layout-spacing-choice`, and `surface-nesting-choice`."
25795
26147
  },
25796
26148
  {
25797
26149
  "title": "Prompt examples",