@manohub/ui 0.10.5 → 1.0.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.
- package/README.md +155 -155
- package/dist/components/form/index.js +8 -1
- package/dist/styles/components/avatar.css +131 -131
- package/dist/styles/components/avatar.tokens.css +24 -24
- package/dist/styles/components/badge.css +266 -266
- package/dist/styles/components/badge.tokens.css +24 -24
- package/dist/styles/components/button.css +460 -460
- package/dist/styles/components/capsule.css +128 -128
- package/dist/styles/components/capsule.tokens.css +27 -27
- package/dist/styles/components/card.css +198 -198
- package/dist/styles/components/checkbox.css +145 -145
- package/dist/styles/components/checkbox.tokens.css +26 -26
- package/dist/styles/components/code-block.css +216 -216
- package/dist/styles/components/code-block.tokens.css +40 -40
- package/dist/styles/components/collapse.css +62 -62
- package/dist/styles/components/collapse.tokens.css +20 -20
- package/dist/styles/components/dialog.css +158 -158
- package/dist/styles/components/dialog.tokens.css +24 -24
- package/dist/styles/components/divider.css +75 -75
- package/dist/styles/components/divider.tokens.css +22 -22
- package/dist/styles/components/drawer.css +143 -143
- package/dist/styles/components/drawer.tokens.css +22 -22
- package/dist/styles/components/filter.css +29 -29
- package/dist/styles/components/form.css +442 -425
- package/dist/styles/components/form.tokens.css +15 -15
- package/dist/styles/components/input.css +538 -538
- package/dist/styles/components/input.tokens.css +43 -43
- package/dist/styles/components/layout.css +200 -200
- package/dist/styles/components/list-view.css +244 -244
- package/dist/styles/components/loading.css +76 -76
- package/dist/styles/components/loading.tokens.css +23 -23
- package/dist/styles/components/nav.css +48 -48
- package/dist/styles/components/notice.css +153 -153
- package/dist/styles/components/notice.tokens.css +17 -17
- package/dist/styles/components/notification.css +159 -159
- package/dist/styles/components/notification.tokens.css +37 -37
- package/dist/styles/components/page.css +473 -473
- package/dist/styles/components/pagination.css +303 -303
- package/dist/styles/components/pagination.tokens.css +32 -32
- package/dist/styles/components/panel.css +77 -77
- package/dist/styles/components/query-state.css +88 -88
- package/dist/styles/components/radio.css +271 -271
- package/dist/styles/components/radio.tokens.css +26 -26
- package/dist/styles/components/search.css +34 -34
- package/dist/styles/components/select.css +326 -326
- package/dist/styles/components/select.tokens.css +44 -44
- package/dist/styles/components/skeleton.css +60 -60
- package/dist/styles/components/skeleton.tokens.css +27 -27
- package/dist/styles/components/steps.css +205 -205
- package/dist/styles/components/steps.tokens.css +44 -44
- package/dist/styles/components/switch.css +165 -165
- package/dist/styles/components/switch.tokens.css +26 -26
- package/dist/styles/components/tabbar.css +235 -235
- package/dist/styles/components/tabbar.tokens.css +30 -30
- package/dist/styles/components/table.css +504 -504
- package/dist/styles/components/table.tokens.css +44 -44
- package/dist/styles/components/tag.css +127 -127
- package/dist/styles/components/tag.tokens.css +24 -24
- package/dist/styles/components/toast.css +185 -185
- package/dist/styles/components/toast.tokens.css +26 -26
- package/dist/styles/components/tooltip.css +89 -89
- package/dist/styles/components/tooltip.tokens.css +25 -25
- package/dist/styles/components/tree.css +173 -173
- package/dist/styles/components/upload.css +151 -151
- package/dist/styles/components/upload.tokens.css +27 -27
- package/dist/styles/index.css +153 -153
- package/dist/styles/operations/collapse.css +84 -84
- package/dist/styles/operations/popup.css +193 -193
- package/dist/styles/operations/tabs.css +82 -82
- package/package.json +62 -62
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 操作层 · 浮层(零 JS,**只给操作、不给任何面**)。
|
|
3
|
-
*
|
|
4
|
-
* 出处:`@aihub/theme` 的 `playground/components/popup.css`。
|
|
5
|
-
* 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀;**箭头不再取 utils 的 CSS 字形**,改由 `@manohub/icon`
|
|
6
|
-
* 的 `<Icon name="chevron-down" class="mh-popup-caret">` 渲染(本层只负责「展开时转向」)。
|
|
7
|
-
*
|
|
8
|
-
* 面与几何一律来自皮肤族类,面板根上并列两个类即组合:
|
|
9
|
-
* 气泡确认 = 气泡皮肤、下拉层 = 选择面板皮肤、提示 = 提示皮肤、对话框 = 卡片 + 对话框皮肤。
|
|
10
|
-
*
|
|
11
|
-
* 结构(原生 popover,零 JS 即具备轻 dismiss / Esc / top layer 渲染):
|
|
12
|
-
* <button popovertarget="p1">触发器</button>
|
|
13
|
-
* <div id="p1" popover class="mh-popup [皮肤类]" data-side="bottom">…</div>
|
|
14
|
-
*
|
|
15
|
-
* 本层只做五件事:
|
|
16
|
-
*
|
|
17
|
-
* 一、状态根 `.mh-popup` —— 三条状态源等价(与折叠的 `[open]` / `data-state` 同构):
|
|
18
|
-
* · 原生 popover:`popovertarget` 开合,`:popover-open` 即展开(本层无需为它写状态规则);
|
|
19
|
-
* · 原生 `<dialog>`:`[open]`(`showModal()` 那条路同样接得住);
|
|
20
|
-
* · 组件下发:`data-state="open|closed"`(与本仓其它件的 `data-state` 协议同款)。
|
|
21
|
-
* 收起态本该由 UA 的 `display: none` 承担(组件路径则由组件卸载)—— 但皮肤自带 display 的会以作者源
|
|
22
|
-
* 压过 UA(提示皮肤实测踩坑),故收起态仍要按高特异性重新钉一次(见「收起态派生」)。
|
|
23
|
-
*
|
|
24
|
-
* 二、触发器钩子 —— `[popovertarget]`(原生,属性即钩子)/ `.mh-popup-trigger`(组件路径),
|
|
25
|
-
* 只做「可点 + 可键盘 + 焦点环」。**触发器不做 UA 归零**(与折叠清 `<summary>` 三角标相反):
|
|
26
|
-
* 它本身就是带皮肤的控件,那样清会顶掉按钮皮肤。
|
|
27
|
-
*
|
|
28
|
-
* 三、UA 装饰归零 + 收起态派生 —— 原生 `[popover]` 与 `<dialog>` 会发下 `border` / `padding` /
|
|
29
|
-
* `background`,不归零就在面板外面多出一圈黑框;收起态则如上条所述要重新钉住 display。
|
|
30
|
-
* 两条都只落在浮层本体,不碰任何皮肤属性面。
|
|
31
|
-
*
|
|
32
|
-
* 四、零 JS 锚定 —— CSS Anchor Positioning:`position-area` 定位档(`data-side` / `data-align`)
|
|
33
|
-
* + `position-try-fallbacks` 自动翻面;锚点走 `popovertarget` 的**隐式锚**,一个 `anchor-name`
|
|
34
|
-
* 都不用写(隐式锚够不着时才用 `.mh-popup-anchor` / `.mh-popup--anchored` 那一档)。
|
|
35
|
-
* 无 `data-side` 时不落定位档 —— 模态与无锚点浮层退回**件自己声明的**视口居中
|
|
36
|
-
* (`inset: 0` + `margin: auto`)。⚠️ 这里**不能指望 UA**:UA 确有 `dialog { margin: auto }`,
|
|
37
|
-
* 但作者源无条件压过 UA 源,而宿主的 `* { margin: 0 }` reset 会把它归零 ⇒ 弹窗贴上贴左。
|
|
38
|
-
* 故居中必须由**件**写实(见 `components/dialog.css` 的 `.mh-dialog { margin: auto }`,
|
|
39
|
-
* 2026-09-30 在带 Tailwind 的宿主里实测踩到)。
|
|
40
|
-
*
|
|
41
|
-
* 五、展开态派生 —— 箭头转向:原生路径由宿主 `:has` 反推,组件路径由触发器自带的
|
|
42
|
-
* `aria-expanded` 反推。
|
|
43
|
-
*
|
|
44
|
-
* 六、hover 档 `.mh-popup--hover` —— 给「非交互提示」的纯 CSS 显形(移入 / 聚焦即出)。
|
|
45
|
-
* 必须存在的原因:popover 只能由点击或 JS 开合,CSS 开合不了;hover 触发的原生属性尚未落地。
|
|
46
|
-
* 代价见该节注释(不进 top layer:会被裁切、要自带 z-index、无 light dismiss)。
|
|
47
|
-
*
|
|
48
|
-
* **硬约束:本层规则一律走 `:where()`(特异性 0)** —— 这是「不顶掉皮肤」的机械保证:
|
|
49
|
-
* 作者源本来就高于 UA 源,故 `:where()` 压得住 UA 装饰;而对皮肤类(0-1-0 起)永远让位
|
|
50
|
-
* (反例即折叠里 `.mh-collapse > button.mh-collapse-header`:那里清的是 UA 按钮装饰,故须高特异性
|
|
51
|
-
* 且只落在组件形态的触发器上;本层结论是「能不动触发器就不动」)。
|
|
52
|
-
* 例外只有三类,都是「必须压过皮肤」的 display 与「只声明身份」的属性:
|
|
53
|
-
* ① 四条裸类规则(`.mh-popup` / `.mh-popup-anchor` / `.mh-popup-host` / `.mh-popup--anchored`)
|
|
54
|
-
* —— 声明状态根与锚点身份,皮肤族不碰这些属性面;
|
|
55
|
-
* ② 收起态规则走 `:is()`(0-3-0)—— 皮肤自带 display 会压过 UA 的收起 display:none;
|
|
56
|
-
* ③ hover 档两条(`.mh-popup.mh-popup--hover` 0-2-0 / `.mh-popup-host:hover …` 0-3-0)—— 同上。
|
|
57
|
-
* 三条 display 规则都只碰 display(hover 档另加定位与层级),不动任何皮肤属性面。
|
|
58
|
-
*
|
|
59
|
-
* 禁写清单(与折叠同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 / 遮罩色 / 动画
|
|
60
|
-
* —— 遮罩色归对话框皮肤(真实弹出层遮罩由其 `::backdrop` 画),进出场动画归显示层。
|
|
61
|
-
* 层级:popover 档由 top layer 接管(零 z-index),hover 档不进 top layer 故自带一层 z-index。
|
|
62
|
-
*/
|
|
63
|
-
/* ===== 一、状态根 ===== */
|
|
64
|
-
.mh-popup {
|
|
65
|
-
min-width: 0; /* 状态根标记;同时作本族独立基类 */
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/* ===== 二、触发器钩子(只做「可点 + 可键盘」) ===== */
|
|
69
|
-
:where(.mh-popup-trigger, [popovertarget]) {
|
|
70
|
-
cursor: pointer;
|
|
71
|
-
user-select: none;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* 可见焦点环:原生按钮有 UA 环,但带皮肤类的控件与普通元素都要有 —— 与折叠取同一句 */
|
|
75
|
-
:where(.mh-popup-trigger:focus-visible, [popovertarget]:focus-visible) {
|
|
76
|
-
outline: 2px solid var(--ui-primary);
|
|
77
|
-
outline-offset: -2px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/* ===== 三、UA 装饰归零(只落浮层本体,不碰任何皮肤属性面) ===== */
|
|
81
|
-
:where(.mh-popup[popover], dialog.mh-popup) {
|
|
82
|
-
border: 0;
|
|
83
|
-
padding: 0;
|
|
84
|
-
background: transparent;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/* 收起态派生(本层唯一一条非 `:where()` 的状态规则,理由在特异性):
|
|
88
|
-
原生 popover / dialog 的收起靠 UA 的 `display: none`,而皮肤自带 display 的会以作者源压过 UA
|
|
89
|
-
—— 提示皮肤的 inline-block 就让收起的面板在流内显形(实测踩坑)。
|
|
90
|
-
故按「收起的浮层就是 display: none」重新钉一次:`:is()` 取最具体分支,特异性 0-3-0 足以压过任何
|
|
91
|
-
皮肤类,且只碰 display 一项;组件路径(data-state)由组件卸载,不经此条。 */
|
|
92
|
-
:is(.mh-popup[popover]:not(:popover-open), dialog.mh-popup:not([open])) {
|
|
93
|
-
display: none;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* ===== 四、零 JS 锚定(CSS Anchor Positioning) ===== */
|
|
97
|
-
/* 定位档:声明「面板落在锚点的哪一侧」+ 与锚点的呼吸位(4px)。
|
|
98
|
-
皮肤或消费方要改间距/换侧,用自己的 margin / position-area 覆盖即可 —— 本层恒 0 特异性。
|
|
99
|
-
锚点 = `popovertarget` 的调用者(隐式锚,`position-anchor: auto` 是初始值,无需声明)。 */
|
|
100
|
-
:where(.mh-popup[data-side='bottom']) {
|
|
101
|
-
position-area: bottom;
|
|
102
|
-
margin-block-start: var(--ui-space-1);
|
|
103
|
-
}
|
|
104
|
-
:where(.mh-popup[data-side='top']) {
|
|
105
|
-
position-area: top;
|
|
106
|
-
margin-block-end: var(--ui-space-1);
|
|
107
|
-
}
|
|
108
|
-
:where(.mh-popup[data-side='left']) {
|
|
109
|
-
position-area: left;
|
|
110
|
-
margin-inline-end: var(--ui-space-1);
|
|
111
|
-
}
|
|
112
|
-
:where(.mh-popup[data-side='right']) {
|
|
113
|
-
position-area: right;
|
|
114
|
-
margin-inline-start: var(--ui-space-1);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/* 溢出自动翻面:贴视口边时按块轴 / 行内轴翻到对侧,零 JS 免裁切 */
|
|
118
|
-
:where(.mh-popup[data-side]) {
|
|
119
|
-
position-try-fallbacks: flip-block, flip-inline;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/* 两侧对齐档(与 reka 同名的 data-align):top / bottom 沿行内轴、left / right 沿块轴;
|
|
123
|
-
不写 data-align(或写 center)= 面板中线对齐锚点(position-area 的默认行为,实测中线偏差 0)。
|
|
124
|
-
**钉边必须用 anchor() 而不是 justify-self / align-self**(实测踩坑):
|
|
125
|
-
单关键词的 position-area(如 `bottom`)在另一条轴上是铺满**包含块**的(此处即视口)——
|
|
126
|
-
于是 `justify-self: start` 会把面板贴到视口左边(实测偏了 409px),而不是锚点左边。 */
|
|
127
|
-
:where(.mh-popup[data-side='top'][data-align='start'],
|
|
128
|
-
.mh-popup[data-side='bottom'][data-align='start']) {
|
|
129
|
-
left: anchor(left);
|
|
130
|
-
right: auto;
|
|
131
|
-
}
|
|
132
|
-
:where(.mh-popup[data-side='top'][data-align='end'],
|
|
133
|
-
.mh-popup[data-side='bottom'][data-align='end']) {
|
|
134
|
-
left: auto;
|
|
135
|
-
right: anchor(right);
|
|
136
|
-
}
|
|
137
|
-
:where(.mh-popup[data-side='left'][data-align='start'],
|
|
138
|
-
.mh-popup[data-side='right'][data-align='start']) {
|
|
139
|
-
top: anchor(top);
|
|
140
|
-
bottom: auto;
|
|
141
|
-
}
|
|
142
|
-
:where(.mh-popup[data-side='left'][data-align='end'],
|
|
143
|
-
.mh-popup[data-side='right'][data-align='end']) {
|
|
144
|
-
top: auto;
|
|
145
|
-
bottom: anchor(bottom);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/* 显式锚档(隐式锚够不着时用:浮层由 JS `showPopover()` 打开、触发器不是 `popovertarget` 元素等):
|
|
149
|
-
锚点元素挂 `.mh-popup-anchor` 声明锚点名、浮层加 `.mh-popup--anchored` 接入;
|
|
150
|
-
同页多实例用 `.mh-popup-host`(两者的共同祖先)把同名锚收敛到子树(`anchor-scope`),
|
|
151
|
-
否则固定锚点名在整页只有最后一个声明者生效。 */
|
|
152
|
-
.mh-popup-anchor {
|
|
153
|
-
anchor-name: --mh-popup-anchor;
|
|
154
|
-
}
|
|
155
|
-
.mh-popup-host {
|
|
156
|
-
anchor-scope: --mh-popup-anchor;
|
|
157
|
-
}
|
|
158
|
-
.mh-popup--anchored {
|
|
159
|
-
position-anchor: --mh-popup-anchor;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/* ===== 五、展开态派生(箭头转向:字形由 @manohub/icon 给,本层只转向) =====
|
|
163
|
-
* 前三条是**后代**关系(箭头在触发器子树里);后两条是**兄弟**关系 ——
|
|
164
|
-
* 组合件把箭头挂到触发器的同级附加位槽里(本仓的「触发器形态」:`Select` 的箭头在表壳的
|
|
165
|
-
* `.mh-input__suffix` 里,与 `[popovertarget]` 那个控件是兄弟),后代组合器一条都命不中(实测),
|
|
166
|
-
* 故补 `~ *` 一档:同宿主内、触发器**之后**的任一兄弟(及其子树)里的箭头跟着转向。 */
|
|
167
|
-
:where(.mh-popup-host:has(.mh-popup:popover-open)) [popovertarget] .mh-popup-caret,
|
|
168
|
-
:where(.mh-popup-host:has(dialog.mh-popup[open])) [popovertarget] .mh-popup-caret,
|
|
169
|
-
:where(.mh-popup-trigger[aria-expanded='true']) .mh-popup-caret,
|
|
170
|
-
:where(.mh-popup-host:has(.mh-popup:popover-open)) [popovertarget] ~ * .mh-popup-caret,
|
|
171
|
-
:where(.mh-popup-host:has(dialog.mh-popup[open])) [popovertarget] ~ * .mh-popup-caret {
|
|
172
|
-
transform: rotate(180deg);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/* ===== 六、hover 档(非交互提示:移入 / 聚焦即显形,移开即消失) =====
|
|
176
|
-
* 为何需要单独一档:原生 popover 的开合只有两个入口 —— JS `showPopover()` 与 `popovertarget`(点击),
|
|
177
|
-
* **CSS 开合不了 popover**;原生给 hover 留的口子(interest invoker)尚未落地。
|
|
178
|
-
* 故 hover 档退回普通定位元素,**不进 top layer**,代价三条,用前先认:
|
|
179
|
-
* ① 会被祖先 overflow 裁切(popover 档不会);② 层级要自带一层 z-index;③ 无 light dismiss / Esc
|
|
180
|
-
* (移开即消失,本就不需要)。换来的是提示语义正确:不吃点击、不抢焦点。
|
|
181
|
-
* 锚点必须显式声明(hover 没有隐式锚):触发器挂 `.mh-popup-anchor`、面板挂 `.mh-popup--anchored`、
|
|
182
|
-
* 两者共同祖先挂 `.mh-popup-host`(宿主 `:hover` / `:focus-within` 即显形)。`:hover` 按 DOM 祖先传播,
|
|
183
|
-
* 故指针从触发器移到面板上不会闪断。延迟与淡入属显示层 / 组件层,本层不管。
|
|
184
|
-
* 特异性说明:`display` 必须压过皮肤(提示皮肤自带 inline-block),故这两条不走 `:where()`。 */
|
|
185
|
-
.mh-popup.mh-popup--hover {
|
|
186
|
-
position: fixed;
|
|
187
|
-
z-index: 1;
|
|
188
|
-
display: none;
|
|
189
|
-
}
|
|
190
|
-
.mh-popup-host:hover .mh-popup--hover,
|
|
191
|
-
.mh-popup-host:focus-within .mh-popup--hover {
|
|
192
|
-
display: block;
|
|
193
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 操作层 · 浮层(零 JS,**只给操作、不给任何面**)。
|
|
3
|
+
*
|
|
4
|
+
* 出处:`@aihub/theme` 的 `playground/components/popup.css`。
|
|
5
|
+
* 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀;**箭头不再取 utils 的 CSS 字形**,改由 `@manohub/icon`
|
|
6
|
+
* 的 `<Icon name="chevron-down" class="mh-popup-caret">` 渲染(本层只负责「展开时转向」)。
|
|
7
|
+
*
|
|
8
|
+
* 面与几何一律来自皮肤族类,面板根上并列两个类即组合:
|
|
9
|
+
* 气泡确认 = 气泡皮肤、下拉层 = 选择面板皮肤、提示 = 提示皮肤、对话框 = 卡片 + 对话框皮肤。
|
|
10
|
+
*
|
|
11
|
+
* 结构(原生 popover,零 JS 即具备轻 dismiss / Esc / top layer 渲染):
|
|
12
|
+
* <button popovertarget="p1">触发器</button>
|
|
13
|
+
* <div id="p1" popover class="mh-popup [皮肤类]" data-side="bottom">…</div>
|
|
14
|
+
*
|
|
15
|
+
* 本层只做五件事:
|
|
16
|
+
*
|
|
17
|
+
* 一、状态根 `.mh-popup` —— 三条状态源等价(与折叠的 `[open]` / `data-state` 同构):
|
|
18
|
+
* · 原生 popover:`popovertarget` 开合,`:popover-open` 即展开(本层无需为它写状态规则);
|
|
19
|
+
* · 原生 `<dialog>`:`[open]`(`showModal()` 那条路同样接得住);
|
|
20
|
+
* · 组件下发:`data-state="open|closed"`(与本仓其它件的 `data-state` 协议同款)。
|
|
21
|
+
* 收起态本该由 UA 的 `display: none` 承担(组件路径则由组件卸载)—— 但皮肤自带 display 的会以作者源
|
|
22
|
+
* 压过 UA(提示皮肤实测踩坑),故收起态仍要按高特异性重新钉一次(见「收起态派生」)。
|
|
23
|
+
*
|
|
24
|
+
* 二、触发器钩子 —— `[popovertarget]`(原生,属性即钩子)/ `.mh-popup-trigger`(组件路径),
|
|
25
|
+
* 只做「可点 + 可键盘 + 焦点环」。**触发器不做 UA 归零**(与折叠清 `<summary>` 三角标相反):
|
|
26
|
+
* 它本身就是带皮肤的控件,那样清会顶掉按钮皮肤。
|
|
27
|
+
*
|
|
28
|
+
* 三、UA 装饰归零 + 收起态派生 —— 原生 `[popover]` 与 `<dialog>` 会发下 `border` / `padding` /
|
|
29
|
+
* `background`,不归零就在面板外面多出一圈黑框;收起态则如上条所述要重新钉住 display。
|
|
30
|
+
* 两条都只落在浮层本体,不碰任何皮肤属性面。
|
|
31
|
+
*
|
|
32
|
+
* 四、零 JS 锚定 —— CSS Anchor Positioning:`position-area` 定位档(`data-side` / `data-align`)
|
|
33
|
+
* + `position-try-fallbacks` 自动翻面;锚点走 `popovertarget` 的**隐式锚**,一个 `anchor-name`
|
|
34
|
+
* 都不用写(隐式锚够不着时才用 `.mh-popup-anchor` / `.mh-popup--anchored` 那一档)。
|
|
35
|
+
* 无 `data-side` 时不落定位档 —— 模态与无锚点浮层退回**件自己声明的**视口居中
|
|
36
|
+
* (`inset: 0` + `margin: auto`)。⚠️ 这里**不能指望 UA**:UA 确有 `dialog { margin: auto }`,
|
|
37
|
+
* 但作者源无条件压过 UA 源,而宿主的 `* { margin: 0 }` reset 会把它归零 ⇒ 弹窗贴上贴左。
|
|
38
|
+
* 故居中必须由**件**写实(见 `components/dialog.css` 的 `.mh-dialog { margin: auto }`,
|
|
39
|
+
* 2026-09-30 在带 Tailwind 的宿主里实测踩到)。
|
|
40
|
+
*
|
|
41
|
+
* 五、展开态派生 —— 箭头转向:原生路径由宿主 `:has` 反推,组件路径由触发器自带的
|
|
42
|
+
* `aria-expanded` 反推。
|
|
43
|
+
*
|
|
44
|
+
* 六、hover 档 `.mh-popup--hover` —— 给「非交互提示」的纯 CSS 显形(移入 / 聚焦即出)。
|
|
45
|
+
* 必须存在的原因:popover 只能由点击或 JS 开合,CSS 开合不了;hover 触发的原生属性尚未落地。
|
|
46
|
+
* 代价见该节注释(不进 top layer:会被裁切、要自带 z-index、无 light dismiss)。
|
|
47
|
+
*
|
|
48
|
+
* **硬约束:本层规则一律走 `:where()`(特异性 0)** —— 这是「不顶掉皮肤」的机械保证:
|
|
49
|
+
* 作者源本来就高于 UA 源,故 `:where()` 压得住 UA 装饰;而对皮肤类(0-1-0 起)永远让位
|
|
50
|
+
* (反例即折叠里 `.mh-collapse > button.mh-collapse-header`:那里清的是 UA 按钮装饰,故须高特异性
|
|
51
|
+
* 且只落在组件形态的触发器上;本层结论是「能不动触发器就不动」)。
|
|
52
|
+
* 例外只有三类,都是「必须压过皮肤」的 display 与「只声明身份」的属性:
|
|
53
|
+
* ① 四条裸类规则(`.mh-popup` / `.mh-popup-anchor` / `.mh-popup-host` / `.mh-popup--anchored`)
|
|
54
|
+
* —— 声明状态根与锚点身份,皮肤族不碰这些属性面;
|
|
55
|
+
* ② 收起态规则走 `:is()`(0-3-0)—— 皮肤自带 display 会压过 UA 的收起 display:none;
|
|
56
|
+
* ③ hover 档两条(`.mh-popup.mh-popup--hover` 0-2-0 / `.mh-popup-host:hover …` 0-3-0)—— 同上。
|
|
57
|
+
* 三条 display 规则都只碰 display(hover 档另加定位与层级),不动任何皮肤属性面。
|
|
58
|
+
*
|
|
59
|
+
* 禁写清单(与折叠同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 / 遮罩色 / 动画
|
|
60
|
+
* —— 遮罩色归对话框皮肤(真实弹出层遮罩由其 `::backdrop` 画),进出场动画归显示层。
|
|
61
|
+
* 层级:popover 档由 top layer 接管(零 z-index),hover 档不进 top layer 故自带一层 z-index。
|
|
62
|
+
*/
|
|
63
|
+
/* ===== 一、状态根 ===== */
|
|
64
|
+
.mh-popup {
|
|
65
|
+
min-width: 0; /* 状态根标记;同时作本族独立基类 */
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ===== 二、触发器钩子(只做「可点 + 可键盘」) ===== */
|
|
69
|
+
:where(.mh-popup-trigger, [popovertarget]) {
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
user-select: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* 可见焦点环:原生按钮有 UA 环,但带皮肤类的控件与普通元素都要有 —— 与折叠取同一句 */
|
|
75
|
+
:where(.mh-popup-trigger:focus-visible, [popovertarget]:focus-visible) {
|
|
76
|
+
outline: 2px solid var(--ui-primary);
|
|
77
|
+
outline-offset: -2px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* ===== 三、UA 装饰归零(只落浮层本体,不碰任何皮肤属性面) ===== */
|
|
81
|
+
:where(.mh-popup[popover], dialog.mh-popup) {
|
|
82
|
+
border: 0;
|
|
83
|
+
padding: 0;
|
|
84
|
+
background: transparent;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* 收起态派生(本层唯一一条非 `:where()` 的状态规则,理由在特异性):
|
|
88
|
+
原生 popover / dialog 的收起靠 UA 的 `display: none`,而皮肤自带 display 的会以作者源压过 UA
|
|
89
|
+
—— 提示皮肤的 inline-block 就让收起的面板在流内显形(实测踩坑)。
|
|
90
|
+
故按「收起的浮层就是 display: none」重新钉一次:`:is()` 取最具体分支,特异性 0-3-0 足以压过任何
|
|
91
|
+
皮肤类,且只碰 display 一项;组件路径(data-state)由组件卸载,不经此条。 */
|
|
92
|
+
:is(.mh-popup[popover]:not(:popover-open), dialog.mh-popup:not([open])) {
|
|
93
|
+
display: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* ===== 四、零 JS 锚定(CSS Anchor Positioning) ===== */
|
|
97
|
+
/* 定位档:声明「面板落在锚点的哪一侧」+ 与锚点的呼吸位(4px)。
|
|
98
|
+
皮肤或消费方要改间距/换侧,用自己的 margin / position-area 覆盖即可 —— 本层恒 0 特异性。
|
|
99
|
+
锚点 = `popovertarget` 的调用者(隐式锚,`position-anchor: auto` 是初始值,无需声明)。 */
|
|
100
|
+
:where(.mh-popup[data-side='bottom']) {
|
|
101
|
+
position-area: bottom;
|
|
102
|
+
margin-block-start: var(--ui-space-1);
|
|
103
|
+
}
|
|
104
|
+
:where(.mh-popup[data-side='top']) {
|
|
105
|
+
position-area: top;
|
|
106
|
+
margin-block-end: var(--ui-space-1);
|
|
107
|
+
}
|
|
108
|
+
:where(.mh-popup[data-side='left']) {
|
|
109
|
+
position-area: left;
|
|
110
|
+
margin-inline-end: var(--ui-space-1);
|
|
111
|
+
}
|
|
112
|
+
:where(.mh-popup[data-side='right']) {
|
|
113
|
+
position-area: right;
|
|
114
|
+
margin-inline-start: var(--ui-space-1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* 溢出自动翻面:贴视口边时按块轴 / 行内轴翻到对侧,零 JS 免裁切 */
|
|
118
|
+
:where(.mh-popup[data-side]) {
|
|
119
|
+
position-try-fallbacks: flip-block, flip-inline;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* 两侧对齐档(与 reka 同名的 data-align):top / bottom 沿行内轴、left / right 沿块轴;
|
|
123
|
+
不写 data-align(或写 center)= 面板中线对齐锚点(position-area 的默认行为,实测中线偏差 0)。
|
|
124
|
+
**钉边必须用 anchor() 而不是 justify-self / align-self**(实测踩坑):
|
|
125
|
+
单关键词的 position-area(如 `bottom`)在另一条轴上是铺满**包含块**的(此处即视口)——
|
|
126
|
+
于是 `justify-self: start` 会把面板贴到视口左边(实测偏了 409px),而不是锚点左边。 */
|
|
127
|
+
:where(.mh-popup[data-side='top'][data-align='start'],
|
|
128
|
+
.mh-popup[data-side='bottom'][data-align='start']) {
|
|
129
|
+
left: anchor(left);
|
|
130
|
+
right: auto;
|
|
131
|
+
}
|
|
132
|
+
:where(.mh-popup[data-side='top'][data-align='end'],
|
|
133
|
+
.mh-popup[data-side='bottom'][data-align='end']) {
|
|
134
|
+
left: auto;
|
|
135
|
+
right: anchor(right);
|
|
136
|
+
}
|
|
137
|
+
:where(.mh-popup[data-side='left'][data-align='start'],
|
|
138
|
+
.mh-popup[data-side='right'][data-align='start']) {
|
|
139
|
+
top: anchor(top);
|
|
140
|
+
bottom: auto;
|
|
141
|
+
}
|
|
142
|
+
:where(.mh-popup[data-side='left'][data-align='end'],
|
|
143
|
+
.mh-popup[data-side='right'][data-align='end']) {
|
|
144
|
+
top: auto;
|
|
145
|
+
bottom: anchor(bottom);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* 显式锚档(隐式锚够不着时用:浮层由 JS `showPopover()` 打开、触发器不是 `popovertarget` 元素等):
|
|
149
|
+
锚点元素挂 `.mh-popup-anchor` 声明锚点名、浮层加 `.mh-popup--anchored` 接入;
|
|
150
|
+
同页多实例用 `.mh-popup-host`(两者的共同祖先)把同名锚收敛到子树(`anchor-scope`),
|
|
151
|
+
否则固定锚点名在整页只有最后一个声明者生效。 */
|
|
152
|
+
.mh-popup-anchor {
|
|
153
|
+
anchor-name: --mh-popup-anchor;
|
|
154
|
+
}
|
|
155
|
+
.mh-popup-host {
|
|
156
|
+
anchor-scope: --mh-popup-anchor;
|
|
157
|
+
}
|
|
158
|
+
.mh-popup--anchored {
|
|
159
|
+
position-anchor: --mh-popup-anchor;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ===== 五、展开态派生(箭头转向:字形由 @manohub/icon 给,本层只转向) =====
|
|
163
|
+
* 前三条是**后代**关系(箭头在触发器子树里);后两条是**兄弟**关系 ——
|
|
164
|
+
* 组合件把箭头挂到触发器的同级附加位槽里(本仓的「触发器形态」:`Select` 的箭头在表壳的
|
|
165
|
+
* `.mh-input__suffix` 里,与 `[popovertarget]` 那个控件是兄弟),后代组合器一条都命不中(实测),
|
|
166
|
+
* 故补 `~ *` 一档:同宿主内、触发器**之后**的任一兄弟(及其子树)里的箭头跟着转向。 */
|
|
167
|
+
:where(.mh-popup-host:has(.mh-popup:popover-open)) [popovertarget] .mh-popup-caret,
|
|
168
|
+
:where(.mh-popup-host:has(dialog.mh-popup[open])) [popovertarget] .mh-popup-caret,
|
|
169
|
+
:where(.mh-popup-trigger[aria-expanded='true']) .mh-popup-caret,
|
|
170
|
+
:where(.mh-popup-host:has(.mh-popup:popover-open)) [popovertarget] ~ * .mh-popup-caret,
|
|
171
|
+
:where(.mh-popup-host:has(dialog.mh-popup[open])) [popovertarget] ~ * .mh-popup-caret {
|
|
172
|
+
transform: rotate(180deg);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ===== 六、hover 档(非交互提示:移入 / 聚焦即显形,移开即消失) =====
|
|
176
|
+
* 为何需要单独一档:原生 popover 的开合只有两个入口 —— JS `showPopover()` 与 `popovertarget`(点击),
|
|
177
|
+
* **CSS 开合不了 popover**;原生给 hover 留的口子(interest invoker)尚未落地。
|
|
178
|
+
* 故 hover 档退回普通定位元素,**不进 top layer**,代价三条,用前先认:
|
|
179
|
+
* ① 会被祖先 overflow 裁切(popover 档不会);② 层级要自带一层 z-index;③ 无 light dismiss / Esc
|
|
180
|
+
* (移开即消失,本就不需要)。换来的是提示语义正确:不吃点击、不抢焦点。
|
|
181
|
+
* 锚点必须显式声明(hover 没有隐式锚):触发器挂 `.mh-popup-anchor`、面板挂 `.mh-popup--anchored`、
|
|
182
|
+
* 两者共同祖先挂 `.mh-popup-host`(宿主 `:hover` / `:focus-within` 即显形)。`:hover` 按 DOM 祖先传播,
|
|
183
|
+
* 故指针从触发器移到面板上不会闪断。延迟与淡入属显示层 / 组件层,本层不管。
|
|
184
|
+
* 特异性说明:`display` 必须压过皮肤(提示皮肤自带 inline-block),故这两条不走 `:where()`。 */
|
|
185
|
+
.mh-popup.mh-popup--hover {
|
|
186
|
+
position: fixed;
|
|
187
|
+
z-index: 1;
|
|
188
|
+
display: none;
|
|
189
|
+
}
|
|
190
|
+
.mh-popup-host:hover .mh-popup--hover,
|
|
191
|
+
.mh-popup-host:focus-within .mh-popup--hover {
|
|
192
|
+
display: block;
|
|
193
|
+
}
|
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 操作层 · 面板切换骨架(把「一组互斥选项 + 按顺序排列的面板」接起来;只给骨架、不给面)。
|
|
3
|
-
*
|
|
4
|
-
* 出处:`@aihub/theme` 的 `playground/components/tabset.css`(本件当时叫 `Tabset`,0.7.1 起改名 `Tabs`)。
|
|
5
|
-
* 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀。
|
|
6
|
-
*
|
|
7
|
-
* 本层只做三件事 ——
|
|
8
|
-
* ① 操作根(轨道 → 面板组 的呼吸位);
|
|
9
|
-
* ② 面板组与面板的**弹性链**(供抽屉 / 区域容器里的「填满」用法);
|
|
10
|
-
* ③ 面板的**收起态**(`hidden`)。
|
|
11
|
-
*
|
|
12
|
-
* **显隐只有一条路径:组件路径。** `Tabs` 按受控值给非选中面板下发 `hidden`,
|
|
13
|
-
* 与选择控件形态无关(页签条 / 胶囊 / 分段按钮 / 单选卡片都一样)。本层因此:
|
|
14
|
-
* · 收起态写在 `.mh-tabs-panel[hidden]` 上(UA 的 `[hidden]` 是**元素级**规则,
|
|
15
|
-
* 作者源里任何自带 `display` 的类都能压过它,故这里显式落下一次);
|
|
16
|
-
* · **显形态一条规则都不写** —— 面板显形就是它自己的 `display`(块 / 弹性 / 网格归消费方与皮肤)。
|
|
17
|
-
*
|
|
18
|
-
* ⚠️ 历史缺陷一(0.7.0 及以前):当时只有「零 JS 档位表」、没有上面那条收起规则 ⇒ 面板被基线按住,
|
|
19
|
-
* 而档位表在 `TabBar` 下恒不命中 ⇒ 三块面板全不显示(`apps/mcp` 配置抽屉实测踩到)。
|
|
20
|
-
* ⚠️ 历史缺陷二(0.7.1 一度这么修、已改回):组件路径的显形**不能**写成
|
|
21
|
-
* `.mh-tabs-panel:not([hidden]) { display: block }` —— 它把面板的 `display` 钉死成 `block`,
|
|
22
|
-
* 连带顶掉消费方/皮肤给面板的布局(面板里是弹性列时整条高度链当场断掉)。
|
|
23
|
-
* ⚠️ 已退役(2026-09-24 拍板删除):**零 JS 路径(原生 radio ↔ 档位表)整段移除**。原写法
|
|
24
|
-
* `.mh-tabs:has(input:nth-of-type(n):checked) .mh-tabs-panels > :nth-child(n)` 逐档一条写不出通式,
|
|
25
|
-
* 且同时受三条硬限制:① 上限 8 档;② 开关必须与面板**同序**,且按「同一父级里第 n 个 input」计数;
|
|
26
|
-
* ③ 面板必须是 `.mh-tabs-panels` 的**直接子级**。局限远大于它省下的那点 JS —— 取消。
|
|
27
|
-
* (`TabBar` / `Capsule` 各自面向**静态页**的原生 `:checked` 选中态与本文件无关,仍然有效。)
|
|
28
|
-
*
|
|
29
|
-
* **与皮肤零互指**:本层不认任何皮肤类名(退役后也不再认识 `input`)。
|
|
30
|
-
*
|
|
31
|
-
* 结构契约(轨道项与面板组顺序**一一对应**;面板壳由 `Tabs` 出,消费方不必手写):
|
|
32
|
-
* <div class="mh-tabs">
|
|
33
|
-
* <div class="[皮肤:轨道 / 选择控件]">…</div>
|
|
34
|
-
* <div class="mh-tabs-panels">
|
|
35
|
-
* <section class="mh-tabs-panel [皮肤类]" hidden>…</section>
|
|
36
|
-
* </div>
|
|
37
|
-
* </div>
|
|
38
|
-
*
|
|
39
|
-
* 禁写(与折叠 / 浮层同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 —— 写了就顶掉皮肤族属性面。
|
|
40
|
-
* 面板的面与几何由皮肤族给(卡片一类);本层只写「收起态」「弹性链」与根上的呼吸位。
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/* ===== 一、操作根:选择控件在上、面板在下 =====
|
|
44
|
-
呼吸位(`gap`)随 `size` 档走:档位由组件在根上出 `mh-tabs--sm` / `mh-tabs--lg`
|
|
45
|
-
(`md` 缺省不发类,与 `TabBar` 同口径)。skin 只决定控件长什么样,控件与面板之间的
|
|
46
|
-
间距归骨架 —— 故本档**与皮肤无关**,传了 `selector` 自定义控件时同样生效。 */
|
|
47
|
-
.mh-tabs {
|
|
48
|
-
display: flex;
|
|
49
|
-
flex-direction: column;
|
|
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 */
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/* ===== 二、弹性链:面板组 → 面板 =====
|
|
60
|
-
只声明「吃满面板组的剩余高度」,**不动面板的 `display`**。
|
|
61
|
-
用途:抽屉 / 面板级容器里要「页签条固定 + 面板填满 + 面板内部自己滚」时,消费方在自己加到
|
|
62
|
-
根上的类里写 `height: 100%` 即启用 —— 本层不设任何绝对高度,高度归属始终在消费方容器手里。
|
|
63
|
-
根高 auto(桌面普通用法)时这些声明不产生高度变化(无剩余空间可分),与块级布局等价。 */
|
|
64
|
-
.mh-tabs-panels {
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
flex: 1 1 auto;
|
|
68
|
-
min-height: 0;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.mh-tabs-panel {
|
|
72
|
-
flex: 1 1 auto;
|
|
73
|
-
min-height: 0;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* ===== 三、收起态:本层唯一一条显隐规则 =====
|
|
77
|
-
非选中面板一律带 `hidden`(由 `Tabs` 下发,与控件形态无关)。显式落一次「收起 = 不显示」——
|
|
78
|
-
不依赖 UA 那条 `[hidden]`(它是元素级规则,消费方/皮肤里任何自带 `display` 的类都能压过它)。
|
|
79
|
-
**不写显形规则**:面板显形就是它自己的 `display`(见文件头「历史缺陷二」)。 */
|
|
80
|
-
.mh-tabs-panel[hidden] {
|
|
81
|
-
display: none;
|
|
82
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 操作层 · 面板切换骨架(把「一组互斥选项 + 按顺序排列的面板」接起来;只给骨架、不给面)。
|
|
3
|
+
*
|
|
4
|
+
* 出处:`@aihub/theme` 的 `playground/components/tabset.css`(本件当时叫 `Tabset`,0.7.1 起改名 `Tabs`)。
|
|
5
|
+
* 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀。
|
|
6
|
+
*
|
|
7
|
+
* 本层只做三件事 ——
|
|
8
|
+
* ① 操作根(轨道 → 面板组 的呼吸位);
|
|
9
|
+
* ② 面板组与面板的**弹性链**(供抽屉 / 区域容器里的「填满」用法);
|
|
10
|
+
* ③ 面板的**收起态**(`hidden`)。
|
|
11
|
+
*
|
|
12
|
+
* **显隐只有一条路径:组件路径。** `Tabs` 按受控值给非选中面板下发 `hidden`,
|
|
13
|
+
* 与选择控件形态无关(页签条 / 胶囊 / 分段按钮 / 单选卡片都一样)。本层因此:
|
|
14
|
+
* · 收起态写在 `.mh-tabs-panel[hidden]` 上(UA 的 `[hidden]` 是**元素级**规则,
|
|
15
|
+
* 作者源里任何自带 `display` 的类都能压过它,故这里显式落下一次);
|
|
16
|
+
* · **显形态一条规则都不写** —— 面板显形就是它自己的 `display`(块 / 弹性 / 网格归消费方与皮肤)。
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ 历史缺陷一(0.7.0 及以前):当时只有「零 JS 档位表」、没有上面那条收起规则 ⇒ 面板被基线按住,
|
|
19
|
+
* 而档位表在 `TabBar` 下恒不命中 ⇒ 三块面板全不显示(`apps/mcp` 配置抽屉实测踩到)。
|
|
20
|
+
* ⚠️ 历史缺陷二(0.7.1 一度这么修、已改回):组件路径的显形**不能**写成
|
|
21
|
+
* `.mh-tabs-panel:not([hidden]) { display: block }` —— 它把面板的 `display` 钉死成 `block`,
|
|
22
|
+
* 连带顶掉消费方/皮肤给面板的布局(面板里是弹性列时整条高度链当场断掉)。
|
|
23
|
+
* ⚠️ 已退役(2026-09-24 拍板删除):**零 JS 路径(原生 radio ↔ 档位表)整段移除**。原写法
|
|
24
|
+
* `.mh-tabs:has(input:nth-of-type(n):checked) .mh-tabs-panels > :nth-child(n)` 逐档一条写不出通式,
|
|
25
|
+
* 且同时受三条硬限制:① 上限 8 档;② 开关必须与面板**同序**,且按「同一父级里第 n 个 input」计数;
|
|
26
|
+
* ③ 面板必须是 `.mh-tabs-panels` 的**直接子级**。局限远大于它省下的那点 JS —— 取消。
|
|
27
|
+
* (`TabBar` / `Capsule` 各自面向**静态页**的原生 `:checked` 选中态与本文件无关,仍然有效。)
|
|
28
|
+
*
|
|
29
|
+
* **与皮肤零互指**:本层不认任何皮肤类名(退役后也不再认识 `input`)。
|
|
30
|
+
*
|
|
31
|
+
* 结构契约(轨道项与面板组顺序**一一对应**;面板壳由 `Tabs` 出,消费方不必手写):
|
|
32
|
+
* <div class="mh-tabs">
|
|
33
|
+
* <div class="[皮肤:轨道 / 选择控件]">…</div>
|
|
34
|
+
* <div class="mh-tabs-panels">
|
|
35
|
+
* <section class="mh-tabs-panel [皮肤类]" hidden>…</section>
|
|
36
|
+
* </div>
|
|
37
|
+
* </div>
|
|
38
|
+
*
|
|
39
|
+
* 禁写(与折叠 / 浮层同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 —— 写了就顶掉皮肤族属性面。
|
|
40
|
+
* 面板的面与几何由皮肤族给(卡片一类);本层只写「收起态」「弹性链」与根上的呼吸位。
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/* ===== 一、操作根:选择控件在上、面板在下 =====
|
|
44
|
+
呼吸位(`gap`)随 `size` 档走:档位由组件在根上出 `mh-tabs--sm` / `mh-tabs--lg`
|
|
45
|
+
(`md` 缺省不发类,与 `TabBar` 同口径)。skin 只决定控件长什么样,控件与面板之间的
|
|
46
|
+
间距归骨架 —— 故本档**与皮肤无关**,传了 `selector` 自定义控件时同样生效。 */
|
|
47
|
+
.mh-tabs {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
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 */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ===== 二、弹性链:面板组 → 面板 =====
|
|
60
|
+
只声明「吃满面板组的剩余高度」,**不动面板的 `display`**。
|
|
61
|
+
用途:抽屉 / 面板级容器里要「页签条固定 + 面板填满 + 面板内部自己滚」时,消费方在自己加到
|
|
62
|
+
根上的类里写 `height: 100%` 即启用 —— 本层不设任何绝对高度,高度归属始终在消费方容器手里。
|
|
63
|
+
根高 auto(桌面普通用法)时这些声明不产生高度变化(无剩余空间可分),与块级布局等价。 */
|
|
64
|
+
.mh-tabs-panels {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
flex: 1 1 auto;
|
|
68
|
+
min-height: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.mh-tabs-panel {
|
|
72
|
+
flex: 1 1 auto;
|
|
73
|
+
min-height: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ===== 三、收起态:本层唯一一条显隐规则 =====
|
|
77
|
+
非选中面板一律带 `hidden`(由 `Tabs` 下发,与控件形态无关)。显式落一次「收起 = 不显示」——
|
|
78
|
+
不依赖 UA 那条 `[hidden]`(它是元素级规则,消费方/皮肤里任何自带 `display` 的类都能压过它)。
|
|
79
|
+
**不写显形规则**:面板显形就是它自己的 `display`(见文件头「历史缺陷二」)。 */
|
|
80
|
+
.mh-tabs-panel[hidden] {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|