@manohub/ui 0.10.3 → 0.10.5
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/components/filter/index.d.ts +74 -6
- package/dist/components/filter/index.js +38 -10
- package/dist/components/tabs/index.d.ts +25 -0
- package/dist/components/tabs/index.js +12 -1
- package/dist/index.d.ts +1 -1
- package/dist/styles/components/capsule.css +8 -0
- package/dist/styles/components/form.css +11 -16
- package/dist/styles/components/input.css +6 -1
- package/dist/styles/operations/tabs.css +11 -2
- package/package.json +2 -2
|
@@ -13,6 +13,18 @@ export type FilterValues = Record<string, FilterValue>;
|
|
|
13
13
|
* 会显示占位文案)—— 两条路子的最终视觉一致,见 `docs/components/filter.md`。
|
|
14
14
|
*/
|
|
15
15
|
export declare const FILTER_ALL = "all";
|
|
16
|
+
/**
|
|
17
|
+
* 筛选时机:
|
|
18
|
+
*
|
|
19
|
+
* - `manual`(缺省):值变化只回写快照(`onChange`),查询由**回车 / 「筛选」按钮**显式触发
|
|
20
|
+
* (`onQuery`)—— 适合「几个字段填完再查」的条件区;
|
|
21
|
+
* - `auto`:值变化即查询(发 `onQuery`)—— 适合「改即查」的轻量条件区。
|
|
22
|
+
* 此时**同一次变化不再发 `onChange`**(一个变化只对应一个事件,消费方两处都接也不会查两遍),
|
|
23
|
+
* 且操作区默认不渲染(见 `showReset`)。
|
|
24
|
+
*
|
|
25
|
+
* 两种时机下**值变化都会发 `update:modelValue`**(`v-model` 落地不受时机影响)。
|
|
26
|
+
*/
|
|
27
|
+
export type FilterTrigger = 'manual' | 'auto';
|
|
16
28
|
/**
|
|
17
29
|
* 筛选字段的作用域插槽:控件由消费方渲染,本件交出**归一后**的当前值。
|
|
18
30
|
*
|
|
@@ -56,11 +68,19 @@ export interface FilterProps {
|
|
|
56
68
|
queryText?: string;
|
|
57
69
|
/** 「重置」按钮文案 */
|
|
58
70
|
resetText?: string;
|
|
59
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* 是否渲染「重置」按钮 —— **两档的缺省口径不同**(故本项缺省是 `undefined` 而非 `true`):
|
|
73
|
+
* `manual` 缺省渲染(`:show-reset="false"` 才隐藏);`auto` 缺省**不**渲染(显式传 `true` 才留一颗)。
|
|
74
|
+
*/
|
|
60
75
|
showReset?: boolean;
|
|
61
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* 筛选时机:`manual`(缺省)值变化只回写、查询靠「筛选」按钮 / 字段区回车;
|
|
78
|
+
* `auto` 值变化**即**查询,且操作区默认不渲染(详见组件说明「筛选时机」一节)。
|
|
79
|
+
*/
|
|
80
|
+
trigger?: FilterTrigger;
|
|
81
|
+
/** 条件值变化(快照已归一)。**`auto` 下不发** —— 同一次变化改走 `onQuery` */
|
|
62
82
|
onChange?: (values: FilterValues) => void;
|
|
63
|
-
/** 「筛选」按钮 /
|
|
83
|
+
/** 「筛选」按钮 / 字段区回车(回车只作用于输入框,且不认浮层里的输入);**`auto` 下由值变化触发** */
|
|
64
84
|
onQuery?: (values: FilterValues) => void;
|
|
65
85
|
/** 「重置」按钮:全部条件清空(**不再触发 `onChange`**,避免与重置回调双触发) */
|
|
66
86
|
onReset?: (values: FilterValues) => void;
|
|
@@ -175,9 +195,24 @@ export declare const Filter: {
|
|
|
175
195
|
type: StringConstructor;
|
|
176
196
|
default: string;
|
|
177
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* 是否渲染「重置」按钮。**缺省值随时机而变**(故本 prop 缺省是 `undefined`,不是 `true`):
|
|
200
|
+
*
|
|
201
|
+
* - `trigger="manual"`(缺省):缺省**渲染**(只有显式 `:show-reset="false"` 才隐藏);
|
|
202
|
+
* - `trigger="auto"`:缺省**不渲染** —— 自动模式下操作区整块让位给字段,
|
|
203
|
+
* 要留一颗重置按钮就得**显式**写 `show-reset`。
|
|
204
|
+
*
|
|
205
|
+
* 自动模式下一键清空的另一条路是各字段自带的清除位(控件自己的 `clearable`),
|
|
206
|
+
* 或页面级入口(`Form.Header` 的 `extra` 一侧)。
|
|
207
|
+
*/
|
|
178
208
|
showReset: {
|
|
179
209
|
type: BooleanConstructor;
|
|
180
|
-
default:
|
|
210
|
+
default: undefined;
|
|
211
|
+
};
|
|
212
|
+
/** 筛选时机:`manual`(缺省,回车 / 「筛选」按钮查询)/ `auto`(值变化即查询,操作区默认不渲染) */
|
|
213
|
+
trigger: {
|
|
214
|
+
type: PropType<FilterTrigger>;
|
|
215
|
+
default: string;
|
|
181
216
|
};
|
|
182
217
|
onChange: {
|
|
183
218
|
type: PropType<(values: FilterValues) => void>;
|
|
@@ -202,6 +237,7 @@ export declare const Filter: {
|
|
|
202
237
|
defaultValue: FilterValues;
|
|
203
238
|
modelValue: FilterValues;
|
|
204
239
|
description: string;
|
|
240
|
+
trigger: FilterTrigger;
|
|
205
241
|
labelWidth: number;
|
|
206
242
|
queryText: string;
|
|
207
243
|
resetText: string;
|
|
@@ -245,9 +281,24 @@ export declare const Filter: {
|
|
|
245
281
|
type: StringConstructor;
|
|
246
282
|
default: string;
|
|
247
283
|
};
|
|
284
|
+
/**
|
|
285
|
+
* 是否渲染「重置」按钮。**缺省值随时机而变**(故本 prop 缺省是 `undefined`,不是 `true`):
|
|
286
|
+
*
|
|
287
|
+
* - `trigger="manual"`(缺省):缺省**渲染**(只有显式 `:show-reset="false"` 才隐藏);
|
|
288
|
+
* - `trigger="auto"`:缺省**不渲染** —— 自动模式下操作区整块让位给字段,
|
|
289
|
+
* 要留一颗重置按钮就得**显式**写 `show-reset`。
|
|
290
|
+
*
|
|
291
|
+
* 自动模式下一键清空的另一条路是各字段自带的清除位(控件自己的 `clearable`),
|
|
292
|
+
* 或页面级入口(`Form.Header` 的 `extra` 一侧)。
|
|
293
|
+
*/
|
|
248
294
|
showReset: {
|
|
249
295
|
type: BooleanConstructor;
|
|
250
|
-
default:
|
|
296
|
+
default: undefined;
|
|
297
|
+
};
|
|
298
|
+
/** 筛选时机:`manual`(缺省,回车 / 「筛选」按钮查询)/ `auto`(值变化即查询,操作区默认不渲染) */
|
|
299
|
+
trigger: {
|
|
300
|
+
type: PropType<FilterTrigger>;
|
|
301
|
+
default: string;
|
|
251
302
|
};
|
|
252
303
|
onChange: {
|
|
253
304
|
type: PropType<(values: FilterValues) => void>;
|
|
@@ -270,6 +321,7 @@ export declare const Filter: {
|
|
|
270
321
|
defaultValue: FilterValues;
|
|
271
322
|
modelValue: FilterValues;
|
|
272
323
|
description: string;
|
|
324
|
+
trigger: FilterTrigger;
|
|
273
325
|
labelWidth: number;
|
|
274
326
|
queryText: string;
|
|
275
327
|
resetText: string;
|
|
@@ -308,9 +360,24 @@ export declare const Filter: {
|
|
|
308
360
|
type: StringConstructor;
|
|
309
361
|
default: string;
|
|
310
362
|
};
|
|
363
|
+
/**
|
|
364
|
+
* 是否渲染「重置」按钮。**缺省值随时机而变**(故本 prop 缺省是 `undefined`,不是 `true`):
|
|
365
|
+
*
|
|
366
|
+
* - `trigger="manual"`(缺省):缺省**渲染**(只有显式 `:show-reset="false"` 才隐藏);
|
|
367
|
+
* - `trigger="auto"`:缺省**不渲染** —— 自动模式下操作区整块让位给字段,
|
|
368
|
+
* 要留一颗重置按钮就得**显式**写 `show-reset`。
|
|
369
|
+
*
|
|
370
|
+
* 自动模式下一键清空的另一条路是各字段自带的清除位(控件自己的 `clearable`),
|
|
371
|
+
* 或页面级入口(`Form.Header` 的 `extra` 一侧)。
|
|
372
|
+
*/
|
|
311
373
|
showReset: {
|
|
312
374
|
type: BooleanConstructor;
|
|
313
|
-
default:
|
|
375
|
+
default: undefined;
|
|
376
|
+
};
|
|
377
|
+
/** 筛选时机:`manual`(缺省,回车 / 「筛选」按钮查询)/ `auto`(值变化即查询,操作区默认不渲染) */
|
|
378
|
+
trigger: {
|
|
379
|
+
type: PropType<FilterTrigger>;
|
|
380
|
+
default: string;
|
|
314
381
|
};
|
|
315
382
|
onChange: {
|
|
316
383
|
type: PropType<(values: FilterValues) => void>;
|
|
@@ -335,6 +402,7 @@ export declare const Filter: {
|
|
|
335
402
|
defaultValue: FilterValues;
|
|
336
403
|
modelValue: FilterValues;
|
|
337
404
|
description: string;
|
|
405
|
+
trigger: FilterTrigger;
|
|
338
406
|
labelWidth: number;
|
|
339
407
|
queryText: string;
|
|
340
408
|
resetText: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent, createVNode, ref, h, Fragment } from "vue";
|
|
1
|
+
import { defineComponent, createVNode, ref, computed, h, Fragment } from "vue";
|
|
2
2
|
import { Button } from "../button/index.js";
|
|
3
3
|
import { FormItem, Form } from "../form/index.js";
|
|
4
4
|
const FILTER_ALL = "all";
|
|
@@ -50,9 +50,24 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
50
50
|
type: String,
|
|
51
51
|
default: "重置"
|
|
52
52
|
},
|
|
53
|
+
/**
|
|
54
|
+
* 是否渲染「重置」按钮。**缺省值随时机而变**(故本 prop 缺省是 `undefined`,不是 `true`):
|
|
55
|
+
*
|
|
56
|
+
* - `trigger="manual"`(缺省):缺省**渲染**(只有显式 `:show-reset="false"` 才隐藏);
|
|
57
|
+
* - `trigger="auto"`:缺省**不渲染** —— 自动模式下操作区整块让位给字段,
|
|
58
|
+
* 要留一颗重置按钮就得**显式**写 `show-reset`。
|
|
59
|
+
*
|
|
60
|
+
* 自动模式下一键清空的另一条路是各字段自带的清除位(控件自己的 `clearable`),
|
|
61
|
+
* 或页面级入口(`Form.Header` 的 `extra` 一侧)。
|
|
62
|
+
*/
|
|
53
63
|
showReset: {
|
|
54
64
|
type: Boolean,
|
|
55
|
-
default:
|
|
65
|
+
default: void 0
|
|
66
|
+
},
|
|
67
|
+
/** 筛选时机:`manual`(缺省,回车 / 「筛选」按钮查询)/ `auto`(值变化即查询,操作区默认不渲染) */
|
|
68
|
+
trigger: {
|
|
69
|
+
type: String,
|
|
70
|
+
default: "manual"
|
|
56
71
|
},
|
|
57
72
|
onChange: {
|
|
58
73
|
type: Function,
|
|
@@ -82,6 +97,10 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
82
97
|
if (clearing) return;
|
|
83
98
|
const snapshot2 = normalizeValues(values);
|
|
84
99
|
emit("update:modelValue", snapshot2);
|
|
100
|
+
if (props.trigger === "auto") {
|
|
101
|
+
props.onQuery?.(snapshot2);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
85
104
|
props.onChange?.(snapshot2);
|
|
86
105
|
};
|
|
87
106
|
const snapshot = () => normalizeValues(formRef.value?.getValues());
|
|
@@ -101,12 +120,14 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
101
120
|
event.preventDefault();
|
|
102
121
|
query();
|
|
103
122
|
};
|
|
104
|
-
const
|
|
123
|
+
const showResetButton = computed(() => props.trigger === "auto" ? props.showReset === true : props.showReset !== false);
|
|
124
|
+
const hasActions = computed(() => props.trigger === "manual" || showResetButton.value);
|
|
125
|
+
const renderActions = () => createVNode(Fragment, null, [props.trigger === "manual" ? createVNode(Button, {
|
|
105
126
|
"variant": "primary",
|
|
106
127
|
"onClick": query
|
|
107
128
|
}, {
|
|
108
129
|
default: () => props.queryText
|
|
109
|
-
}),
|
|
130
|
+
}) : null, showResetButton.value ? createVNode(Button, {
|
|
110
131
|
"variant": "secondary",
|
|
111
132
|
"onClick": reset
|
|
112
133
|
}, {
|
|
@@ -126,12 +147,19 @@ const FilterRoot = /* @__PURE__ */ defineComponent({
|
|
|
126
147
|
default: () => {
|
|
127
148
|
const raw = slots.default?.();
|
|
128
149
|
const fields = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
|
|
129
|
-
return [h(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
150
|
+
return [h(
|
|
151
|
+
Form.Header,
|
|
152
|
+
{
|
|
153
|
+
title: props.title,
|
|
154
|
+
description: props.description
|
|
155
|
+
},
|
|
156
|
+
/* 没有任何按钮时**不传** `extra`:`Form.Header` 认的是「插槽有没有传」,
|
|
157
|
+
传一个渲染成空的 slot 仍会撑出一行(右端空容器 + 一档行距),
|
|
158
|
+
且三样都没有时整块还会照常占位。 */
|
|
159
|
+
hasActions.value ? {
|
|
160
|
+
extra: renderActions
|
|
161
|
+
} : {}
|
|
162
|
+
), ...fields];
|
|
135
163
|
}
|
|
136
164
|
});
|
|
137
165
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PropType, type SlotsType, type VNode, type VNodeChild } from 'vue';
|
|
2
|
+
import type { ControlSize } from '../control-size';
|
|
2
3
|
/** 轨道项:`Tabs` 从 `TabPanel` 提取(写了面板时)或由 `options` 直接给(老写法) */
|
|
3
4
|
export interface TabsOption {
|
|
4
5
|
/** 项文字 */
|
|
@@ -19,6 +20,16 @@ export interface TabsProps {
|
|
|
19
20
|
onChange?: (value: string | number) => void;
|
|
20
21
|
/** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
|
|
21
22
|
lazy?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* 尺寸档(`sm` / `md` / `lg`,缺省 `md`)—— 管**两件事**:
|
|
25
|
+
*
|
|
26
|
+
* 1. **骨架的呼吸位**:`控件 → 面板` 的 `gap`(`4 / 8 / 12px`)。这一条**与皮肤无关** ——
|
|
27
|
+
* 传了 `selector` 自定义控件时同样生效(间距归骨架,控件长什么样归皮肤);
|
|
28
|
+
* 2. **缺省皮肤的尺寸档**:原样透传给 `TabBar`(高度 `24 / 32 / 40` + 同级字号)。
|
|
29
|
+
* 换了皮肤则这一条不生效:控件的尺寸归你放进来的那个控件自己管
|
|
30
|
+
* (`Capsule` / 分段按钮各有自己的 `size`),本件不代它加类。
|
|
31
|
+
*/
|
|
32
|
+
size?: ControlSize;
|
|
22
33
|
}
|
|
23
34
|
/** 一块面板的信息(本件只承载这些,自己不画任何东西) */
|
|
24
35
|
export interface TabPanelProps {
|
|
@@ -110,6 +121,9 @@ export declare const TabPanel: import("vue").DefineComponent<import("vue").Extra
|
|
|
110
121
|
* - 传插槽则整块替换:放 `Capsule`(胶囊)、按钮族的分段形态、单选卡片都行,
|
|
111
122
|
* 作用域参数 `{ value, options, select }` 把值、项(已含从 `TabPanel` 提取的那些)与选中回调
|
|
112
123
|
* 递出来。本件不认识任何选择控件的类名 —— **控制器与骨架零互指**,换皮肤不必动本件。
|
|
124
|
+
* - 尺寸档 `size` 管两件事:① 骨架的呼吸位(`.mh-tabs` 的 `gap`,4 / 8 / 12px,**与皮肤无关**);
|
|
125
|
+
* ② 缺省皮肤 `TabBar` 的高与字号(24 / 32 / 40)。换了皮肤则第 ② 条不生效 ——
|
|
126
|
+
* 控件尺寸归你的控件自己管,本件不代它加类。
|
|
113
127
|
*
|
|
114
128
|
* ## 显隐只有一条路径
|
|
115
129
|
* 本件按受控值给非选中面板下发 `hidden`,**与控件形态无关**(是不是原生 radio 都一样)。
|
|
@@ -157,6 +171,11 @@ export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPr
|
|
|
157
171
|
type: BooleanConstructor;
|
|
158
172
|
default: boolean;
|
|
159
173
|
};
|
|
174
|
+
/** 缺省皮肤的尺寸档(`sm` / `md` / `lg`);口径见 `TabsProps.size` */
|
|
175
|
+
size: {
|
|
176
|
+
type: PropType<ControlSize>;
|
|
177
|
+
default: string;
|
|
178
|
+
};
|
|
160
179
|
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
161
180
|
'update:value': (value: string | number) => true;
|
|
162
181
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -180,9 +199,15 @@ export declare const Tabs: import("vue").DefineComponent<import("vue").ExtractPr
|
|
|
180
199
|
type: BooleanConstructor;
|
|
181
200
|
default: boolean;
|
|
182
201
|
};
|
|
202
|
+
/** 缺省皮肤的尺寸档(`sm` / `md` / `lg`);口径见 `TabsProps.size` */
|
|
203
|
+
size: {
|
|
204
|
+
type: PropType<ControlSize>;
|
|
205
|
+
default: string;
|
|
206
|
+
};
|
|
183
207
|
}>> & Readonly<{
|
|
184
208
|
"onUpdate:value"?: ((value: string | number) => any) | undefined;
|
|
185
209
|
}>, {
|
|
210
|
+
size: ControlSize;
|
|
186
211
|
value: string | number | undefined;
|
|
187
212
|
onChange: (value: string | number) => void;
|
|
188
213
|
options: TabsOption[];
|
|
@@ -55,6 +55,11 @@ const Tabs = /* @__PURE__ */ defineComponent({
|
|
|
55
55
|
lazy: {
|
|
56
56
|
type: Boolean,
|
|
57
57
|
default: false
|
|
58
|
+
},
|
|
59
|
+
/** 缺省皮肤的尺寸档(`sm` / `md` / `lg`);口径见 `TabsProps.size` */
|
|
60
|
+
size: {
|
|
61
|
+
type: String,
|
|
62
|
+
default: "md"
|
|
58
63
|
}
|
|
59
64
|
},
|
|
60
65
|
/* 同 `TabBar`:受控值必须 emit 回 `update:value`,否则 `v-model:value="current"` 静默失效
|
|
@@ -107,7 +112,12 @@ const Tabs = /* @__PURE__ */ defineComponent({
|
|
|
107
112
|
}, [node]);
|
|
108
113
|
});
|
|
109
114
|
return createVNode("div", {
|
|
110
|
-
"class": [
|
|
115
|
+
"class": [
|
|
116
|
+
"mh-tabs",
|
|
117
|
+
/* `md` 缺省不发类(与 `TabBar` 同口径):骨架的呼吸位 `gap` 靠这个档位类改写 */
|
|
118
|
+
props.size === "md" ? "" : `mh-tabs--${props.size}`,
|
|
119
|
+
attrs.class
|
|
120
|
+
].filter(Boolean).join(" "),
|
|
111
121
|
"style": attrs.style
|
|
112
122
|
}, [slots.selector ? slots.selector({
|
|
113
123
|
value: current,
|
|
@@ -116,6 +126,7 @@ const Tabs = /* @__PURE__ */ defineComponent({
|
|
|
116
126
|
}) : createVNode(TabBar, {
|
|
117
127
|
"options": items,
|
|
118
128
|
"value": current,
|
|
129
|
+
"size": props.size,
|
|
119
130
|
"onChange": select
|
|
120
131
|
}, null), createVNode("div", {
|
|
121
132
|
"class": "mh-tabs-panels"
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export { Switch } from './components/switch';
|
|
|
39
39
|
export { Capsule, type CapsuleOption, type CapsuleShape } from './components/capsule';
|
|
40
40
|
export { Form, type FormProps, type FormHeaderProps, type FormItemProps, type FormValues, type FormItemSlotScope, type FormItemAlign, type FormLabelAlign, type FormColumns, type FormPadding, type FormCompound, } from './components/form';
|
|
41
41
|
export { Checkbox, type CheckboxOption, type CheckboxCompound, type CheckboxCompoundType, } from './components/checkbox';
|
|
42
|
-
export { Filter, FilterItem, FILTER_ALL, normalizeFilterValue, type FilterValue, type FilterValues, type FilterProps, type FilterItemProps, type FilterItemSlotScope, type FilterCompound, } from './components/filter';
|
|
42
|
+
export { Filter, FilterItem, FILTER_ALL, normalizeFilterValue, type FilterValue, type FilterValues, type FilterProps, type FilterItemProps, type FilterItemSlotScope, type FilterTrigger, type FilterCompound, } from './components/filter';
|
|
43
43
|
export { Notice, type NoticeTone } from './components/notice';
|
|
44
44
|
export { Notification, type NotificationTone, } from './components/notification';
|
|
45
45
|
export { Dialog, type DialogWidth } from './components/dialog';
|
|
@@ -19,9 +19,17 @@
|
|
|
19
19
|
*
|
|
20
20
|
* **与 `Tabs` 的判据**:`Tabs` 是操作层的**骨架**(只给根、面板组与收起态,不带面),
|
|
21
21
|
* 面可由本件或按钮族的分段形态担任;本件是**带自己轨道与选中胶囊的轻量选择控件**。
|
|
22
|
+
*
|
|
23
|
+
* **轨道按内容宽收缩,不被父级拉宽**(缺省档口径的第二半)—— `align-self: flex-start` 就是为这条而写:
|
|
24
|
+
* 父级若是**列向弹性**(典型是 `Tabs` 的根 `.mh-tabs`),交叉轴缺省 `stretch` 会把唯一的子项拉成通栏,
|
|
25
|
+
* 轨道底随之变成一条长胶囊(实测:内容 112px 的轨道被拉到 638px);`TabBar` 同样被拉满,但它规范里
|
|
26
|
+
* 第 1 条就是「不画轨线」,没有底色,肉眼看不出来。要**主动**撑满仍然走 `block` 档 —— 那条
|
|
27
|
+
* `width: 100%` 是显式宽度,`align-self` 管不着它(撑满与否只由 `block` 决定)。
|
|
22
28
|
*/
|
|
23
29
|
.mh-capsule {
|
|
24
30
|
display: inline-flex;
|
|
31
|
+
/* 缺省不吃父级交叉轴的拉伸(理由见上);`align-self` 只对弹性子项生效,独立使用无副作用 */
|
|
32
|
+
align-self: flex-start;
|
|
25
33
|
align-items: center;
|
|
26
34
|
gap: 0; /* 胶囊相邻无间隙 */
|
|
27
35
|
min-height: var(--ui-capsule-height);
|
|
@@ -169,7 +169,13 @@
|
|
|
169
169
|
display: inline-flex;
|
|
170
170
|
align-items: center;
|
|
171
171
|
flex: 0 0 auto;
|
|
172
|
-
line-height:
|
|
172
|
+
/* 行盒归零(`font-size: 0` + `line-height: 0`):`Tooltip` 的宿主里还夹着一层 **inline 的锚点
|
|
173
|
+
span**(`.mh-popup-anchor`),它会给内含的 `inline-flex` 触发器生成行盒 —— 行盒按基线对齐,
|
|
174
|
+
于是宿主比图标高出一个 descender 间隙(实测 16px 图标 ⇒ 宿主 17px)。宿主再把这 17px 在
|
|
175
|
+
label 行里居中,图标中线就比文字中线高 0.5px。归零后宿主高度 === 图标高度,中线才重合。
|
|
176
|
+
图标 svg 不受影响(它自带尺寸,不读字号)。 */
|
|
177
|
+
font-size: 0;
|
|
178
|
+
line-height: 0;
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
/* 触发器(问号按钮):`reset` 不代消费方归零控件外观,故边 / 底 / 内距三项自备。
|
|
@@ -182,29 +188,18 @@
|
|
|
182
188
|
padding: 0;
|
|
183
189
|
border: none;
|
|
184
190
|
background: transparent;
|
|
185
|
-
|
|
191
|
+
/* 静止:**浅灰**(`subtle`,同计数器档);滑过 / 键盘聚焦转**正文色(黑)** ——
|
|
192
|
+
从 muted(#666) 起手的那版与 hover 后的 content(#1a1a1a) 只差一档,视觉上几乎看不出交互。 */
|
|
193
|
+
color: var(--ui-base-content-subtle);
|
|
186
194
|
cursor: help;
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
.mh-form-item__tip-btn:hover
|
|
190
|
-
.mh-form-item__tip-btn:focus-visible {
|
|
197
|
+
.mh-form-item__tip-btn:hover {
|
|
191
198
|
color: var(--ui-base-content);
|
|
192
199
|
}
|
|
193
200
|
|
|
194
|
-
/* 键盘可达:气泡显形靠操作层的宿主 `:focus-within` 档,这里只管**焦点可见**(主色环)。 */
|
|
195
201
|
|
|
196
|
-
.mh-form-item__tip-btn:focus-visible {
|
|
197
|
-
outline: 2px solid var(--ui-primary);
|
|
198
|
-
outline-offset: 2px;
|
|
199
|
-
}
|
|
200
202
|
|
|
201
|
-
/* 图标尺寸:常规图标一律取全局图标档。`<Icon>` 的宽高是**属性**,面层能覆盖;
|
|
202
|
-
不写就会静默落到组件默认的 16(口径见 `contract-icon-direction.spec.ts`)。 */
|
|
203
|
-
|
|
204
|
-
.mh-form-item__tip-btn > svg {
|
|
205
|
-
width: var(--ui-font-icon);
|
|
206
|
-
height: var(--ui-font-icon);
|
|
207
|
-
}
|
|
208
203
|
|
|
209
204
|
/* label 对齐:基类默认右对齐(贴控件列,`labelAlign` 缺省档);
|
|
210
205
|
`labelAlign="left"` 时挂这个修饰类改成左对齐 —— 只给「非默认值」挂类,避免两段声明争胜出顺序。
|
|
@@ -479,7 +479,12 @@
|
|
|
479
479
|
}
|
|
480
480
|
.mh-input__wrap:has(> .mh-input--textarea) > .mh-input__counter {
|
|
481
481
|
position: absolute;
|
|
482
|
-
|
|
482
|
+
/* 右让位一个「拖拽角」:多行是 `resize: vertical`(`.mh-input--textarea`),浏览器于是在框的
|
|
483
|
+
右下角画一枚原生拖拽柄(Chromium 约 16px 见方),与计数器**同角重叠**——实测截图里
|
|
484
|
+
`0/1024` 与手柄叠在一起。故计数器在同一行内右移整一档令牌(`--ui-space-4` = 16px):
|
|
485
|
+
`bottom` 不动,底部留白口径(见上方 padding-bottom 规则)不受影响。
|
|
486
|
+
不同平台的手柄宽略有差异(Firefox 略窄),此处取整档、不按浏览器分支。 */
|
|
487
|
+
right: calc(var(--ui-input-padding-x) + var(--ui-space-4));
|
|
483
488
|
bottom: var(--ui-space-1);
|
|
484
489
|
}
|
|
485
490
|
|
|
@@ -40,11 +40,20 @@
|
|
|
40
40
|
* 面板的面与几何由皮肤族给(卡片一类);本层只写「收起态」「弹性链」与根上的呼吸位。
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
|
-
/* ===== 一、操作根:选择控件在上、面板在下 =====
|
|
43
|
+
/* ===== 一、操作根:选择控件在上、面板在下 =====
|
|
44
|
+
呼吸位(`gap`)随 `size` 档走:档位由组件在根上出 `mh-tabs--sm` / `mh-tabs--lg`
|
|
45
|
+
(`md` 缺省不发类,与 `TabBar` 同口径)。skin 只决定控件长什么样,控件与面板之间的
|
|
46
|
+
间距归骨架 —— 故本档**与皮肤无关**,传了 `selector` 自定义控件时同样生效。 */
|
|
44
47
|
.mh-tabs {
|
|
45
48
|
display: flex;
|
|
46
49
|
flex-direction: column;
|
|
47
|
-
gap: var(--ui-space-
|
|
50
|
+
gap: var(--ui-space-2); /* md(缺省):8px */
|
|
51
|
+
}
|
|
52
|
+
.mh-tabs--sm {
|
|
53
|
+
gap: var(--ui-space-1); /* sm:4px */
|
|
54
|
+
}
|
|
55
|
+
.mh-tabs--lg {
|
|
56
|
+
gap: var(--ui-space-3); /* lg:12px */
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
/* ===== 二、弹性链:面板组 → 面板 =====
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manohub/ui",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "AIHub 自绘组件层:不依赖 farris 的手写 Vue TSX 组件 + 自带令牌层(Farris 规范视觉 · daisyUI 式语义令牌 · shadcn 式 API 词汇)。",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"vue": "^3.5.0"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@manohub/icon": "^0.10.
|
|
49
|
+
"@manohub/icon": "^0.10.5"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^24.0.0",
|