@morya-ui/mcp 0.2.1 → 0.2.2

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-11T07:53:05.288Z",
2
+ "generatedAt": "2026-09-14T01:38:21.808Z",
3
3
  "library": {
4
4
  "name": "morya-ui",
5
- "version": "0.2.1"
5
+ "version": "0.2.2"
6
6
  },
7
7
  "mcp": {
8
8
  "name": "@morya-ui/mcp",
9
- "version": "0.2.1"
9
+ "version": "0.2.2"
10
10
  },
11
11
  "components": [
12
12
  {
@@ -12448,7 +12448,7 @@
12448
12448
  "sectionId": "引入",
12449
12449
  "lang": "ts",
12450
12450
  "preview": false,
12451
- "code": "import { MMenu, type MenuItem } from 'morya-ui'",
12451
+ "code": "import type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'",
12452
12452
  "locale": "zh-CN"
12453
12453
  },
12454
12454
  {
@@ -12457,7 +12457,7 @@
12457
12457
  "sectionId": "导航选中",
12458
12458
  "lang": "vue",
12459
12459
  "preview": true,
12460
- "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 style=\"\n width: 15rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\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>",
12460
+ "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>",
12461
12461
  "locale": "zh-CN"
12462
12462
  },
12463
12463
  {
@@ -12538,7 +12538,7 @@
12538
12538
  "sectionId": "import",
12539
12539
  "lang": "ts",
12540
12540
  "preview": false,
12541
- "code": "import { MMenu, type MenuItem } from 'morya-ui'",
12541
+ "code": "import type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'",
12542
12542
  "locale": "en-US"
12543
12543
  },
12544
12544
  {
@@ -12636,12 +12636,12 @@
12636
12636
  {
12637
12637
  "id": "引入",
12638
12638
  "title": "引入",
12639
- "body": "```ts\nimport { MMenu, type MenuItem } from 'morya-ui'\n```"
12639
+ "body": "```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```"
12640
12640
  },
12641
12641
  {
12642
12642
  "id": "导航选中",
12643
12643
  "title": "导航选中",
12644
- "body": "为叶子项设置稳定的 `key`,用 `v-model:selected-key` 与路由同步;点击时触发 `select`。\n\n```vue preview\n<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 style=\"\n width: 15rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\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>\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。"
12644
+ "body": "为叶子项设置稳定的 `key`,用 `v-model:selected-key` 与路由同步;点击时触发 `select`。\n\n```vue preview\n<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>\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。"
12645
12645
  },
12646
12646
  {
12647
12647
  "id": "嵌套子菜单",
@@ -12656,7 +12656,7 @@
12656
12656
  {
12657
12657
  "id": "折叠与飞出层",
12658
12658
  "title": "折叠与飞出层",
12659
- "body": "`collapsed` 隐藏文案,仅保留图标;悬停/聚焦带子项的节点时,在右侧弹出飞出层(`.m-menu--flyout`)。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: '工作区',\n icon: 'folder',\n items: [\n { key: 'home', label: '首页', icon: 'home' },\n { key: 'docs', label: '文档', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: '设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n 展开\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n 折叠\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```"
12659
+ "body": "`collapsed` 隐藏文案,仅保留图标;悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: '工作区',\n icon: 'folder',\n items: [\n { key: 'home', label: '首页', icon: 'home' },\n { key: 'docs', label: '文档', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: '设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n 展开\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n 折叠\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```"
12660
12660
  },
12661
12661
  {
12662
12662
  "id": "嵌入-layout-侧栏",
@@ -12704,7 +12704,7 @@
12704
12704
  "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)。"
12705
12705
  }
12706
12706
  ],
12707
- "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 { MMenu, type MenuItem } from 'morya-ui'\n```\n\n## 导航选中\n\n为叶子项设置稳定的 `key`,用 `v-model:selected-key` 与路由同步;点击时触发 `select`。\n\n```vue preview\n<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 style=\"\n width: 15rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\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>\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。\n\n## 嵌套子菜单\n\n点击带子项的节点可展开/收起;选中子项时父级会显示 `child-active` 高亮。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('reports')\nconst model = [\n {\n key: 'analytics',\n label: '数据分析',\n icon: 'chart-bar',\n items: [\n { key: 'reports', label: '报表', icon: 'file-text' },\n { key: 'monitor', label: '监控', icon: 'activity' },\n ],\n },\n { key: 'settings', label: '系统设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 16rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n</template>\n```\n\n## 手风琴与展开控制\n\n`accordion` 同时只保留一个一级子菜单展开。`defaultExpandedKeys` / `v-model:expanded-keys` 可受控展开项;变更 `selectedKey` 时会自动展开其祖先路径。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('a1')\nconst model = [\n { key: 'a', label: '模块 A', items: [{ key: 'a1', label: 'A-1' }] },\n { key: 'b', label: '模块 B', items: [{ key: 'b1', label: 'B-1' }] },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 14rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" accordion embedded />\n </div>\n</template>\n```\n\n## 折叠与飞出层\n\n`collapsed` 隐藏文案,仅保留图标;悬停/聚焦带子项的节点时,在右侧弹出飞出层(`.m-menu--flyout`)。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: '工作区',\n icon: 'folder',\n items: [\n { key: 'home', label: '首页', icon: 'home' },\n { key: 'docs', label: '文档', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: '设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n 展开\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n 折叠\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```\n\n## 嵌入 Layout 侧栏\n\n推荐结构:**全局 Header + 下方 `has-sider` Layout**。菜单放在 `MLayoutSider` 内,与 `v-model:collapsed` 联动。\n\n```vue preview\n<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>\n```\n\n## 水平菜单\n\n`mode=\"horizontal\"` 用于顶栏一级导航;子菜单以下拉飞出层展示,选中后自动关闭。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n { key: 'home', label: '首页', icon: 'home' },\n {\n key: 'products',\n label: '产品',\n icon: 'box',\n items: [\n { key: 'cloud', label: '云服务', icon: 'cloud' },\n { key: 'edge', label: '边缘计算', icon: 'server' },\n ],\n },\n { key: 'about', label: '关于', icon: 'info-circle' },\n]\n</script>\n\n<template>\n <div\n style=\"\n padding: 0 var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" mode=\"horizontal\" embedded />\n </div>\n</template>\n```\n\n## 反色(深色侧栏)\n\n`inverted` 配合 `MLayoutSider` 的 `inverted`,用于深色背景侧栏。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MLayout, MLayoutSider, 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]\n</script>\n\n<template>\n <MLayout\n has-sider\n style=\"\n height: 10rem;\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutSider inverted bordered style=\"width: 12rem\">\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" inverted />\n </MLayoutSider>\n </MLayout>\n</template>\n```\n\n## 弹出模式\n\n`popup` + `v-model` 将菜单作为浮层,默认 Teleport 到 `body` 并相对**默认插槽触发器**定位(无插槽时回退到最后一次指针位置)。点击外部或选中叶子项后关闭。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MButton, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst open = ref(false)\nconst model = [\n { label: '复制', command: () => undefined },\n { separator: true },\n { label: '删除', disabled: true },\n]\n</script>\n\n<template>\n <MMenu v-model=\"open\" popup :model=\"model\">\n <MButton label=\"更多操作\" @click=\"open = !open\" />\n </MMenu>\n</template>\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"
12707
+ "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\n<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>\n```\n\n未提供 `key` 时会回退到 `label`;生产环境建议始终显式设置 `key`。\n\n## 嵌套子菜单\n\n点击带子项的节点可展开/收起;选中子项时父级会显示 `child-active` 高亮。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('reports')\nconst model = [\n {\n key: 'analytics',\n label: '数据分析',\n icon: 'chart-bar',\n items: [\n { key: 'reports', label: '报表', icon: 'file-text' },\n { key: 'monitor', label: '监控', icon: 'activity' },\n ],\n },\n { key: 'settings', label: '系统设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 16rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n</template>\n```\n\n## 手风琴与展开控制\n\n`accordion` 同时只保留一个一级子菜单展开。`defaultExpandedKeys` / `v-model:expanded-keys` 可受控展开项;变更 `selectedKey` 时会自动展开其祖先路径。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('a1')\nconst model = [\n { key: 'a', label: '模块 A', items: [{ key: 'a1', label: 'A-1' }] },\n { key: 'b', label: '模块 B', items: [{ key: 'b1', label: 'B-1' }] },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 14rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" accordion embedded />\n </div>\n</template>\n```\n\n## 折叠与飞出层\n\n`collapsed` 隐藏文案,仅保留图标;悬停时在右侧显示 `MTooltip` 标签,带子项的节点还会弹出飞出层(`.m-menu--flyout`)。`collapsed-width` 应与侧栏折叠宽度一致,用于居中图标。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: '工作区',\n icon: 'folder',\n items: [\n { key: 'home', label: '首页', icon: 'home' },\n { key: 'docs', label: '文档', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: '设置', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n 展开\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n 折叠\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```\n\n## 嵌入 Layout 侧栏\n\n推荐结构:**全局 Header + 下方 `has-sider` Layout**。菜单放在 `MLayoutSider` 内,与 `v-model:collapsed` 联动。\n\n```vue preview\n<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>\n```\n\n## 水平菜单\n\n`mode=\"horizontal\"` 用于顶栏一级导航;子菜单以下拉飞出层展示,选中后自动关闭。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n { key: 'home', label: '首页', icon: 'home' },\n {\n key: 'products',\n label: '产品',\n icon: 'box',\n items: [\n { key: 'cloud', label: '云服务', icon: 'cloud' },\n { key: 'edge', label: '边缘计算', icon: 'server' },\n ],\n },\n { key: 'about', label: '关于', icon: 'info-circle' },\n]\n</script>\n\n<template>\n <div\n style=\"\n padding: 0 var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" mode=\"horizontal\" embedded />\n </div>\n</template>\n```\n\n## 反色(深色侧栏)\n\n`inverted` 配合 `MLayoutSider` 的 `inverted`,用于深色背景侧栏。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MLayout, MLayoutSider, 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]\n</script>\n\n<template>\n <MLayout\n has-sider\n style=\"\n height: 10rem;\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutSider inverted bordered style=\"width: 12rem\">\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" inverted />\n </MLayoutSider>\n </MLayout>\n</template>\n```\n\n## 弹出模式\n\n`popup` + `v-model` 将菜单作为浮层,默认 Teleport 到 `body` 并相对**默认插槽触发器**定位(无插槽时回退到最后一次指针位置)。点击外部或选中叶子项后关闭。\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MButton, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst open = ref(false)\nconst model = [\n { label: '复制', command: () => undefined },\n { separator: true },\n { label: '删除', disabled: true },\n]\n</script>\n\n<template>\n <MMenu v-model=\"open\" popup :model=\"model\">\n <MButton label=\"更多操作\" @click=\"open = !open\" />\n </MMenu>\n</template>\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"
12708
12708
  },
12709
12709
  "en-US": {
12710
12710
  "title": "Menu",
@@ -12718,7 +12718,7 @@
12718
12718
  {
12719
12719
  "id": "import",
12720
12720
  "title": "Import",
12721
- "body": "```ts\nimport { MMenu, type MenuItem } from 'morya-ui'\n```"
12721
+ "body": "```ts\nimport type {MenuItem} from 'morya-ui';\nimport { MMenu } from 'morya-ui'\n```"
12722
12722
  },
12723
12723
  {
12724
12724
  "id": "selection",
@@ -12738,7 +12738,7 @@
12738
12738
  {
12739
12739
  "id": "collapsed-flyout",
12740
12740
  "title": "Collapsed & flyout",
12741
- "body": "`collapsed` hides labels and keeps icons. Hover/focus on a group opens a right flyout (`.m-menu--flyout`). Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: 'Workspace',\n icon: 'folder',\n items: [\n { key: 'home', label: 'Home', icon: 'home' },\n { key: 'docs', label: 'Docs', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n Expanded\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n Collapsed\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```"
12741
+ "body": "`collapsed` hides labels and keeps icons. Hover shows an `MTooltip` with the label; groups also open a right flyout (`.m-menu--flyout`). Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: 'Workspace',\n icon: 'folder',\n items: [\n { key: 'home', label: 'Home', icon: 'home' },\n { key: 'docs', label: 'Docs', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n Expanded\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n Collapsed\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\n```"
12742
12742
  },
12743
12743
  {
12744
12744
  "id": "embed-in-layout-sider",
@@ -12786,7 +12786,7 @@
12786
12786
  "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)."
12787
12787
  }
12788
12788
  ],
12789
- "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 { MMenu, type MenuItem } 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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n { key: 'users', label: 'Users', icon: 'users' },\n { key: 'settings', label: 'Settings', icon: 'settings', disabled: true },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 15rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\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>\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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('reports')\nconst model = [\n {\n key: 'analytics',\n label: 'Analytics',\n icon: 'chart-bar',\n items: [\n { key: 'reports', label: 'Reports', icon: 'file-text' },\n { key: 'monitor', label: 'Monitor', icon: 'activity' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 16rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n</template>\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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('a1')\nconst model = [\n { key: 'a', label: 'Module A', items: [{ key: 'a1', label: 'A-1' }] },\n { key: 'b', label: 'Module B', items: [{ key: 'b1', label: 'B-1' }] },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 14rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" accordion embedded />\n </div>\n</template>\n```\n\n## Collapsed & flyout\n\n`collapsed` hides labels and keeps icons. Hover/focus on a group opens a right flyout (`.m-menu--flyout`). Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: 'Workspace',\n icon: 'folder',\n items: [\n { key: 'home', label: 'Home', icon: 'home' },\n { key: 'docs', label: 'Docs', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n Expanded\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n Collapsed\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\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\n<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>\n```\n\n## Horizontal mode\n\n`mode=\"horizontal\"` for top nav bars. Submenus open in a dropdown flyout and close after selection.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n { key: 'home', label: 'Home', icon: 'home' },\n {\n key: 'products',\n label: 'Products',\n icon: 'box',\n items: [\n { key: 'cloud', label: 'Cloud', icon: 'cloud' },\n { key: 'edge', label: 'Edge', icon: 'server' },\n ],\n },\n { key: 'about', label: 'About', icon: 'info-circle' },\n]\n</script>\n\n<template>\n <div\n style=\"\n padding: 0 var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" mode=\"horizontal\" embedded />\n </div>\n</template>\n```\n\n## Inverted (dark sider)\n\nUse `inverted` with `MLayoutSider`'s `inverted` on dark backgrounds.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MLayout, MLayoutSider, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n { key: 'users', label: 'Users', icon: 'users' },\n]\n</script>\n\n<template>\n <MLayout\n has-sider\n style=\"\n height: 10rem;\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutSider inverted bordered style=\"width: 12rem\">\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" inverted />\n </MLayoutSider>\n </MLayout>\n</template>\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\n<script setup lang=\"ts\">\nimport { MButton, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst open = ref(false)\nconst model = [\n { label: 'Copy', command: () => undefined },\n { separator: true },\n { label: 'Delete', disabled: true },\n]\n</script>\n\n<template>\n <MMenu v-model=\"open\" popup :model=\"model\">\n <MButton label=\"More\" @click=\"open = !open\" />\n </MMenu>\n</template>\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"
12789
+ "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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n { key: 'users', label: 'Users', icon: 'users' },\n { key: 'settings', label: 'Settings', icon: 'settings', disabled: true },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 15rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\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>\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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('reports')\nconst model = [\n {\n key: 'analytics',\n label: 'Analytics',\n icon: 'chart-bar',\n items: [\n { key: 'reports', label: 'Reports', icon: 'file-text' },\n { key: 'monitor', label: 'Monitor', icon: 'activity' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 16rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n</template>\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\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('a1')\nconst model = [\n { key: 'a', label: 'Module A', items: [{ key: 'a1', label: 'A-1' }] },\n { key: 'b', label: 'Module B', items: [{ key: 'b1', label: 'B-1' }] },\n]\n</script>\n\n<template>\n <div\n style=\"\n width: 14rem;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" accordion embedded />\n </div>\n</template>\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`). Set `collapsed-width` to match the sider width for centered icons.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n {\n key: 'workspace',\n label: 'Workspace',\n icon: 'folder',\n items: [\n { key: 'home', label: 'Home', icon: 'home' },\n { key: 'docs', label: 'Docs', icon: 'file-text' },\n ],\n },\n { key: 'settings', label: 'Settings', icon: 'settings' },\n]\n</script>\n\n<template>\n <div style=\"display: flex; gap: var(--m-space-4); align-items: stretch\">\n <div\n style=\"\n flex: 1;\n min-width: 0;\n padding: var(--m-space-3);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n \"\n >\n Expanded\n </p>\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" embedded />\n </div>\n <div\n style=\"\n width: 4.5rem;\n padding: var(--m-space-3) var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <p\n style=\"\n margin: 0 0 var(--m-space-3);\n font-size: var(--m-font-size-xs);\n color: var(--m-color-text-muted);\n text-align: center;\n \"\n >\n Collapsed\n </p>\n <MMenu\n v-model:selected-key=\"selectedKey\"\n :model=\"model\"\n collapsed\n embedded\n :collapsed-width=\"64\"\n />\n </div>\n </div>\n</template>\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\n<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>\n```\n\n## Horizontal mode\n\n`mode=\"horizontal\"` for top nav bars. Submenus open in a dropdown flyout and close after selection.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('home')\nconst model = [\n { key: 'home', label: 'Home', icon: 'home' },\n {\n key: 'products',\n label: 'Products',\n icon: 'box',\n items: [\n { key: 'cloud', label: 'Cloud', icon: 'cloud' },\n { key: 'edge', label: 'Edge', icon: 'server' },\n ],\n },\n { key: 'about', label: 'About', icon: 'info-circle' },\n]\n</script>\n\n<template>\n <div\n style=\"\n padding: 0 var(--m-space-2);\n background: var(--m-color-surface);\n border: 1px solid var(--m-color-border);\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n \"\n >\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" mode=\"horizontal\" embedded />\n </div>\n</template>\n```\n\n## Inverted (dark sider)\n\nUse `inverted` with `MLayoutSider`'s `inverted` on dark backgrounds.\n\n```vue preview\n<script setup lang=\"ts\">\nimport { MLayout, MLayoutSider, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst selectedKey = ref('dashboard')\nconst model = [\n { key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard' },\n { key: 'users', label: 'Users', icon: 'users' },\n]\n</script>\n\n<template>\n <MLayout\n has-sider\n style=\"\n height: 10rem;\n border-radius: var(--m-radius-lg);\n box-shadow: var(--m-shadow-sm);\n overflow: hidden;\n \"\n >\n <MLayoutSider inverted bordered style=\"width: 12rem\">\n <MMenu v-model:selected-key=\"selectedKey\" :model=\"model\" inverted />\n </MLayoutSider>\n </MLayout>\n</template>\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\n<script setup lang=\"ts\">\nimport { MButton, MMenu } from 'morya-ui'\nimport { ref } from 'vue'\n\nconst open = ref(false)\nconst model = [\n { label: 'Copy', command: () => undefined },\n { separator: true },\n { label: 'Delete', disabled: true },\n]\n</script>\n\n<template>\n <MMenu v-model=\"open\" popup :model=\"model\">\n <MButton label=\"More\" @click=\"open = !open\" />\n </MMenu>\n</template>\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"
12790
12790
  }
12791
12791
  }
12792
12792
  },
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-09-11T07:52:45.232Z",
3
- "catalogGeneratedAt": "2026-09-11T07:52:42.355Z",
2
+ "generatedAt": "2026-09-14T01:38:04.233Z",
3
+ "catalogGeneratedAt": "2026-09-14T01:38:01.275Z",
4
4
  "components": [
5
5
  {
6
6
  "id": "Accordion",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@morya-ui/mcp",
3
3
  "type": "module",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "description": "MCP server for morya-ui — component docs, examples, and usage guidance for AI coding agents.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp#readme",