@manohub/ui 0.6.1 → 0.7.0

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.
Files changed (36) hide show
  1. package/README.md +9 -1
  2. package/dist/components/button/index.d.ts +8 -8
  3. package/dist/components/dialog/index.d.ts +58 -6
  4. package/dist/components/dialog/index.js +45 -8
  5. package/dist/components/drawer/index.d.ts +18 -6
  6. package/dist/components/drawer/index.js +11 -5
  7. package/dist/components/input/index.d.ts +4 -4
  8. package/dist/components/input/index.js +1 -1
  9. package/dist/components/notice/index.d.ts +23 -10
  10. package/dist/components/notice/index.js +11 -5
  11. package/dist/components/notification/index.d.ts +1 -1
  12. package/dist/components/search/index.d.ts +26 -6
  13. package/dist/components/search/index.js +22 -4
  14. package/dist/components/tabs/index.d.ts +6 -2
  15. package/dist/components/tabs/index.js +9 -1
  16. package/dist/components/tabset/index.d.ts +6 -2
  17. package/dist/components/tabset/index.js +8 -1
  18. package/dist/components/tag/index.d.ts +1 -1
  19. package/dist/components/text/index.d.ts +120 -0
  20. package/dist/components/text/index.js +55 -0
  21. package/dist/components/toast/index.d.ts +4 -4
  22. package/dist/components/toast/index.js +11 -2
  23. package/dist/components/upload/index.d.ts +30 -0
  24. package/dist/components/upload/index.js +7 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +2 -0
  27. package/dist/services/dialog.d.ts +20 -5
  28. package/dist/services/dialog.js +8 -1
  29. package/dist/styles/components/dialog.css +40 -1
  30. package/dist/styles/components/input.css +1 -1
  31. package/dist/styles/components/select.css +11 -0
  32. package/dist/styles/components/text.css +101 -0
  33. package/dist/styles/components/toast.css +12 -6
  34. package/dist/styles/index.css +5 -1
  35. package/dist/styles/reset.css +205 -0
  36. package/package.json +2 -2
@@ -102,7 +102,7 @@ export declare const Notification: import("vue").DefineComponent<import("vue").E
102
102
  default: undefined;
103
103
  };
104
104
  }>> & Readonly<{}>, {
105
- icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
105
+ icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
106
106
  title: string;
107
107
  onClose: () => void;
108
108
  tone: NotificationTone;
@@ -1,5 +1,7 @@
1
1
  import { type PropType } from 'vue';
2
2
  import type { ControlSize } from '../control-size';
3
+ /** 搜索触发位的形态:`text` 主色文案按钮 / `icon` 纯图标按钮 */
4
+ export type SearchAction = 'text' | 'icon';
3
5
  export interface SearchProps {
4
6
  /** 受控值 */
5
7
  modelValue?: string;
@@ -16,6 +18,8 @@ export interface SearchProps {
16
18
  loading?: boolean;
17
19
  /** 搜索按钮文案;**不传即不渲染按钮**(只留框内放大镜,提交走回车) */
18
20
  searchText?: string;
21
+ /** 触发位形态(配合 `searchText` 或单独给):`text` 文案按钮 / `icon` 纯图标按钮 */
22
+ action?: SearchAction;
19
23
  /** 值变更回调(每次输入都调,含清空) */
20
24
  onChange?: (value: string) => void;
21
25
  /** 搜索触发(点搜索按钮 / 输入框内回车) */
@@ -26,14 +30,18 @@ export interface SearchProps {
26
30
  /**
27
31
  * 搜索框(**自绘**;输入框 + 可选搜索触发位的组合件)。
28
32
  *
29
- * ## 默认形态:**一个放大镜**
33
+ * ## 三种形态(**同屏只会出现一个「搜索」字形**)
30
34
  *
31
- * 框内的放大镜(`Input` 的 `prefix` 槽)已经把「这是搜索」这个语义占住了,
32
- * 所以**不传 `searchText` 时不渲染右侧按钮** —— 否则同一个字形在一行里出现两次,
33
- * 看着像两个控件,其实一个是装饰、一个是触发,用户无从分辨。
35
+ * | 形态 | 怎么给 | 框内放大镜 | 右侧触发位 |
36
+ * | --- | --- | --- | --- |
37
+ * | 只有回车(缺省) | 什么都不给 | ✅ | 无 |
38
+ * | 图标按钮 | `action="icon"` | ❌(让给按钮) | 主色图标按钮 |
39
+ * | 文案按钮 | `searchText="搜索"` | ✅ | 主色文案按钮 |
34
40
  *
35
- * 缺省形态的提交走**回车**(`Input` 的 `onEnter` 与 `onSearch` 是同一次语义);
36
- * 需要「有可点的触发位」时才传 `searchText`,右侧随之出现主色文案按钮。
41
+ * **框内放大镜与图标按钮不会同时出现** —— 两者是同一个语义的两种画法,
42
+ * 摆在一起就是「一行里两个放大镜,分不出哪个能点」(0.6.0 的缺陷,0.6.1 靠「不给按钮」绕开,
43
+ * 0.7.0 起由 `action="icon"` 把「图标按钮」这一档补上,取图标按钮时框内自动不再画装饰)。
44
+ * 缺省形态的提交走**回车**(`Input` 的 `onEnter` 与 `onSearch` 是同一次语义)。
37
45
  *
38
46
  * ## 为什么不是 `Input` 的一个档,而是单独一件
39
47
  *
@@ -66,6 +74,9 @@ export interface SearchProps {
66
74
  * onSearch={apply}
67
75
  * onClear={() => apply('')}
68
76
  * />
77
+ *
78
+ * @example 纯图标按钮(框内不再画装饰放大镜;`searchText` 退化为无障碍名)
79
+ * <Search modelValue={kw} action="icon" search-text="搜索" onChange={setKw} onSearch={apply} />
69
80
  */
70
81
  export declare const Search: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
71
82
  modelValue: {
@@ -100,6 +111,10 @@ export declare const Search: import("vue").DefineComponent<import("vue").Extract
100
111
  type: StringConstructor;
101
112
  default: undefined;
102
113
  };
114
+ action: {
115
+ type: PropType<SearchAction>;
116
+ default: undefined;
117
+ };
103
118
  onChange: {
104
119
  type: PropType<(value: string) => void>;
105
120
  default: undefined;
@@ -147,6 +162,10 @@ export declare const Search: import("vue").DefineComponent<import("vue").Extract
147
162
  type: StringConstructor;
148
163
  default: undefined;
149
164
  };
165
+ action: {
166
+ type: PropType<SearchAction>;
167
+ default: undefined;
168
+ };
150
169
  onChange: {
151
170
  type: PropType<(value: string) => void>;
152
171
  default: undefined;
@@ -171,6 +190,7 @@ export declare const Search: import("vue").DefineComponent<import("vue").Extract
171
190
  modelValue: string;
172
191
  clearable: boolean;
173
192
  searchText: string;
193
+ action: SearchAction;
174
194
  onSearch: (value: string) => void;
175
195
  onClear: () => void;
176
196
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -38,6 +38,10 @@ const Search = /* @__PURE__ */ defineComponent({
38
38
  type: String,
39
39
  default: void 0
40
40
  },
41
+ action: {
42
+ type: String,
43
+ default: void 0
44
+ },
41
45
  onChange: {
42
46
  type: Function,
43
47
  default: void 0
@@ -69,6 +73,9 @@ const Search = /* @__PURE__ */ defineComponent({
69
73
  if (cleared) props.onClear?.();
70
74
  };
71
75
  const search = () => props.onSearch?.(current.value ?? "");
76
+ const iconAction = computed(() => props.action === "icon");
77
+ const showAction = computed(() => iconAction.value || props.searchText !== void 0);
78
+ const actionLabel = computed(() => props.searchText ?? "搜索");
72
79
  return () => createVNode("div", {
73
80
  "class": ["mh-search", attrs.class].filter(Boolean).join(" "),
74
81
  "style": attrs.style
@@ -82,10 +89,21 @@ const Search = /* @__PURE__ */ defineComponent({
82
89
  "onChange": commit,
83
90
  "onEnter": search
84
91
  }, {
85
- prefix: () => createVNode(Icon, {
86
- "name": "search"
87
- }, null)
88
- }), props.searchText ? createVNode(Button, {
92
+ default: () => [iconAction.value ? {} : {
93
+ prefix: () => createVNode(Icon, {
94
+ "name": "search"
95
+ }, null)
96
+ }]
97
+ }), showAction.value ? iconAction.value ? createVNode(Button, {
98
+ "class": "mh-search__btn",
99
+ "variant": "primary",
100
+ "size": props.size,
101
+ "icon": "search",
102
+ "title": actionLabel.value,
103
+ "disabled": props.disabled,
104
+ "loading": props.loading,
105
+ "onClick": search
106
+ }, null) : createVNode(Button, {
89
107
  "class": "mh-search__btn",
90
108
  "variant": "primary",
91
109
  "size": props.size,
@@ -100,7 +100,9 @@ export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPr
100
100
  type: PropType<() => void>;
101
101
  default: undefined;
102
102
  };
103
- }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
103
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
104
+ 'update:value': (value: TabsValue) => true;
105
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
104
106
  options: {
105
107
  type: PropType<TabsOption[]>;
106
108
  required: true;
@@ -160,7 +162,9 @@ export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPr
160
162
  type: PropType<() => void>;
161
163
  default: undefined;
162
164
  };
163
- }>> & Readonly<{}>, {
165
+ }>> & Readonly<{
166
+ "onUpdate:value"?: ((value: TabsValue) => any) | undefined;
167
+ }>, {
164
168
  size: ControlSize;
165
169
  value: TabsValue | undefined;
166
170
  type: TabsType;
@@ -64,10 +64,17 @@ const Tabs = /* @__PURE__ */ defineComponent({
64
64
  default: void 0
65
65
  }
66
66
  },
67
+ /* 受控值必须 emit 回 `update:value`,否则 `v-model:value="x"` 是**静默失效**的:
68
+ 受控时 `props.value !== undefined` ⇒ 内部状态不更新,而外部又收不到新值 ⇒ 点 tab 毫无反应
69
+ (不报错、不警告)。本件 0.6.x 就漏了这条 —— 文档示例教 `v-model:value` 却点了不动。 */
70
+ emits: {
71
+ "update:value": (value) => true
72
+ },
67
73
  slots: Object,
68
74
  setup(props, {
69
75
  slots,
70
- attrs
76
+ attrs,
77
+ emit
71
78
  }) {
72
79
  const innerValue = ref(props.value ?? props.defaultValue ?? props.options[0]?.value);
73
80
  const current = computed(() => props.value ?? innerValue.value);
@@ -76,6 +83,7 @@ const Tabs = /* @__PURE__ */ defineComponent({
76
83
  const target = props.options.find((option) => option.value === value);
77
84
  if (target?.disabled) return;
78
85
  if (props.value === void 0) innerValue.value = value;
86
+ emit("update:value", value);
79
87
  props.onChange?.(value);
80
88
  };
81
89
  const isClosable = (option) => option.closable ?? props.closable;
@@ -68,7 +68,9 @@ export declare const Tabset: import("vue").DefineComponent<import("vue").Extract
68
68
  type: BooleanConstructor;
69
69
  default: boolean;
70
70
  };
71
- }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
71
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
72
+ 'update:value': (value: string | number) => true;
73
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
72
74
  options: {
73
75
  type: PropType<TabsetOption[]>;
74
76
  required: true;
@@ -90,7 +92,9 @@ export declare const Tabset: import("vue").DefineComponent<import("vue").Extract
90
92
  type: BooleanConstructor;
91
93
  default: boolean;
92
94
  };
93
- }>> & Readonly<{}>, {
95
+ }>> & Readonly<{
96
+ "onUpdate:value"?: ((value: string | number) => any) | undefined;
97
+ }>, {
94
98
  value: string | number | undefined;
95
99
  onChange: (value: string | number) => void;
96
100
  defaultValue: string | number | undefined;
@@ -25,10 +25,16 @@ const Tabset = /* @__PURE__ */ defineComponent({
25
25
  default: false
26
26
  }
27
27
  },
28
+ /* 同 `Tabs`:受控值必须 emit 回 `update:value`,否则 `v-model:value="current"` 静默失效
29
+ (受控时内部状态不更新、外部又收不到 ⇒ 点选项毫无反应)。 */
30
+ emits: {
31
+ "update:value": (value) => true
32
+ },
28
33
  slots: Object,
29
34
  setup(props, {
30
35
  slots,
31
- attrs
36
+ attrs,
37
+ emit
32
38
  }) {
33
39
  const innerValue = ref(props.value ?? props.defaultValue ?? props.options[0]?.value);
34
40
  const current = computed(() => props.value ?? innerValue.value);
@@ -36,6 +42,7 @@ const Tabset = /* @__PURE__ */ defineComponent({
36
42
  const target = props.options.find((option) => option.value === value);
37
43
  if (target?.disabled) return;
38
44
  if (props.value === void 0) innerValue.value = value;
45
+ emit("update:value", value);
39
46
  props.onChange?.(value);
40
47
  };
41
48
  const panels = () => {
@@ -185,7 +185,7 @@ export declare const Tag: import("vue").DefineComponent<import("vue").ExtractPro
185
185
  }>> & Readonly<{}>, {
186
186
  color: string;
187
187
  size: ControlSize;
188
- icon: "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
188
+ icon: "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
189
189
  disabled: boolean;
190
190
  name: string;
191
191
  value: string | number;
@@ -0,0 +1,120 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ /** 字号档(每档都有一枚配套的行高令牌,故**不开放**只有字号的 micro / display) */
3
+ export type TextSize = 'caption' | 'body' | 'heading' | 'title';
4
+ /** 语义色档(`success` / `warning` 取 `-strong`,与 `Notice` / `Dialog` 同一张表) */
5
+ export type TextTone = 'default' | 'muted' | 'subtle' | 'primary' | 'success' | 'warning' | 'error';
6
+ /** 字重档(缺省**不设**,即继承上下文 —— 这样「在已加粗的区域里放一段普通文字」不必显式写 regular) */
7
+ export type TextWeight = 'regular' | 'medium' | 'semibold';
8
+ /** 承载标签(只开放语义明确的这几个;`as` 决定语义,`size` 决定视觉,两者**有意解耦**) */
9
+ export type TextTag = 'span' | 'p' | 'div' | 'label' | 'small' | 'strong' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
10
+ export interface TextProps {
11
+ /** 字号档(缺省 `body` = 14/20) */
12
+ size?: TextSize;
13
+ /** 语义色档(缺省 `default` = 正文色) */
14
+ tone?: TextTone;
15
+ /** 字重档(缺省不设,继承上下文) */
16
+ weight?: TextWeight;
17
+ /** 等宽族(代码、路径、ID 一类) */
18
+ mono?: boolean;
19
+ /** 截断:`true` 单行省略 / 数字 = 最多 N 行省略 */
20
+ truncate?: boolean | number;
21
+ /** 承载标签(缺省 `span`;语义标签如 `h2` / `p` / `label` 用它,视觉仍由 `size` 定) */
22
+ as?: TextTag;
23
+ }
24
+ /**
25
+ * 文本排版(**最小排版件**:字号 / 行高 / 字重 / 语义色 / 等宽 / 截断六个维度)。
26
+ *
27
+ * ## 为什么需要它
28
+ *
29
+ * `theme` 一直有 `--ui-font-{caption,body,heading,title}` 与 `--ui-font-mono` 这套档位令牌,
30
+ * 但**没有件消费它们**:卡片描述、表单说明、只读值、列表次级信息这些「容器里的文字层级」
31
+ * 于是无处可归 —— `Card` 只管卡片外壳,`Panel` 只管区域,两者都不管内容里的排版;
32
+ * 而契约 L1-5 又禁应用侧写 `font-*` / `color`。**令牌有了、路径没有**,
33
+ * 结果就是每个应用都要为「卡片里的文字」保留一条定版例外登记(本仓 repository 的 31 处里,
34
+ * 绝大多数属于这一类)。本件把这条路径补上。
35
+ *
36
+ * ## 与 `Title` / 平台默认的关系
37
+ *
38
+ * 浏览器给 `h1`-`h6` 的字阶已被 reset 归零(`font-size: inherit` / `font-weight: inherit`),
39
+ * 所以 `as="h2"` 只贡献**语义**,视觉完全由 `size` / `weight` 决定 ——
40
+ * 这与「标题的字阶必须跟设计稿」不冲突:要多大显式给 `size`。
41
+ *
42
+ * ## 不做什么
43
+ *
44
+ * - **不做富文本**:不解析 markdown、不认 `**加粗**`(富文本排版的归属见 `@manohub/kit/CONTRACT.md` §10);
45
+ * - **不做省略的展开**:截断只表示「显示不下就省略」,需要「展开全文」交互的走业务自己实现;
46
+ * - **不承载色底 / 描边 / 内距**:那是 `Tag` / `Badge` / `Card` 的事。
47
+ *
48
+ * @example 卡片里的三行信息(标题 / 描述 / 元信息)
49
+ * <Text as="h3" size="heading" weight="semibold">{repo.name}</Text>
50
+ * <Text tone="muted" truncate>{repo.url}</Text>
51
+ * <Text as="small" size="caption" tone="subtle">{repo.updatedAt}</Text>
52
+ *
53
+ * @example 只读值 + 等宽
54
+ * <Text mono>{task.id}</Text>
55
+ *
56
+ * @example 最多两行,超出省略
57
+ * <Text :truncate="2">{longDescription}</Text>
58
+ */
59
+ export declare const Text: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
60
+ size: {
61
+ type: PropType<TextSize>;
62
+ default: string;
63
+ };
64
+ tone: {
65
+ type: PropType<TextTone>;
66
+ default: string;
67
+ };
68
+ weight: {
69
+ type: PropType<TextWeight>;
70
+ default: undefined;
71
+ };
72
+ mono: {
73
+ type: BooleanConstructor;
74
+ default: boolean;
75
+ };
76
+ truncate: {
77
+ type: PropType<boolean | number>;
78
+ default: boolean;
79
+ };
80
+ as: {
81
+ type: PropType<TextTag>;
82
+ default: string;
83
+ };
84
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
85
+ [key: string]: any;
86
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
87
+ size: {
88
+ type: PropType<TextSize>;
89
+ default: string;
90
+ };
91
+ tone: {
92
+ type: PropType<TextTone>;
93
+ default: string;
94
+ };
95
+ weight: {
96
+ type: PropType<TextWeight>;
97
+ default: undefined;
98
+ };
99
+ mono: {
100
+ type: BooleanConstructor;
101
+ default: boolean;
102
+ };
103
+ truncate: {
104
+ type: PropType<boolean | number>;
105
+ default: boolean;
106
+ };
107
+ as: {
108
+ type: PropType<TextTag>;
109
+ default: string;
110
+ };
111
+ }>> & Readonly<{}>, {
112
+ size: TextSize;
113
+ weight: TextWeight;
114
+ tone: TextTone;
115
+ mono: boolean;
116
+ truncate: number | boolean;
117
+ as: TextTag;
118
+ }, SlotsType<{
119
+ default?: () => VNodeChild;
120
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,55 @@
1
+ import { defineComponent, h } from "vue";
2
+ const Text = /* @__PURE__ */ defineComponent({
3
+ name: "Text",
4
+ inheritAttrs: false,
5
+ props: {
6
+ size: {
7
+ type: String,
8
+ default: "body"
9
+ },
10
+ tone: {
11
+ type: String,
12
+ default: "default"
13
+ },
14
+ weight: {
15
+ type: String,
16
+ default: void 0
17
+ },
18
+ mono: {
19
+ type: Boolean,
20
+ default: false
21
+ },
22
+ truncate: {
23
+ type: [Boolean, Number],
24
+ default: false
25
+ },
26
+ as: {
27
+ type: String,
28
+ default: "span"
29
+ }
30
+ },
31
+ slots: Object,
32
+ setup(props, {
33
+ attrs,
34
+ slots
35
+ }) {
36
+ return () => {
37
+ const lines = props.truncate === true ? 1 : typeof props.truncate === "number" && props.truncate >= 1 ? Math.floor(props.truncate) : 0;
38
+ const classes = ["mh-text", `mh-text--${props.size}`, `mh-text--${props.tone}`, props.weight ? `mh-text--${props.weight}` : "", props.mono ? "mh-text--mono" : "", lines === 1 ? "mh-text--truncate" : "", lines > 1 ? "mh-text--clamp" : "", attrs.class].filter(Boolean).join(" ");
39
+ const style = {
40
+ ...lines > 1 ? {
41
+ "--mh-text-lines": String(lines)
42
+ } : {},
43
+ ...attrs.style
44
+ };
45
+ return h(props.as, {
46
+ ...attrs,
47
+ class: classes,
48
+ style
49
+ }, [slots.default?.()]);
50
+ };
51
+ }
52
+ });
53
+ export {
54
+ Text
55
+ };
@@ -99,7 +99,7 @@ export declare const Toast: import("vue").DefineComponent<import("vue").ExtractP
99
99
  onClose?: (() => any) | undefined;
100
100
  }>, {
101
101
  text: string;
102
- icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
102
+ icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
103
103
  tone: ToastTone;
104
104
  closable: boolean;
105
105
  action: string;
@@ -151,7 +151,7 @@ export declare const ToastCompound: {
151
151
  close: () => true;
152
152
  }, import("vue").PublicProps, {
153
153
  text: string;
154
- icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
154
+ icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
155
155
  tone: ToastTone;
156
156
  closable: boolean;
157
157
  action: string;
@@ -205,7 +205,7 @@ export declare const ToastCompound: {
205
205
  onClose?: (() => any) | undefined;
206
206
  }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, {
207
207
  text: string;
208
- icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
208
+ icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
209
209
  tone: ToastTone;
210
210
  closable: boolean;
211
211
  action: string;
@@ -256,7 +256,7 @@ export declare const ToastCompound: {
256
256
  close: () => true;
257
257
  }, string, {
258
258
  text: string;
259
- icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "wrench" | "plus" | "bell" | "settings" | "logout" | "home" | "workbench" | "grid-dots" | "heart" | "heart-filled" | "edit" | "refresh" | "upload" | "save" | "more" | "eye" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "sparkles" | "shield-check" | "shield-alert" | "history";
259
+ icon: boolean | "filter" | "copy" | "help" | "table" | "menu" | "search" | "link" | "delete" | "image" | "close" | "key" | "page-title" | "loading" | "info" | "alert" | "chevron-left" | "chevron-right" | "chevron-down" | "chevron-up" | "check" | "user" | "download" | "back" | "folder" | "folder-open" | "file" | "file-code" | "file-json" | "file-text" | "terminal" | "shield" | "tool" | "plus" | "notification" | "settings" | "logout" | "home" | "workbench" | "apps" | "favorite" | "favorite-filled" | "drag-handle" | "edit" | "refresh" | "upload" | "save" | "more" | "preview" | "external-link" | "minus" | "plus-circle" | "close-circle" | "list" | "calendar" | "clock" | "lock" | "unlock" | "users" | "archive" | "package" | "plug" | "branch" | "tag" | "ai" | "shield-check" | "shield-alert" | "history";
260
260
  tone: ToastTone;
261
261
  closable: boolean;
262
262
  action: string;
@@ -67,11 +67,20 @@ const Toast = /* @__PURE__ */ defineComponent({
67
67
  return () => {
68
68
  const hasAction = Boolean(props.action || slots.action);
69
69
  return createVNode("div", {
70
- "class": ["mh-toast", props.tone === "loading" ? "mh-toast--loading" : "", hasAction ? "mh-toast--action" : "", attrs.class].filter(Boolean).join(" "),
70
+ "class": [
71
+ "mh-toast",
72
+ /* 语义档一律落在**根修饰符**:`.mh-<件>--<tone>` 是本包 tone 维度的统一落点
73
+ (`Badge` / `Dialog` / `Notice` / `Notification` / `Tag` / `Text` 同款)。
74
+ 此前本件把 tone 落在 `.mh-toast__icon--<tone>`,是唯一一个落子元素修饰符的 ——
75
+ 消费方按「组件名 → 类名」的直觉拼 `.mh-toast--success` 会落空(缺陷 §3.5)。 */
76
+ `mh-toast--${props.tone}`,
77
+ hasAction ? "mh-toast--action" : "",
78
+ attrs.class
79
+ ].filter(Boolean).join(" "),
71
80
  "style": attrs.style,
72
81
  "role": "status"
73
82
  }, [props.icon === false ? null : createVNode("span", {
74
- "class": ["mh-toast__icon", `mh-toast__icon--${props.tone}`].join(" ")
83
+ "class": "mh-toast__icon"
75
84
  }, [createVNode(Icon, {
76
85
  "name": typeof props.icon === "string" ? props.icon : TONE_ICON[props.tone],
77
86
  "size": props.tone === "loading" ? 16 : 12
@@ -40,6 +40,12 @@ export declare const Upload: import("vue").DefineComponent<import("vue").Extract
40
40
  type: StringConstructor;
41
41
  default: undefined;
42
42
  };
43
+ /**
44
+ * 是否允许多选(**默认关**,与主流一致)。
45
+ *
46
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
47
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
48
+ */
43
49
  multiple: {
44
50
  type: BooleanConstructor;
45
51
  default: boolean;
@@ -94,6 +100,12 @@ export declare const Upload: import("vue").DefineComponent<import("vue").Extract
94
100
  type: StringConstructor;
95
101
  default: undefined;
96
102
  };
103
+ /**
104
+ * 是否允许多选(**默认关**,与主流一致)。
105
+ *
106
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
107
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
108
+ */
97
109
  multiple: {
98
110
  type: BooleanConstructor;
99
111
  default: boolean;
@@ -164,6 +176,12 @@ export declare const UploadCompound: {
164
176
  type: StringConstructor;
165
177
  default: undefined;
166
178
  };
179
+ /**
180
+ * 是否允许多选(**默认关**,与主流一致)。
181
+ *
182
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
183
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
184
+ */
167
185
  multiple: {
168
186
  type: BooleanConstructor;
169
187
  default: boolean;
@@ -239,6 +257,12 @@ export declare const UploadCompound: {
239
257
  type: StringConstructor;
240
258
  default: undefined;
241
259
  };
260
+ /**
261
+ * 是否允许多选(**默认关**,与主流一致)。
262
+ *
263
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
264
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
265
+ */
242
266
  multiple: {
243
267
  type: BooleanConstructor;
244
268
  default: boolean;
@@ -309,6 +333,12 @@ export declare const UploadCompound: {
309
333
  type: StringConstructor;
310
334
  default: undefined;
311
335
  };
336
+ /**
337
+ * 是否允许多选(**默认关**,与主流一致)。
338
+ *
339
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
340
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
341
+ */
312
342
  multiple: {
313
343
  type: BooleanConstructor;
314
344
  default: boolean;
@@ -19,9 +19,15 @@ const Upload = /* @__PURE__ */ defineComponent({
19
19
  type: String,
20
20
  default: void 0
21
21
  },
22
+ /**
23
+ * 是否允许多选(**默认关**,与主流一致)。
24
+ *
25
+ * 0.6.x 默认开 + `maxCount` 默认 0(不限量)⇒ 拖入一堆文件会被**静默全部接收** ——
26
+ * 单文件场景(换头像、传一份合同)因此多收文件且不报错。要多选请显式 `multiple`。
27
+ */
22
28
  multiple: {
23
29
  type: Boolean,
24
- default: true
30
+ default: false
25
31
  },
26
32
  disabled: {
27
33
  type: Boolean,
package/dist/index.d.ts CHANGED
@@ -27,6 +27,7 @@ export { Avatar, type AvatarProps, type AvatarSize, type AvatarCompound } from '
27
27
  export { Skeleton, type SkeletonProps } from './components/skeleton';
28
28
  export { Radio, type RadioProps, type RadioCompound, type RadioCompoundType, type RadioCardItem, type RadioCardValue, } from './components/radio';
29
29
  export { Tag, type TagProps } from './components/tag';
30
+ export { Text, type TextProps, type TextSize, type TextTone, type TextWeight, type TextTag, } from './components/text';
30
31
  export { Tree, type TreeNode } from './components/tree';
31
32
  export { ListView, type ListViewProps, type ListViewStatus, type ListViewStatusTone, type ListViewCardItemProps, type ListViewCompound, } from './components/list-view';
32
33
  export { Badge, type BadgeTone, type BadgeShape, type BadgeSize, type BadgeDot, type BadgeStatus, } from './components/badge';
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { Avatar } from "./components/avatar/index.js";
10
10
  import { Skeleton } from "./components/skeleton/index.js";
11
11
  import { Radio } from "./components/radio/index.js";
12
12
  import { Tag } from "./components/tag/index.js";
13
+ import { Text } from "./components/text/index.js";
13
14
  import { Tree } from "./components/tree/index.js";
14
15
  import { ListView } from "./components/list-view/index.js";
15
16
  import { Badge } from "./components/badge/index.js";
@@ -80,6 +81,7 @@ export {
80
81
  Tabs,
81
82
  Tabset,
82
83
  Tag,
84
+ Text,
83
85
  Textarea,
84
86
  Toast,
85
87
  Tooltip,