@xihan-ui/styles 1.0.0-alpha.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/CHANGELOG.md +44 -0
- package/LICENSE +21 -0
- package/README.md +27 -0
- package/css/accordion.css +108 -0
- package/css/affix.css +27 -0
- package/css/alert.css +108 -0
- package/css/anchor.css +137 -0
- package/css/avatar-group.css +82 -0
- package/css/avatar.css +55 -0
- package/css/back-top.css +61 -0
- package/css/badge.css +50 -0
- package/css/breadcrumb.css +127 -0
- package/css/button-group.css +131 -0
- package/css/button.css +98 -0
- package/css/calendar.css +219 -0
- package/css/card.css +116 -0
- package/css/carousel.css +193 -0
- package/css/cascader.css +397 -0
- package/css/checkbox-group.css +185 -0
- package/css/checkbox.css +91 -0
- package/css/clipboard.css +133 -0
- package/css/code-block.css +81 -0
- package/css/collapsible.css +63 -0
- package/css/color-picker.css +424 -0
- package/css/combobox.css +433 -0
- package/css/composer.css +127 -0
- package/css/context-menu.css +263 -0
- package/css/countdown.css +21 -0
- package/css/date-field.css +200 -0
- package/css/date-picker.css +231 -0
- package/css/descriptions.css +200 -0
- package/css/dialog.css +127 -0
- package/css/drawer.css +372 -0
- package/css/dynamic-input.css +157 -0
- package/css/editable.css +249 -0
- package/css/ellipsis.css +41 -0
- package/css/empty-state.css +78 -0
- package/css/field.css +65 -0
- package/css/file-upload.css +298 -0
- package/css/flex.css +95 -0
- package/css/float-button.css +121 -0
- package/css/form.css +185 -0
- package/css/gradient-text.css +62 -0
- package/css/grid.css +428 -0
- package/css/highlight.css +21 -0
- package/css/hover-card.css +146 -0
- package/css/icon-wrapper.css +64 -0
- package/css/icon.css +54 -0
- package/css/image.css +45 -0
- package/css/infinite-scroll.css +22 -0
- package/css/layers.css +2 -0
- package/css/layout.css +169 -0
- package/css/list.css +117 -0
- package/css/listbox.css +174 -0
- package/css/loading-bar.css +66 -0
- package/css/log.css +66 -0
- package/css/marquee.css +182 -0
- package/css/mention.css +222 -0
- package/css/menu.css +144 -0
- package/css/menubar.css +271 -0
- package/css/motion.css +58 -0
- package/css/navigation-menu.css +270 -0
- package/css/number-animation.css +32 -0
- package/css/number-field.css +219 -0
- package/css/page-header.css +85 -0
- package/css/pagination.css +148 -0
- package/css/pin-input.css +157 -0
- package/css/popconfirm.css +150 -0
- package/css/popover.css +150 -0
- package/css/popselect.css +207 -0
- package/css/progress.css +37 -0
- package/css/qr-code.css +50 -0
- package/css/radio-group.css +101 -0
- package/css/rating.css +141 -0
- package/css/reset.css +22 -0
- package/css/result.css +104 -0
- package/css/scroll-area.css +176 -0
- package/css/select.css +264 -0
- package/css/separator.css +17 -0
- package/css/skeleton.css +78 -0
- package/css/slider.css +197 -0
- package/css/spinner.css +74 -0
- package/css/splitter.css +127 -0
- package/css/statistic.css +67 -0
- package/css/steps.css +252 -0
- package/css/switch.css +61 -0
- package/css/table.css +404 -0
- package/css/tabs.css +157 -0
- package/css/tags-input.css +360 -0
- package/css/text-field.css +195 -0
- package/css/thread.css +107 -0
- package/css/time-field.css +200 -0
- package/css/time-picker.css +347 -0
- package/css/time.css +20 -0
- package/css/timeline.css +284 -0
- package/css/toast.css +195 -0
- package/css/toaster.css +69 -0
- package/css/toggle-group.css +160 -0
- package/css/toggle.css +103 -0
- package/css/tone.css +85 -0
- package/css/toolbar.css +114 -0
- package/css/tooltip.css +109 -0
- package/css/tour.css +305 -0
- package/css/transfer.css +318 -0
- package/css/tree-select.css +441 -0
- package/css/tree.css +204 -0
- package/css/typography.css +151 -0
- package/css/undefined.css +38 -0
- package/css/virtualizer.css +104 -0
- package/css/visually-hidden.css +13 -0
- package/css/watermark.css +48 -0
- package/index.css +113 -0
- package/index.unlayered.css +16164 -0
- package/package.json +163 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @xihan-ui/styles
|
|
2
|
+
|
|
3
|
+
## 1.0.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bc65cb7: 首个公开版本:框架无关的 UI 基座。
|
|
8
|
+
|
|
9
|
+
自研薄 FSM 内核 + headless(anatomy / machine / connect)+ 设计令牌与主题运行时 + 样式层,
|
|
10
|
+
102 个组件在 Vue 与 Web Components 两套适配器上共用同一份内核,跨适配器一致性套件与
|
|
11
|
+
真实 Chromium 里的无障碍扫描、浮层定位契约全绿。
|
|
12
|
+
|
|
13
|
+
浮层定位、虚拟滚动、Web Components 响应式基类、代码着色、流式 Markdown 均为自研,
|
|
14
|
+
运行时不带第三方依赖。
|
|
15
|
+
|
|
16
|
+
- 84b1aa3: 新增 Icon 原语,`@xihan-ui/icons` 整包重写为首方图标集。
|
|
17
|
+
|
|
18
|
+
旧的 `@xihan-ui/icons` 是 27 个第三方图标集的聚合(约四万个图标),已整体移除并在
|
|
19
|
+
npm 上弃用。新包只收自研图标,第一批 29 个覆盖组件库自用的全部语义,24×24 单色
|
|
20
|
+
描边、`stroke-width` 2。
|
|
21
|
+
|
|
22
|
+
用法:
|
|
23
|
+
|
|
24
|
+
- `@xihan-ui/kernel` 导出 `IconRecord` / `IconNode` / `IconTag` 三个类型
|
|
25
|
+
- `@xihan-ui/headless` 导出 `connectIcon` / `iconAnatomy` / `iconMeta` / `iconKeyboard`
|
|
26
|
+
- `@xihan-ui/vue` 导出 `XhIcon`,`@xihan-ui/web-components` 注册 `<xh-icon>`
|
|
27
|
+
- `@xihan-ui/styles` 新增 `icon.css`,`data-size` 与 `data-weight` 各三档
|
|
28
|
+
|
|
29
|
+
图标记录是结构化节点数组而不是 SVG 字符串,渲染端逐节点建元素,运行期不经 HTML
|
|
30
|
+
解析器。图标数据传的是记录本身而不是名字:按名字查表要把全表静态引进来,摇树会
|
|
31
|
+
整个失效。
|
|
32
|
+
|
|
33
|
+
WC 侧要在 `<svg data-xh-part="root">` 里留一个空的 `<g data-xh-part="glyph"></g>`
|
|
34
|
+
作为授权点,元素只在它内部铺图元;不留这个空壳就一个节点都不动,手写内联 SVG 与
|
|
35
|
+
`<use>` 引用两种写法因此都还能用。`icon` 是对象,只能走 property 传,属性里写不出来。
|
|
36
|
+
|
|
37
|
+
可及名字两态互斥:`label` 给了非空白文本就输出 `role="img"` 与 `aria-label`,否则
|
|
38
|
+
输出 `aria-hidden="true"`。只有图标的按钮请把名字写在按钮上而不是图标上,两处都写
|
|
39
|
+
读屏会念两遍。
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [bc65cb7]
|
|
44
|
+
- @xihan-ui/tokens@1.0.0-alpha.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-Present XiHanFun and contributors.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @xihan-ui/styles
|
|
2
|
+
|
|
3
|
+
默认皮肤:108 份纯 CSS,零 JS。只按 `[data-scope][data-part]` 与 `data-*` 选中,不匹配标签名也不匹配 class——所以整套换掉它不影响任何行为。
|
|
4
|
+
|
|
5
|
+
**谁会装它**:不想自己写样式的人装它。要做自己的设计语言,就不装,照解剖文档写一套自己的。
|
|
6
|
+
|
|
7
|
+
## 用法
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
/* 全量 */
|
|
11
|
+
import '@xihan-ui/styles'
|
|
12
|
+
|
|
13
|
+
/* 或按需:令牌与层序先行,tone 决定语气轴,缺了它 tone 会静默回落品牌色 */
|
|
14
|
+
import '@xihan-ui/styles/layers.css'
|
|
15
|
+
import '@xihan-ui/styles/tone.css'
|
|
16
|
+
import '@xihan-ui/styles/button.css'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 装
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @xihan-ui/styles
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
完整文档见 [https://ui.docs.xihanfun.com](https://ui.docs.xihanfun.com)。这个包属于 `design/` 组,组的含义见仓库里的 `ui/packages/README.md`。
|
|
26
|
+
|
|
27
|
+
许可:MIT
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
[data-scope='accordion'][data-part='root'] {
|
|
3
|
+
/* 尺寸档只换这四个私有槽,标题栏从 root 继承它们,换档不必给每个部件各写一条选择器 */
|
|
4
|
+
--xh-_accordion-trigger-h: var(--xh-control-h-md);
|
|
5
|
+
--xh-_accordion-trigger-px: var(--xh-control-px-md);
|
|
6
|
+
--xh-_accordion-trigger-gap: var(--xh-control-gap-md);
|
|
7
|
+
--xh-_accordion-trigger-font-size: var(--xh-text-label-size);
|
|
8
|
+
|
|
9
|
+
/* 语气落在展开着的标题上,指示器写在标题里、跟着继承这个色,不另立规则。
|
|
10
|
+
没写 data-tone 时 --xh-_tone-fg 没被声明,退回原来的前景色。
|
|
11
|
+
聚焦环不在其列,它恒是 --xh-ring-focus */
|
|
12
|
+
--xh-_accordion-open-fg: var(--xh-_tone-fg, var(--xh-fg-default));
|
|
13
|
+
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
inline-size: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-scope='accordion'][data-part='root'][data-orientation='horizontal'] {
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* —— 尺寸 —— */
|
|
24
|
+
/* 缺省档写在上面的基础规则里 */
|
|
25
|
+
[data-scope='accordion'][data-part='root'][data-size='sm'] {
|
|
26
|
+
--xh-_accordion-trigger-h: var(--xh-control-h-sm);
|
|
27
|
+
--xh-_accordion-trigger-px: var(--xh-control-px-sm);
|
|
28
|
+
--xh-_accordion-trigger-gap: var(--xh-control-gap-sm);
|
|
29
|
+
--xh-_accordion-trigger-font-size: var(--xh-font-size-sm);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[data-scope='accordion'][data-part='root'][data-size='lg'] {
|
|
33
|
+
--xh-_accordion-trigger-h: var(--xh-control-h-lg);
|
|
34
|
+
--xh-_accordion-trigger-px: var(--xh-control-px-lg);
|
|
35
|
+
--xh-_accordion-trigger-gap: var(--xh-control-gap-lg);
|
|
36
|
+
--xh-_accordion-trigger-font-size: var(--xh-font-size-lg);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-scope='accordion'][data-part='item'] {
|
|
40
|
+
border-block-end: 1px solid var(--xh-accordion-item-border, var(--xh-border-default));
|
|
41
|
+
min-inline-size: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
[data-scope='accordion'][data-part='header'] {
|
|
45
|
+
margin: 0;
|
|
46
|
+
font: inherit;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
[data-scope='accordion'][data-part='trigger'] {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: space-between;
|
|
53
|
+
inline-size: 100%;
|
|
54
|
+
gap: var(--xh-accordion-trigger-gap, var(--xh-_accordion-trigger-gap));
|
|
55
|
+
block-size: var(--xh-accordion-trigger-h, var(--xh-_accordion-trigger-h));
|
|
56
|
+
padding-inline: var(--xh-accordion-trigger-px, var(--xh-_accordion-trigger-px));
|
|
57
|
+
border: 0;
|
|
58
|
+
border-radius: var(--xh-accordion-trigger-radius, var(--xh-shape-control));
|
|
59
|
+
background: var(--xh-accordion-trigger-bg, transparent);
|
|
60
|
+
color: var(--xh-accordion-trigger-fg, var(--xh-fg-default));
|
|
61
|
+
font-size: var(--xh-accordion-trigger-font-size, var(--xh-_accordion-trigger-font-size));
|
|
62
|
+
font-weight: var(--xh-accordion-trigger-font-weight, var(--xh-text-label-weight));
|
|
63
|
+
line-height: var(--xh-leading-none);
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[data-scope='accordion'][data-part='trigger']:hover {
|
|
68
|
+
background: var(--xh-accordion-trigger-bg-hover, var(--xh-bg-subtle));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
[data-scope='accordion'][data-part='trigger']:focus-visible {
|
|
72
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
73
|
+
outline-offset: var(--xh-ring-offset);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[data-scope='accordion'][data-part='trigger'][data-state='open'] {
|
|
77
|
+
color: var(--xh-accordion-trigger-fg, var(--xh-_accordion-open-fg));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* 禁用条目走 aria-disabled,仍留在 Tab 序里,只是不可操作 */
|
|
81
|
+
[data-scope='accordion'][data-part='trigger'][data-disabled] {
|
|
82
|
+
cursor: not-allowed;
|
|
83
|
+
opacity: var(--xh-state-disabled-opacity);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-scope='accordion'][data-part='indicator'] {
|
|
87
|
+
display: inline-flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
flex: none;
|
|
91
|
+
line-height: var(--xh-leading-none);
|
|
92
|
+
transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
[data-scope='accordion'][data-part='indicator']::before {
|
|
96
|
+
content: '⌄';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[data-scope='accordion'][data-part='indicator'][data-state='open'] {
|
|
100
|
+
rotate: 180deg;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
[data-scope='accordion'][data-part='content'] {
|
|
104
|
+
padding-block: var(--xh-accordion-content-py, var(--xh-stack-gap-md));
|
|
105
|
+
padding-inline: var(--xh-accordion-content-px, var(--xh-control-px-md));
|
|
106
|
+
color: var(--xh-accordion-content-fg, var(--xh-fg-default));
|
|
107
|
+
}
|
|
108
|
+
}
|
package/css/affix.css
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 占位盒就是 content 在常规流里占的那块地方。
|
|
3
|
+
这里不声明 display,也不写高度:吸住时冻结的高度由连接层量好写进内联样式(它量得到,样式表量不到),
|
|
4
|
+
没吸住时高度就该跟着内容走。不给 display,UA 的 [hidden]{display:none} 也仍然压得住 */
|
|
5
|
+
[data-scope='affix'][data-part='root'] {
|
|
6
|
+
/* 脱流后 content 不再撑开占位盒,宽度改从父级取 */
|
|
7
|
+
inline-size: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* 没吸住时是常规流里普通的一块,不做任何定位 */
|
|
11
|
+
[data-scope='affix'][data-part='content'] {
|
|
12
|
+
inline-size: 100%;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* 吸住:脱离常规流钉在视口上。
|
|
17
|
+
* 四个落位数(top / bottom / left / width)由连接层写成内联样式——它们是照占位盒的矩形实测出来的
|
|
18
|
+
* 物理量,换成逻辑属性会在 RTL 下贴反。这里只管「用哪种定位、压在第几层」。
|
|
19
|
+
* 另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
|
|
20
|
+
* transform / filter / backdrop-filter / contain,包含块就被抢走,钉住的内容立刻贴错位置——
|
|
21
|
+
* 所以别往覆盖钩子里加这几个属性。
|
|
22
|
+
*/
|
|
23
|
+
[data-scope='affix'][data-part='content'][data-affixed] {
|
|
24
|
+
position: fixed;
|
|
25
|
+
z-index: var(--xh-affix-layer, var(--xh-layer-sticky));
|
|
26
|
+
}
|
|
27
|
+
}
|
package/css/alert.css
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
[data-scope='alert'][data-part='root'] {
|
|
3
|
+
/* 强调色随语气走,底色/描边/图标色都由它推导出来,换语气不必逐条属性各写一遍。
|
|
4
|
+
没写 data-tone 时 --xh-_tone 没被声明,退回原来的 info 蓝 */
|
|
5
|
+
--xh-_alert-accent: var(--xh-_tone-soft, var(--xh-color-info-500));
|
|
6
|
+
/* 底色与描边由语气色兑进当前表面色得到:表面色本身跟着深浅模式翻,
|
|
7
|
+
兑出来的淡底也就跟着翻,不必为深色再写一套选择器 */
|
|
8
|
+
--xh-_alert-tint: color-mix(in oklab, var(--xh-_alert-accent) 12%, var(--xh-bg-surface));
|
|
9
|
+
--xh-_alert-edge: color-mix(in oklab, var(--xh-_alert-accent) 32%, var(--xh-bg-surface));
|
|
10
|
+
|
|
11
|
+
display: flex;
|
|
12
|
+
/* 说明用 flex: 1 1 100% 独占一行,容器不换行的话它只会挤在标题旁边 */
|
|
13
|
+
flex-wrap: wrap;
|
|
14
|
+
align-items: flex-start;
|
|
15
|
+
gap: var(--xh-alert-gap, var(--xh-space-3));
|
|
16
|
+
padding-block: var(--xh-alert-py, var(--xh-space-3));
|
|
17
|
+
padding-inline: var(--xh-alert-px, var(--xh-space-4));
|
|
18
|
+
border: var(--xh-stroke-thin) solid var(--xh-alert-border, var(--xh-_alert-edge));
|
|
19
|
+
border-radius: var(--xh-alert-radius, var(--xh-shape-surface));
|
|
20
|
+
background: var(--xh-alert-bg, var(--xh-_alert-tint));
|
|
21
|
+
color: var(--xh-alert-fg, var(--xh-fg-default));
|
|
22
|
+
font-size: var(--xh-alert-font-size, var(--xh-font-size-md));
|
|
23
|
+
line-height: var(--xh-alert-leading, var(--xh-leading-normal));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* 收起态连接层给的是 hidden 属性,而上面声明了 display——
|
|
27
|
+
漏掉这条,关掉的提示还会一直摊在页面上 */
|
|
28
|
+
[data-scope='alert'][data-part='root'][hidden] {
|
|
29
|
+
display: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[data-scope='alert'][data-part='icon'] {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
flex: none;
|
|
37
|
+
/* 与首行文字对齐:图标框高取一行正文的行高 */
|
|
38
|
+
block-size: calc(var(--xh-font-size-md) * var(--xh-leading-normal));
|
|
39
|
+
inline-size: var(--xh-alert-icon-size, var(--xh-control-indicator-size));
|
|
40
|
+
color: var(--xh-alert-icon-fg, var(--xh-_alert-accent));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* 标题与说明摞成一列,占满 root 剩下的横向空间,
|
|
44
|
+
关闭按钮才推得到行尾 */
|
|
45
|
+
[data-scope='alert'][data-part='title'],
|
|
46
|
+
[data-scope='alert'][data-part='description'] {
|
|
47
|
+
margin: 0;
|
|
48
|
+
min-inline-size: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
[data-scope='alert'][data-part='title'] {
|
|
52
|
+
flex: 1 1 auto;
|
|
53
|
+
color: var(--xh-alert-title-fg, var(--xh-fg-default));
|
|
54
|
+
font-size: var(--xh-alert-title-font-size, var(--xh-font-size-md));
|
|
55
|
+
font-weight: var(--xh-alert-title-font-weight, var(--xh-font-weight-semibold));
|
|
56
|
+
line-height: var(--xh-alert-title-leading, var(--xh-leading-tight));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[data-scope='alert'][data-part='description'] {
|
|
60
|
+
flex: 1 1 100%;
|
|
61
|
+
color: var(--xh-alert-description-fg, var(--xh-fg-muted));
|
|
62
|
+
font-size: var(--xh-alert-description-font-size, var(--xh-font-size-sm));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* 没写标题时说明自己占满这一行,否则它会挤在标题旁边 */
|
|
66
|
+
[data-scope='alert'][data-part='title']:empty {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
[data-scope='alert'][data-part='close-trigger'] {
|
|
71
|
+
flex: none;
|
|
72
|
+
/* 前面没有标题时也把叉推到行尾 */
|
|
73
|
+
margin-inline-start: auto;
|
|
74
|
+
display: inline-flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
block-size: var(--xh-alert-close-size, var(--xh-control-h-sm));
|
|
78
|
+
inline-size: var(--xh-alert-close-size, var(--xh-control-h-sm));
|
|
79
|
+
border: 0;
|
|
80
|
+
border-radius: var(--xh-alert-close-radius, var(--xh-shape-control));
|
|
81
|
+
background: transparent;
|
|
82
|
+
color: var(--xh-alert-close-fg, var(--xh-fg-muted));
|
|
83
|
+
/* 按钮不继承字族字号,不接回来的话提示里会突然冒出一段系统 UI 字体 */
|
|
84
|
+
font: inherit;
|
|
85
|
+
line-height: var(--xh-leading-none);
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半 */
|
|
90
|
+
[data-scope='alert'][data-part='close-trigger'][hidden] {
|
|
91
|
+
display: none;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
[data-scope='alert'][data-part='close-trigger']:hover:not(:disabled) {
|
|
95
|
+
background: color-mix(in oklab, var(--xh-_alert-accent) 16%, transparent);
|
|
96
|
+
color: var(--xh-alert-close-fg-hover, var(--xh-fg-default));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[data-scope='alert'][data-part='close-trigger']:disabled {
|
|
100
|
+
color: var(--xh-fg-disabled);
|
|
101
|
+
cursor: not-allowed;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[data-scope='alert'][data-part='close-trigger']:focus-visible {
|
|
105
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
106
|
+
outline-offset: var(--xh-ring-offset);
|
|
107
|
+
}
|
|
108
|
+
}
|
package/css/anchor.css
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 根节点是 nav 地标,不参与排版:整条目录的布局全在 list 上,
|
|
3
|
+
这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
|
|
4
|
+
[data-scope='anchor'][data-part='root'] {
|
|
5
|
+
/* 尺寸档只换这两个私有槽,链接从 root 继承它们,换档不必给每个部件各写一条选择器 */
|
|
6
|
+
--xh-_anchor-font-size: var(--xh-text-label-size);
|
|
7
|
+
--xh-_anchor-link-px: var(--xh-space-3);
|
|
8
|
+
/* 当前那一节的指示条与文字随语气走。没写 data-tone 时这两个槽都没被声明,退回原来的品牌色。
|
|
9
|
+
指示条是装饰性的色条,取柔和档;文字要压在普通背景上读,取语气的文字档。
|
|
10
|
+
聚焦环不在其列,它恒是 --xh-ring-focus */
|
|
11
|
+
--xh-_anchor-accent: var(--xh-_tone-soft, var(--xh-fg-brand));
|
|
12
|
+
--xh-_anchor-accent-text: var(--xh-_tone-fg, var(--xh-fg-brand));
|
|
13
|
+
|
|
14
|
+
color: var(--xh-anchor-fg, var(--xh-fg-muted));
|
|
15
|
+
font-size: var(--xh-anchor-font-size, var(--xh-_anchor-font-size));
|
|
16
|
+
line-height: var(--xh-anchor-leading, var(--xh-leading-normal));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* —— 尺寸 —— */
|
|
20
|
+
/* 缺省档写在上面的基础规则里;链接的内边距走控件内边距那把尺,缺省的 --xh-space-3 即它的中档 */
|
|
21
|
+
[data-scope='anchor'][data-part='root'][data-size='sm'] {
|
|
22
|
+
--xh-_anchor-font-size: var(--xh-font-size-sm);
|
|
23
|
+
--xh-_anchor-link-px: var(--xh-control-px-sm);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[data-scope='anchor'][data-part='root'][data-size='lg'] {
|
|
27
|
+
--xh-_anchor-font-size: var(--xh-font-size-lg);
|
|
28
|
+
--xh-_anchor-link-px: var(--xh-control-px-lg);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* 指示条的定位参照系(它是 absolute,量出来的偏移就是相对这里的)。
|
|
32
|
+
ul 的项目符号与内外边距是 UA 给的,库里没有全局 preflight,只能在这儿自己抹平 */
|
|
33
|
+
[data-scope='anchor'][data-part='list'] {
|
|
34
|
+
position: relative;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
gap: var(--xh-anchor-gap, var(--xh-space-1));
|
|
38
|
+
margin: 0;
|
|
39
|
+
padding: 0;
|
|
40
|
+
/* 起始缘的那条轨道:指示条就在它上面滑 */
|
|
41
|
+
border-inline-start: var(--xh-stroke-thin) solid var(--xh-anchor-track, var(--xh-border-default));
|
|
42
|
+
list-style: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[data-scope='anchor'][data-part='list'][hidden] {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* 横排:轨道从起始缘挪到底边,条目改成一行 */
|
|
50
|
+
[data-scope='anchor'][data-part='list'][data-orientation='horizontal'] {
|
|
51
|
+
flex-direction: row;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: var(--xh-anchor-gap-horizontal, var(--xh-space-2));
|
|
54
|
+
border-inline-start: 0;
|
|
55
|
+
border-block-end: var(--xh-stroke-thin) solid var(--xh-anchor-track, var(--xh-border-default));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-scope='anchor'][data-part='item'] {
|
|
59
|
+
display: flex;
|
|
60
|
+
/* 库里没有全局 preflight,列表项的外边距在这里自己抹平 */
|
|
61
|
+
margin: 0;
|
|
62
|
+
/* 允许被压缩,链接内部的省略号才有生效的余地 */
|
|
63
|
+
min-inline-size: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[data-scope='anchor'][data-part='item'][hidden] {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
[data-scope='anchor'][data-part='link'] {
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
/* 一节的标题可能很长,压不住会把整列撑开 */
|
|
74
|
+
max-inline-size: var(--xh-anchor-link-max-w, 14rem);
|
|
75
|
+
padding-block: var(--xh-anchor-link-py, var(--xh-space-1));
|
|
76
|
+
padding-inline: var(--xh-anchor-link-px, var(--xh-_anchor-link-px));
|
|
77
|
+
border-radius: var(--xh-anchor-link-radius, var(--xh-shape-control));
|
|
78
|
+
color: inherit;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
text-decoration: none;
|
|
81
|
+
text-overflow: ellipsis;
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
transition: color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-scope='anchor'][data-part='link'][hidden] {
|
|
87
|
+
display: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[data-scope='anchor'][data-part='link']:hover {
|
|
91
|
+
color: var(--xh-anchor-link-fg-hover, var(--xh-fg-default));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
[data-scope='anchor'][data-part='link']:focus-visible {
|
|
95
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
96
|
+
outline-offset: var(--xh-ring-offset);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* 当前那一节:颜色与字重都跟着变,不只靠指示条——
|
|
100
|
+
指示条是可选部件,作者不渲染它时"当前在哪"仍然要看得出来 */
|
|
101
|
+
[data-scope='anchor'][data-part='link'][data-active] {
|
|
102
|
+
color: var(--xh-anchor-link-fg-active, var(--xh-_anchor-accent-text));
|
|
103
|
+
font-weight: var(--xh-anchor-link-font-weight-active, var(--xh-font-weight-medium));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* 主轴上的位置与长度由连接层写成内联样式(它量得到,样式表量不到);
|
|
107
|
+
这里只管交叉轴的贴边与粗细,以及长什么样 */
|
|
108
|
+
[data-scope='anchor'][data-part='indicator'] {
|
|
109
|
+
position: absolute;
|
|
110
|
+
display: block;
|
|
111
|
+
/* 指示条也是列表项,宿主给 li 的外边距会把绝对定位的它推离条目 */
|
|
112
|
+
margin: 0;
|
|
113
|
+
inset-inline-start: calc(var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick)) * -1);
|
|
114
|
+
inline-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
|
|
115
|
+
border-radius: var(--xh-anchor-indicator-radius, var(--xh-radius-full));
|
|
116
|
+
background: var(--xh-anchor-indicator-color, var(--xh-_anchor-accent));
|
|
117
|
+
transition:
|
|
118
|
+
inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
|
|
119
|
+
block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* display 会盖掉 hidden 属性的 UA 规则,无激活项时显式让位 */
|
|
123
|
+
[data-scope='anchor'][data-part='indicator'][hidden] {
|
|
124
|
+
display: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* 横排:指示条改躺在底边的轨道上,交叉轴换成块轴 */
|
|
128
|
+
[data-scope='anchor'][data-part='indicator'][data-orientation='horizontal'] {
|
|
129
|
+
inset-inline-start: auto;
|
|
130
|
+
inset-block-end: calc(var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick)) * -1);
|
|
131
|
+
inline-size: auto;
|
|
132
|
+
block-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
|
|
133
|
+
transition:
|
|
134
|
+
inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
|
|
135
|
+
inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 一排叠放的头像:后一枚压在前一枚上。
|
|
3
|
+
组内共用的直径与字号在容器上写一次,沿继承流给每一枚;自己写了档位的那一枚仍按自己的档走 */
|
|
4
|
+
[data-scope='avatar-group'][data-part='root'] {
|
|
5
|
+
/* 私有槽位:整组共用的直径、字号与叠放量,换档只改这三个 */
|
|
6
|
+
--xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-md));
|
|
7
|
+
--xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-sm));
|
|
8
|
+
--xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-2_5));
|
|
9
|
+
|
|
10
|
+
/* 流给组内每一枚 */
|
|
11
|
+
--xh-avatar-size: var(--xh-_avatar-group-size);
|
|
12
|
+
--xh-avatar-font-size: var(--xh-_avatar-group-font-size);
|
|
13
|
+
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
|
|
19
|
+
不补的话作者给节点加 hidden 后它照样显示 */
|
|
20
|
+
[data-scope='avatar-group'][data-part='root'][hidden] {
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* —— 尺寸 —— */
|
|
25
|
+
/* 三档对齐控件档位,缺省档写在上面的基础规则里;
|
|
26
|
+
字号与叠放量跟着直径一起缩放,小头像里回退字放得下、大头像里压住的那段也按比例长 */
|
|
27
|
+
[data-scope='avatar-group'][data-part='root'][data-size='sm'] {
|
|
28
|
+
--xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-sm));
|
|
29
|
+
--xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-xs));
|
|
30
|
+
--xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-2));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
[data-scope='avatar-group'][data-part='root'][data-size='lg'] {
|
|
34
|
+
--xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-lg));
|
|
35
|
+
--xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-md));
|
|
36
|
+
--xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-3));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* —— 叠放 —— */
|
|
40
|
+
/* 谁压在谁上面得能指定,所以每一枚都是定位元素;
|
|
41
|
+
再描一圈底色,被压住的那条边才与上一枚分得开 */
|
|
42
|
+
[data-scope='avatar-group'][data-part='root'] > * {
|
|
43
|
+
position: relative;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[data-scope='avatar-group'][data-part='root'] > *,
|
|
47
|
+
[data-scope='avatar-group'][data-part='root'] > * [data-scope='avatar'][data-part='root'] {
|
|
48
|
+
box-shadow: 0 0 0 var(--xh-stroke-thick) var(--xh-avatar-group-ring, var(--xh-bg-surface));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* 后一枚往回挪一段,压在前一枚上 */
|
|
52
|
+
[data-scope='avatar-group'][data-part='root'] > * + * {
|
|
53
|
+
margin-inline-start: calc(-1 * var(--xh-_avatar-group-overlap));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* 指到哪一枚,哪一枚整个露出来 */
|
|
57
|
+
[data-scope='avatar-group'][data-part='root'] > *:hover {
|
|
58
|
+
z-index: 1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* —— 溢出计数 —— */
|
|
62
|
+
/* 「+N」是这一排里的又一枚:直径、形状与字号跟着组走,里面写什么由作者定 */
|
|
63
|
+
[data-scope='avatar-group'][data-part='overflow'] {
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
flex: none;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
inline-size: var(--xh-_avatar-group-size);
|
|
69
|
+
block-size: var(--xh-_avatar-group-size);
|
|
70
|
+
border-radius: var(--xh-avatar-group-radius, var(--xh-shape-pill));
|
|
71
|
+
background: var(--xh-avatar-group-overflow-bg, var(--xh-bg-muted));
|
|
72
|
+
color: var(--xh-avatar-group-overflow-fg, var(--xh-fg-muted));
|
|
73
|
+
font-size: var(--xh-_avatar-group-font-size);
|
|
74
|
+
font-weight: var(--xh-avatar-group-font-weight, var(--xh-font-weight-medium));
|
|
75
|
+
line-height: var(--xh-leading-none);
|
|
76
|
+
user-select: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[data-scope='avatar-group'][data-part='overflow'][hidden] {
|
|
80
|
+
display: none;
|
|
81
|
+
}
|
|
82
|
+
}
|
package/css/avatar.css
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
[data-scope='avatar'][data-part='root'] {
|
|
3
|
+
position: relative;
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
flex: none;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
inline-size: var(--xh-avatar-size, var(--xh-control-h-md));
|
|
10
|
+
block-size: var(--xh-avatar-size, var(--xh-control-h-md));
|
|
11
|
+
border-radius: var(--xh-avatar-radius, var(--xh-shape-pill));
|
|
12
|
+
background: var(--xh-avatar-bg, var(--xh-bg-subtle));
|
|
13
|
+
color: var(--xh-avatar-fg, var(--xh-fg-muted));
|
|
14
|
+
font-size: var(--xh-avatar-font-size, var(--xh-font-size-sm));
|
|
15
|
+
font-weight: var(--xh-avatar-font-weight, var(--xh-font-weight-medium));
|
|
16
|
+
line-height: var(--xh-leading-none);
|
|
17
|
+
user-select: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* 三档尺寸对齐控件档位,缺省档写在上面的基础规则里;
|
|
21
|
+
字号跟着一起缩放,回退字才在小头像里放得下、在大头像里不显小 */
|
|
22
|
+
[data-scope='avatar'][data-part='root'][data-size='sm'] {
|
|
23
|
+
inline-size: var(--xh-control-h-sm);
|
|
24
|
+
block-size: var(--xh-control-h-sm);
|
|
25
|
+
font-size: var(--xh-font-size-xs);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[data-scope='avatar'][data-part='root'][data-size='lg'] {
|
|
29
|
+
inline-size: var(--xh-control-h-lg);
|
|
30
|
+
block-size: var(--xh-control-h-lg);
|
|
31
|
+
font-size: var(--xh-font-size-md);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* 不声明 display,加载完成前的 hidden 直接交给浏览器的 [hidden] 规则收起 */
|
|
35
|
+
[data-scope='avatar'][data-part='image'] {
|
|
36
|
+
inline-size: 100%;
|
|
37
|
+
block-size: 100%;
|
|
38
|
+
border-radius: inherit;
|
|
39
|
+
object-fit: cover;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[data-scope='avatar'][data-part='fallback'] {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
inline-size: 100%;
|
|
47
|
+
block-size: 100%;
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* display 会盖掉 hidden 属性的 UA 规则,加载完成后显式让位给图片 */
|
|
52
|
+
[data-scope='avatar'][data-part='fallback'][hidden] {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/css/back-top.css
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 定位壳:钉在视口的尾下角,用逻辑属性,RTL 下自动换到另一侧。
|
|
3
|
+
不声明 display —— 收起态由连接层写 hidden,UA 的 [hidden]{display:none} 得压得住 */
|
|
4
|
+
[data-scope='back-top'][data-part='root'] {
|
|
5
|
+
/* 尺寸档只换这一个私有槽,按钮从壳继承,换档不必给每个部件各写一条选择器 */
|
|
6
|
+
--xh-_back-top-size: var(--xh-control-h-md);
|
|
7
|
+
|
|
8
|
+
position: fixed;
|
|
9
|
+
inset-block-end: var(--xh-back-top-inset-block, var(--xh-space-8));
|
|
10
|
+
inset-inline-end: var(--xh-back-top-inset-inline, var(--xh-space-8));
|
|
11
|
+
z-index: var(--xh-back-top-layer, var(--xh-layer-sticky));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* —— 尺寸 —— */
|
|
15
|
+
[data-scope='back-top'][data-part='root'][data-size='sm'] {
|
|
16
|
+
--xh-_back-top-size: var(--xh-control-h-sm);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-scope='back-top'][data-part='root'][data-size='lg'] {
|
|
20
|
+
--xh-_back-top-size: var(--xh-control-h-lg);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* 圆形按钮:里面通常只放一个箭头图标,宽高同取一档尺寸 */
|
|
24
|
+
[data-scope='back-top'][data-part='trigger'] {
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
inline-size: var(--xh-back-top-trigger-size, var(--xh-_back-top-size));
|
|
29
|
+
block-size: var(--xh-back-top-trigger-size, var(--xh-_back-top-size));
|
|
30
|
+
padding: 0;
|
|
31
|
+
border: var(--xh-stroke-thin) solid var(--xh-back-top-border, var(--xh-border-default));
|
|
32
|
+
border-radius: var(--xh-back-top-radius, var(--xh-shape-pill));
|
|
33
|
+
/* 使用者令牌排在语气之前:写了覆盖钩子就以它为准,没写才退到语气,最后才是中性缺省 */
|
|
34
|
+
background: var(--xh-back-top-bg, var(--xh-bg-surface-raised));
|
|
35
|
+
color: var(--xh-back-top-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
|
|
36
|
+
/* 浮在内容之上,靠投影与页面拉开层次 */
|
|
37
|
+
box-shadow: var(--xh-elevation-2);
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
transition:
|
|
40
|
+
background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
|
|
41
|
+
border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* 悬停只在能用指针的设备上生效,触摸端不留一个按不掉的悬停态 */
|
|
45
|
+
@media (hover: hover) {
|
|
46
|
+
[data-scope='back-top'][data-part='trigger']:hover {
|
|
47
|
+
border-color: var(--xh-back-top-border-hover, var(--xh-border-strong));
|
|
48
|
+
background: var(--xh-back-top-bg-hover, var(--xh-bg-subtle-hover));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
[data-scope='back-top'][data-part='trigger']:active {
|
|
53
|
+
background: var(--xh-back-top-bg-active, var(--xh-bg-subtle-active));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* 聚焦环恒是 --xh-ring-focus,不随语气走 */
|
|
57
|
+
[data-scope='back-top'][data-part='trigger']:focus-visible {
|
|
58
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
59
|
+
outline-offset: var(--xh-ring-offset);
|
|
60
|
+
}
|
|
61
|
+
}
|