@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/dist/decisions.js CHANGED
@@ -136,7 +136,7 @@ export const componentDecisions = [
136
136
  titleEn: 'Choosing a selection control',
137
137
  question: '选项是平面少量、层级结构、多选标签,还是需要输入搜索?',
138
138
  questionEn: 'Are options a small flat set, a hierarchy, multi-select tags, or searchable input?',
139
- keywords: ['选择', '下拉', '多选', '树选择', '搜索选择', 'select', 'treeselect', 'autocomplete', 'dropdown'],
139
+ keywords: ['选择', '下拉', '多选', '树选择', '搜索选择', '级联', '列表选择', '按钮组', 'select', 'treeselect', 'autocomplete', 'cascadeselect', 'listbox', 'selectbutton', 'radio', 'dropdown'],
140
140
  options: [
141
141
  {
142
142
  component: 'Select',
@@ -159,6 +159,34 @@ export const componentDecisions = [
159
159
  avoidWhen: ['用户只能从固定枚举中选择', '不应该允许自由输入'],
160
160
  avoidWhenEn: ['Users must choose from a fixed enum', 'Free input must not be allowed'],
161
161
  },
162
+ {
163
+ component: 'SelectButton',
164
+ when: ['选项很少且需要全部露出', '单选或多选都适合按钮组'],
165
+ whenEn: ['Only a few options, and all of them should stay visible', 'Single or multiple selection works as a button group'],
166
+ avoidWhen: ['选项超过大约 5 个', '选项很长或来自远程搜索'],
167
+ avoidWhenEn: ['More than about five options', 'Labels are long or options come from remote search'],
168
+ },
169
+ {
170
+ component: 'Radio',
171
+ when: ['少量互斥选项需要和表单文案一起阅读', '一次只能选一个'],
172
+ whenEn: ['A few mutually exclusive options should be read with the form copy', 'Only one value can be selected'],
173
+ avoidWhen: ['多选', '选项很多需要收进弹出层'],
174
+ avoidWhenEn: ['Multiple selection', 'Too many options for an always-visible list'],
175
+ },
176
+ {
177
+ component: 'Listbox',
178
+ when: ['选项需要始终以列表展示', '可筛选,但不希望收成下拉框'],
179
+ whenEn: ['Options should stay visible as a list', 'Filtering is useful, but a collapsed dropdown is not'],
180
+ avoidWhen: ['页面空间紧、只需要一个闭合的选择框'],
181
+ avoidWhenEn: ['Space is tight and a closed select is enough'],
182
+ },
183
+ {
184
+ component: 'CascadeSelect',
185
+ when: ['值要按多级分栏逐级点选', '层级是路径而不是可勾选的树'],
186
+ whenEn: ['The value is chosen column by column through levels', 'The hierarchy is a path, not a checkable tree'],
187
+ avoidWhen: ['需要勾选树节点或搜索整棵树'],
188
+ avoidWhenEn: ['Users need to check tree nodes or search the whole tree'],
189
+ },
162
190
  ],
163
191
  },
164
192
  {
@@ -383,6 +411,182 @@ export const componentDecisions = [
383
411
  },
384
412
  ],
385
413
  },
414
+ {
415
+ id: 'loading-choice',
416
+ title: '如何选择加载反馈',
417
+ titleEn: 'Choosing a loading indicator',
418
+ question: '这是区域或全屏等待、已知布局的占位、可量化进度,还是只需要阻止交互?',
419
+ questionEn: 'Is this a region or fullscreen wait, a placeholder for a known layout, measurable progress, or interaction blocking without a loading message?',
420
+ keywords: [
421
+ '加载',
422
+ '等待',
423
+ '遮罩',
424
+ '骨架',
425
+ '进度',
426
+ 'loading',
427
+ 'spinner',
428
+ 'skeleton',
429
+ 'progress',
430
+ 'v-loading',
431
+ 'mloading',
432
+ ],
433
+ options: [
434
+ {
435
+ component: 'Loading',
436
+ when: [
437
+ '一块区域或整页正在等待,用户暂时不能操作这块内容',
438
+ '需要加载文案、多种动效,或用 v-loading / loading.service 盖住已有节点',
439
+ '全屏提交、保存、跳转前的短暂等待',
440
+ ],
441
+ whenEn: [
442
+ 'A region or the whole page is waiting and that content should not be operated',
443
+ 'A caption, effect, v-loading, or loading.service mask over an existing node is needed',
444
+ 'A short fullscreen wait before submit, save, or navigation',
445
+ ],
446
+ avoidWhen: ['布局已知、希望用占位块避免跳动', '进度可以量化', '只是按钮自己的 loading 状态'],
447
+ avoidWhenEn: [
448
+ 'The layout is known and a placeholder should prevent jump',
449
+ 'Progress can be measured',
450
+ 'Only the button’s own loading state is needed',
451
+ ],
452
+ },
453
+ {
454
+ component: 'Skeleton',
455
+ when: ['内容结构已知,用占位块表示即将出现的卡片、文本或列表', '仪表盘或详情初次进入'],
456
+ whenEn: ['The content structure is known and placeholders stand in for cards, text, or lists', 'First paint of a dashboard or detail view'],
457
+ avoidWhen: ['需要明确的“正在加载”遮罩', '进度可量化'],
458
+ avoidWhenEn: ['An explicit loading mask is required', 'Progress can be measured'],
459
+ },
460
+ {
461
+ component: 'ProgressBar',
462
+ when: ['进度有百分比或可估算完成度', '上传、导入等长任务'],
463
+ whenEn: ['Progress has a percentage or an estimated completion', 'Long tasks such as upload or import'],
464
+ avoidWhen: ['不知道还要等多久', '只是挡住一块区域'],
465
+ avoidWhenEn: ['Duration is unknown', 'The only goal is to cover a region'],
466
+ },
467
+ {
468
+ component: 'ProgressSpinner',
469
+ when: ['行内或控件旁需要一个很小的转圈,不盖住内容'],
470
+ whenEn: ['A small inline spinner beside a control, without covering content'],
471
+ avoidWhen: ['区域遮罩、全屏等待或带文案的加载态'],
472
+ avoidWhenEn: ['A region mask, fullscreen wait, or loading state with a caption'],
473
+ },
474
+ {
475
+ component: 'BlockUI',
476
+ when: ['只需要阻止点击,不需要表达“正在加载”'],
477
+ whenEn: ['Interaction should be blocked without saying that something is loading'],
478
+ avoidWhen: ['用户需要知道正在等待结果'],
479
+ avoidWhenEn: ['The user needs to know a result is still pending'],
480
+ },
481
+ ],
482
+ },
483
+ {
484
+ id: 'status-label-choice',
485
+ title: '如何选择状态与标签',
486
+ titleEn: 'Choosing status, tag, chip, or badge',
487
+ question: '这是行内业务状态、分类标签、可移除实体,还是挂在控件上的数量?',
488
+ questionEn: 'Is this an inline business status, a category label, a removable entity, or a count on another control?',
489
+ keywords: ['行内状态', '状态点', '角标', '徽章', '可关闭标签', '芯片', 'status', 'badge', 'chip', 'tag', 'closable'],
490
+ options: [
491
+ {
492
+ component: 'Status',
493
+ when: ['表格单元格或标题旁的业务状态', '需要圆点或语义图标加短文案'],
494
+ whenEn: ['Business status in a table cell or beside a title', 'A dot or semantic icon plus a short label'],
495
+ avoidWhen: ['可关闭的分类标签', '挂在按钮上的数字'],
496
+ avoidWhenEn: ['A closable category label', 'A count attached to a button'],
497
+ },
498
+ {
499
+ component: 'Tag',
500
+ when: ['分类、筛选结果或可关闭标签', '需要比 Status 更像芯片的表面'],
501
+ whenEn: ['A category, filter result, or closable label', 'A chip-like surface rather than an inline status'],
502
+ avoidWhen: ['只是一行里的轻量状态', '带图片且代表一个可移除实体'],
503
+ avoidWhenEn: ['A lightweight inline status', 'An entity with an image that can be removed'],
504
+ },
505
+ {
506
+ component: 'Chip',
507
+ when: ['短实体信息,可带图标、图片和移除'],
508
+ whenEn: ['A short entity that may include an icon, image, and remove action'],
509
+ avoidWhen: ['纯状态色点', '只是分类色块'],
510
+ avoidWhenEn: ['A status dot only', 'A category color block only'],
511
+ },
512
+ {
513
+ component: 'Badge',
514
+ when: ['角标数量或圆点,附着在按钮、头像等控件上'],
515
+ whenEn: ['A count or dot attached to a button, avatar, or other control'],
516
+ avoidWhen: ['独立成行的状态文案'],
517
+ avoidWhenEn: ['A standalone status sentence'],
518
+ },
519
+ ],
520
+ },
521
+ {
522
+ id: 'empty-result-choice',
523
+ title: '空态还是结果页',
524
+ titleEn: 'Empty state vs result page',
525
+ question: '这是没有数据,还是流程已经结束的成功、失败或 HTTP 状态?',
526
+ questionEn: 'Is there simply no data, or has a flow ended in success, failure, or an HTTP status?',
527
+ keywords: ['空状态', '无数据', '首次使用', '筛选无结果', '结果页', '404', '403', '500', 'empty', 'result'],
528
+ options: [
529
+ {
530
+ component: 'Empty',
531
+ when: ['列表没有行', '筛选没有命中', '首次使用,需要引导创建'],
532
+ whenEn: ['A list has no rows', 'Filters matched nothing', 'First use, and the next step is to create something'],
533
+ avoidWhen: ['接口失败', '无权限', '页面不存在', '提交成功回执'],
534
+ avoidWhenEn: ['The request failed', 'Permission was denied', 'The page does not exist', 'A submit-success receipt'],
535
+ },
536
+ {
537
+ component: 'Result',
538
+ when: ['提交成功或失败的终点页', '403 / 404 / 500 等阻断状态', '需要明确的下一步(返回、重试、回首页)'],
539
+ whenEn: ['A terminal success or failure page', 'A blocking 403 / 404 / 500 state', 'The next step must be explicit (back, retry, home)'],
540
+ avoidWhen: ['正常的无数据', '表格内部的空行'],
541
+ avoidWhenEn: ['A normal empty collection', 'The empty slot inside a table'],
542
+ },
543
+ ],
544
+ },
545
+ {
546
+ id: 'action-menu-choice',
547
+ title: '如何选择菜单',
548
+ titleEn: 'Choosing a menu',
549
+ question: '这是按钮上的操作项、侧栏导航、右键菜单,还是全局命令搜索?',
550
+ questionEn: 'Is this an action menu on a trigger, sider navigation, a context menu, or a global command search?',
551
+ keywords: ['动作菜单', '右键', '右键菜单', '命令面板', '导航菜单', 'context menu', 'command menu', 'menubar', '上下文菜单'],
552
+ options: [
553
+ {
554
+ component: 'Dropdown',
555
+ when: ['从按钮或图标打开一组操作', '编辑、删除、更多'],
556
+ whenEn: ['Actions open from a button or icon', 'Edit, delete, or more'],
557
+ avoidWhen: ['表单里选一个枚举值', '常驻侧栏导航'],
558
+ avoidWhenEn: ['Choosing an enum in a form', 'Persistent sider navigation'],
559
+ },
560
+ {
561
+ component: 'Menu',
562
+ when: ['后台侧栏或页面内的常驻导航', '需要选中项与路由同步'],
563
+ whenEn: ['Persistent navigation in an admin sider or page', 'Selection should stay in sync with the route'],
564
+ avoidWhen: ['一次性操作菜单', '右键弹出'],
565
+ avoidWhenEn: ['A one-shot action menu', 'A right-click popup'],
566
+ },
567
+ {
568
+ component: 'ContextMenu',
569
+ when: ['在指针位置弹出,通常由右键触发'],
570
+ whenEn: ['The menu opens at the pointer, usually from a right-click'],
571
+ avoidWhen: ['可见的导航', '表单选择'],
572
+ avoidWhenEn: ['Visible navigation', 'Form selection'],
573
+ },
574
+ {
575
+ component: 'CommandMenu',
576
+ when: ['全局搜索命令或跳转', '键盘优先,例如 Cmd/Ctrl+K'],
577
+ whenEn: ['Global command search or jump', 'Keyboard-first, such as Cmd/Ctrl+K'],
578
+ avoidWhen: ['少量固定操作放在按钮旁即可'],
579
+ avoidWhenEn: ['A few fixed actions fit next to a button'],
580
+ },
581
+ {
582
+ component: 'Menubar',
583
+ when: ['顶部应用菜单,项很多且分组'],
584
+ whenEn: ['A top application menu with many grouped items'],
585
+ avoidWhen: ['侧栏只有一层链接'],
586
+ avoidWhenEn: ['The sider is a single level of links'],
587
+ },
588
+ ],
589
+ },
386
590
  ];
387
591
  export function findDecision(name) {
388
592
  const key = name.trim().toLowerCase().replace(/[-_\s]/g, '');
@@ -61,7 +61,7 @@ const statusOptions = [
61
61
  descriptionEn: 'Standard MTable placed directly in MPageContent without an extra Card wrapper.',
62
62
  pageTypes: ['list'],
63
63
  keywords: ['表格', 'table', 'pagination', 'paginator', 'empty', 'columns', 'rows'],
64
- imports: ['MTable'],
64
+ imports: ['MTable', 'MEmpty', 'MButton'],
65
65
  scriptSetup: `const columns = [
66
66
  { key: 'name', label: '名称' },
67
67
  { key: 'status', label: '状态' },
@@ -82,13 +82,19 @@ const loading = ref(false)`,
82
82
  aria-label="数据列表"
83
83
  >
84
84
  <template #empty>
85
- <p style="margin:0;padding:var(--m-space-8);text-align:center;color:var(--m-color-text-muted)">
86
- 暂无数据
87
- </p>
85
+ <MEmpty
86
+ title="还没有数据"
87
+ description="创建第一条记录后,这里会列出结果。"
88
+ icon="inbox"
89
+ >
90
+ <template #extra>
91
+ <MButton severity="primary">新建</MButton>
92
+ </template>
93
+ </MEmpty>
88
94
  </template>
89
95
  </MTable>`,
90
- rules: ['表格直接放在 MPageContent 内', '空态用 #empty,不要留空白区域'],
91
- rulesEn: ['Place the table directly in MPageContent', 'Use #empty for zero-data states'],
96
+ rules: ['表格直接放在 MPageContent 内', '空态用 MEmpty,不要留空白或单行灰字'],
97
+ rulesEn: ['Place the table directly in MPageContent', 'Use MEmpty for zero-data states, not a blank or muted sentence'],
92
98
  avoid: ['不要用 MCard 包裹 bordered MTable'],
93
99
  avoidEn: ['Do not wrap a bordered MTable with MCard'],
94
100
  },
@@ -103,12 +109,12 @@ const loading = ref(false)`,
103
109
  imports: ['MSpace', 'MButton'],
104
110
  template: `<template #cell-actions>
105
111
  <MSpace>
106
- <MButton severity="secondary" size="small">编辑</MButton>
107
- <MButton severity="danger" size="small">删除</MButton>
112
+ <MButton severity="secondary" size="small" text>编辑</MButton>
113
+ <MButton severity="danger" size="small" text>删除</MButton>
108
114
  </MSpace>
109
115
  </template>`,
110
- rules: ['行内操作用 size="small"', '危险操作使用 severity="danger" 并配合确认弹窗'],
111
- rulesEn: ['Use size="small" for row actions', 'Use severity="danger" with confirmation for destructive actions'],
116
+ rules: ['行内操作用 size="small" + text/outlined,避免一排实心按钮', '危险操作使用 severity="danger" 并配合确认弹窗'],
117
+ rulesEn: ['Use size="small" with text/outlined row actions', 'Use severity="danger" with confirmation for destructive actions'],
112
118
  avoid: ['不要用 Dropdown 代替明确的行内按钮组,除非操作很多'],
113
119
  avoidEn: ['Do not replace explicit row buttons with Dropdown unless there are many actions'],
114
120
  },
@@ -116,8 +122,8 @@ const loading = ref(false)`,
116
122
  id: 'list-status-tag',
117
123
  title: '表格状态列 Tag',
118
124
  titleEn: 'Table status tag cell',
119
- description: '在 #cell-status 中用 MTag 展示业务状态。',
120
- descriptionEn: 'Render business status with MTag in #cell-status.',
125
+ description: '在 #cell-status 中用 MTag 展示分类标签(业务状态优先用 list-status-dot / MStatus)。',
126
+ descriptionEn: 'Render category labels with MTag in #cell-status (prefer MStatus for business status).',
121
127
  pageTypes: ['list'],
122
128
  keywords: ['状态', 'tag', 'status', 'cell-status'],
123
129
  imports: ['MTag'],
@@ -313,18 +319,22 @@ const submitting = ref(false)`,
313
319
  descriptionEn: 'Recent records in a small MTable inside MCard.',
314
320
  pageTypes: ['dashboard'],
315
321
  keywords: ['recent', '最近', 'table', 'card', 'list'],
316
- imports: ['MCard', 'MTable', 'MTag'],
322
+ imports: ['MCard', 'MTable', 'MStatus'],
317
323
  scriptSetup: `const recentColumns = [
318
324
  { key: 'id', label: '工单号', width: 96 },
319
325
  { key: 'title', label: '标题' },
320
- { key: 'status', label: '状态', width: 96 },
326
+ { key: 'status', label: '状态', width: 110 },
321
327
  ]
322
328
  const recentRows = ref<Record<string, unknown>[]>([])`,
323
329
  template: `<MCard title="最近工单">
324
- <MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered />
330
+ <MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered row-key="id">
331
+ <template #cell-status="{ value }">
332
+ <MStatus :label="String(value ?? '')" severity="secondary" />
333
+ </template>
334
+ </MTable>
325
335
  </MCard>`,
326
- rules: ['明细列表放 MCard 内合理', 'size="small" 适合卡片内表格'],
327
- rulesEn: ['Detail lists inside MCard are appropriate', 'Use size="small" for in-card tables'],
336
+ rules: ['明细列表放 MCard 内合理', 'size="small" 适合卡片内表格', '行内业务状态用 MStatus'],
337
+ rulesEn: ['Detail lists inside MCard are appropriate', 'Use size="small" for in-card tables', 'Use MStatus for row business status'],
328
338
  avoid: ['卡片内表格不要再外包一层 MPageContent'],
329
339
  avoidEn: ['Do not wrap in-card tables with another MPageContent'],
330
340
  },
@@ -92,13 +92,15 @@ export declare const designRules: {
92
92
  readonly status: {
93
93
  readonly preferred: "MStatus";
94
94
  readonly chip: "MTag";
95
+ readonly badge: "MBadge";
96
+ readonly entity: "MChip";
95
97
  readonly mapping: {
96
98
  readonly active: "success";
97
99
  readonly pending: "warn";
98
100
  readonly disabled: "secondary";
99
101
  readonly error: "danger";
100
102
  };
101
- readonly note: "行内轻量状态用 MStatus;芯片/可关闭标签用 MTag";
103
+ readonly note: "行内轻量状态用 MStatus;分类或可关闭标签用 MTag;数量角标用 MBadge;可移除实体用 MChip";
102
104
  };
103
105
  readonly feedback: {
104
106
  readonly default: "message";
@@ -126,7 +128,7 @@ export declare const designRules: {
126
128
  readonly api: "field errorMessage | token-styled role=alert";
127
129
  readonly when: readonly ["登录/表单区常驻错误:优先字段 errorMessage", "表单级总结:使用 --m-* 样式的 role=alert 条(见 login-page 黄金样例)", "MMessage 组件当前主要为 message 服务宿主,勿臆造 severity 子节点 API"];
128
130
  };
129
- readonly doc: "docs/feedback-message-vs-toast.md";
131
+ readonly doc: "design-kit/.agents/skills/morya-ui-pages/references/feedback.md";
130
132
  };
131
133
  readonly global: readonly ["优先使用组件库组件和 --m-* Token", "操作反馈默认 message;仅一行文案时优先于 toast", "空态用 MEmpty;结果/阻断页用 MResult;行内状态优先 MStatus", "图标按钮建议提供 aria-label;表单字段建议有可见 label", "浮层默认 Teleport 到 body;有明确布局约束时再改 appendTo", "优先使用组件 documented variant,少写深层 CSS 覆盖"];
132
134
  };
package/dist/patterns.js CHANGED
@@ -5,7 +5,7 @@ export const pagePatterns = [
5
5
  titleEn: 'Admin list page',
6
6
  description: '用于资源管理、设备管理、用户管理等带筛选和行操作的数据列表。',
7
7
  descriptionEn: 'A resource-management list with filters, actions, row operations, and pagination.',
8
- goldenPage: 'docs/golden-pages/list-page.vue',
8
+ goldenPage: 'list-page',
9
9
  keywords: [
10
10
  '列表',
11
11
  '表格',
@@ -93,7 +93,7 @@ export const pagePatterns = [
93
93
  titleEn: 'Create or edit form page',
94
94
  description: '用于创建或编辑业务对象,包含分组字段、校验和提交状态。',
95
95
  descriptionEn: 'A create or edit page with grouped fields, validation, and submit states.',
96
- goldenPage: 'docs/golden-pages/form-page.vue',
96
+ goldenPage: 'form-page',
97
97
  keywords: ['表单', '新增', '编辑', '创建', '配置', '设置', 'form', 'create', 'edit', 'settings'],
98
98
  components: [
99
99
  { component: 'ConfigProvider', role: '应用根包裹' },
@@ -216,7 +216,7 @@ export const pagePatterns = [
216
216
  { component: 'Button', role: '刷新、查看详情和快捷操作', required: false },
217
217
  { component: 'Skeleton', role: '初始加载占位', required: false },
218
218
  ],
219
- goldenPage: 'docs/golden-pages/dashboard-page.vue',
219
+ goldenPage: 'dashboard-page',
220
220
  structure: [
221
221
  'ConfigProvider',
222
222
  '└── Layout',
@@ -267,7 +267,7 @@ export const pagePatterns = [
267
267
  titleEn: 'Empty state / no results page',
268
268
  description: '用于首次使用、搜索无结果、资源已清空或暂时没有内容的场景。',
269
269
  descriptionEn: 'For first use, no search results, empty resources, or temporarily unavailable content.',
270
- goldenPage: 'docs/golden-pages/empty-state.vue',
270
+ goldenPage: 'empty-state',
271
271
  keywords: ['空状态', '无数据', '无结果', '首次使用', 'empty', 'no results', 'no data', 'zero state'],
272
272
  components: [
273
273
  { component: 'PageContent', role: '承载空态的内容区', required: false },
@@ -297,7 +297,7 @@ export const pagePatterns = [
297
297
  titleEn: 'Login / authentication page',
298
298
  description: '用于登录、注册、找回密码和二次认证流程。',
299
299
  descriptionEn: 'For login, registration, password recovery, and second-factor authentication flows.',
300
- goldenPage: 'docs/golden-pages/login-page.vue',
300
+ goldenPage: 'login-page',
301
301
  keywords: ['登录', '注册', '认证', '密码', '验证码', 'login', 'register', 'authentication', 'password', 'otp'],
302
302
  components: [
303
303
  { component: 'ConfigProvider', role: '应用根包裹' },
@@ -329,7 +329,7 @@ export const pagePatterns = [
329
329
  titleEn: 'Marketing landing page',
330
330
  description: '用于产品官网、发布页、定价前导等公开营销表面;首屏单一任务,控件仍用 morya-ui。',
331
331
  descriptionEn: 'Public marketing surfaces (product home, launch, pre-pricing). One job in the first viewport; controls still use morya-ui.',
332
- goldenPage: 'docs/golden-pages/landing-page.vue',
332
+ goldenPage: 'landing-page',
333
333
  keywords: [
334
334
  '落地页',
335
335
  '营销',
@@ -432,7 +432,7 @@ export const pagePatterns = [
432
432
  '不使用大面积自定义背景色覆盖组件库 surface Token',
433
433
  ],
434
434
  interactionRules: [
435
- '详情加载中使用 Skeleton ProgressSpinner',
435
+ '已知布局用 Skeleton 占位;区域或全屏等待用 Loading(MLoading / v-loading / loading.service)',
436
436
  '资源不存在用 MResult status="404";列表空数据用 MEmpty,不要混用',
437
437
  '危险操作必须确认并在成功后刷新或离开当前详情页',
438
438
  ],
@@ -693,8 +693,10 @@ export const designRules = {
693
693
  status: {
694
694
  preferred: 'MStatus',
695
695
  chip: 'MTag',
696
+ badge: 'MBadge',
697
+ entity: 'MChip',
696
698
  mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' },
697
- note: '行内轻量状态用 MStatus;芯片/可关闭标签用 MTag',
699
+ note: '行内轻量状态用 MStatus;分类或可关闭标签用 MTag;数量角标用 MBadge;可移除实体用 MChip',
698
700
  },
699
701
  feedback: {
700
702
  default: 'message',
@@ -726,7 +728,7 @@ export const designRules = {
726
728
  'MMessage 组件当前主要为 message 服务宿主,勿臆造 severity 子节点 API',
727
729
  ],
728
730
  },
729
- doc: 'docs/feedback-message-vs-toast.md',
731
+ doc: 'design-kit/.agents/skills/morya-ui-pages/references/feedback.md',
730
732
  },
731
733
  global: [
732
734
  '优先使用组件库组件和 --m-* Token',
package/dist/tools.js CHANGED
@@ -933,8 +933,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
933
933
  standardId: 'layout-shell',
934
934
  type: 'height-chain',
935
935
  message: locale === 'en-US'
936
- ? 'Prefer layout-app-shell / golden pages: include html, body, #app { height: 100% } (morya-app-shell.css) with MLayout.'
937
- : '对齐 layout-app-shell / 黄金样例:配合 MLayout 使用 html, body, #app { height: 100% }(morya-app-shell.css)。',
936
+ ? 'Prefer layout-app-shell / golden pages: with MLayout, set html, body, #app { height: 100% } when the shell is not using fillViewport.'
937
+ : '对齐 layout-app-shell / 黄金样例:未使用 fillViewport 时,配合 MLayout 设置 html, body, #app { height: 100% }',
938
938
  });
939
939
  }
940
940
  if (/<MMenu\b/i.test(code)) {
@@ -1003,13 +1003,25 @@ export function createToolHandlers(catalog = loadCatalog()) {
1003
1003
  destructive: { component: 'MButton', props: ['severity="danger"'], requiresConfirmation: true },
1004
1004
  cancel: { component: 'MButton', props: ['severity="secondary"', 'text'] },
1005
1005
  },
1006
- status: { component: 'MTag', mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' } },
1006
+ status: {
1007
+ preferred: 'MStatus',
1008
+ chip: 'MTag',
1009
+ badge: 'MBadge',
1010
+ entity: 'MChip',
1011
+ mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' },
1012
+ note: 'Inline status uses MStatus; category or closable labels use MTag; counts use MBadge.',
1013
+ },
1007
1014
  feedback: {
1008
1015
  default: 'message',
1009
1016
  message: { when: ['single-line action result', 'save/delete/create confirmations'] },
1010
1017
  toast: { when: ['summary + detail', 'async or background notifications'] },
1011
- inlineMessage: { api: 'field errorMessage | token-styled role=alert', when: ['persistent form/auth errors'] },
1012
- doc: 'docs/feedback-message-vs-toast.md',
1018
+ empty: { component: 'MEmpty', when: ['no rows', 'no filter matches', 'first use'] },
1019
+ result: { component: 'MResult', when: ['terminal success/failure', '403 / 404 / 500'] },
1020
+ inlineMessage: {
1021
+ api: 'field errorMessage | token-styled role=alert',
1022
+ when: ['persistent form/auth errors; MMessage is the message host, not an inline alert'],
1023
+ },
1024
+ doc: 'design-kit/.agents/skills/morya-ui-pages/references/feedback.md',
1013
1025
  },
1014
1026
  global: [
1015
1027
  'Prefer library components and --m-* tokens.',
@@ -1104,6 +1116,14 @@ export function createToolHandlers(catalog = loadCatalog()) {
1104
1116
  install: 'pnpm add morya-ui',
1105
1117
  peer: 'vue@^3.3.0',
1106
1118
  styles: "import 'morya-ui/styles.css'",
1119
+ aiSetup: {
1120
+ command: 'npx @morya-ui/setup',
1121
+ skill: 'morya-ui-pages',
1122
+ mcp: 'npx -y @morya-ui/mcp',
1123
+ note: locale === 'en-US'
1124
+ ? 'setup installs the library, copies the page skill and Cursor rules, and merges MCP. Table data uses the rows prop. MMessage is the message host, not an inline alert.'
1125
+ : 'setup 会安装组件库、复制页面 skill 与 Cursor 规则,并合并 MCP。表格数据用 rows。MMessage 是 message 宿主,不是内嵌 Alert。',
1126
+ },
1107
1127
  guides: {
1108
1128
  introduction: pickMarkdown(intro),
1109
1129
  quickStart: pickMarkdown(quickStart),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@morya-ui/mcp",
3
3
  "type": "module",
4
- "version": "0.2.7",
4
+ "version": "0.2.9",
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",