agentcss 0.0.0-stage → 0.11.3
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/01-tokens/README.md +236 -0
- package/01-tokens/behavior/dismissable.js +132 -0
- package/01-tokens/behavior/emit.js +76 -0
- package/01-tokens/behavior/focus-return.js +81 -0
- package/01-tokens/behavior/roving.js +152 -0
- package/01-tokens/behavior/typeahead.js +124 -0
- package/01-tokens/focus-ring-demo.html +133 -0
- package/01-tokens/focus-ring.css +102 -0
- package/01-tokens/page.css +244 -0
- package/01-tokens/polyfill.js +116 -0
- package/01-tokens/responsive-demo.html +171 -0
- package/01-tokens/scrollbar-demo.html +194 -0
- package/01-tokens/scrollbar.css +179 -0
- package/01-tokens/theme-toggle.js +103 -0
- package/01-tokens/tokens.css +972 -0
- package/01-tokens/typography.css +156 -0
- package/02-primitives/badge/README.md +71 -0
- package/02-primitives/badge/badge.css +141 -0
- package/02-primitives/badge/demo.html +101 -0
- package/02-primitives/button/README.md +99 -0
- package/02-primitives/button/button.css +353 -0
- package/02-primitives/button/demo.html +200 -0
- package/02-primitives/card/README.md +145 -0
- package/02-primitives/card/card.css +246 -0
- package/02-primitives/card/demo.html +170 -0
- package/02-primitives/choice/README.md +161 -0
- package/02-primitives/choice/choice.css +395 -0
- package/02-primitives/choice/demo.html +277 -0
- package/02-primitives/combobox/README.md +79 -0
- package/02-primitives/combobox/combobox.css +223 -0
- package/02-primitives/combobox/combobox.js +485 -0
- package/02-primitives/combobox/demo.html +109 -0
- package/02-primitives/date-range/README.md +100 -0
- package/02-primitives/date-range/date-range.css +206 -0
- package/02-primitives/date-range/date-range.js +301 -0
- package/02-primitives/date-range/demo.html +104 -0
- package/02-primitives/input/README.md +170 -0
- package/02-primitives/input/demo.html +246 -0
- package/02-primitives/input/input.css +239 -0
- package/02-primitives/popover/README.md +80 -0
- package/02-primitives/popover/demo.html +150 -0
- package/02-primitives/popover/popover.css +187 -0
- package/02-primitives/popover/popover.js +331 -0
- package/02-primitives/progress/README.md +82 -0
- package/02-primitives/progress/demo.html +154 -0
- package/02-primitives/progress/progress.css +172 -0
- package/02-primitives/select/README.md +95 -0
- package/02-primitives/select/demo.html +121 -0
- package/02-primitives/select/select.css +151 -0
- package/02-primitives/select/select.js +549 -0
- package/02-primitives/separator/README.md +63 -0
- package/02-primitives/separator/demo.html +84 -0
- package/02-primitives/separator/separator.css +73 -0
- package/02-primitives/skeleton/README.md +69 -0
- package/02-primitives/skeleton/demo.html +110 -0
- package/02-primitives/skeleton/skeleton.css +96 -0
- package/02-primitives/switch/README.md +65 -0
- package/02-primitives/switch/demo.html +115 -0
- package/02-primitives/switch/switch.css +370 -0
- package/03-patterns/accordion/README.md +121 -0
- package/03-patterns/accordion/accordion.css +453 -0
- package/03-patterns/accordion/accordion.js +369 -0
- package/03-patterns/accordion/demo.html +223 -0
- package/03-patterns/content/README.md +103 -0
- package/03-patterns/content/content.css +286 -0
- package/03-patterns/content/demo.html +88 -0
- package/03-patterns/drawer/README.md +79 -0
- package/03-patterns/drawer/demo.html +101 -0
- package/03-patterns/drawer/drawer.css +129 -0
- package/03-patterns/drawer/drawer.js +258 -0
- package/03-patterns/dropdown/README.md +78 -0
- package/03-patterns/dropdown/demo.html +101 -0
- package/03-patterns/dropdown/dropdown.css +135 -0
- package/03-patterns/dropdown/dropdown.js +451 -0
- package/03-patterns/form-validation/README.md +147 -0
- package/03-patterns/form-validation/demo.html +280 -0
- package/03-patterns/form-validation/form-validation.css +263 -0
- package/03-patterns/list/README.md +150 -0
- package/03-patterns/list/demo.html +225 -0
- package/03-patterns/list/flip.js +201 -0
- package/03-patterns/list/list.css +162 -0
- package/03-patterns/nav/README.md +225 -0
- package/03-patterns/nav/demo.html +131 -0
- package/03-patterns/nav/nav.css +314 -0
- package/03-patterns/nav/nav.js +430 -0
- package/03-patterns/nav/toc.js +111 -0
- package/03-patterns/overlay/README.md +196 -0
- package/03-patterns/overlay/demo.html +241 -0
- package/03-patterns/overlay/overlay.css +319 -0
- package/03-patterns/overlay/overlay.js +563 -0
- package/03-patterns/pagination/README.md +114 -0
- package/03-patterns/pagination/demo.html +165 -0
- package/03-patterns/pagination/pagination.css +195 -0
- package/03-patterns/pagination/pagination.js +395 -0
- package/03-patterns/reveal/README.md +91 -0
- package/03-patterns/reveal/demo.html +106 -0
- package/03-patterns/reveal/reveal.css +93 -0
- package/03-patterns/reveal/reveal.js +172 -0
- package/03-patterns/states/README.md +141 -0
- package/03-patterns/states/demo.html +240 -0
- package/03-patterns/states/states.css +252 -0
- package/03-patterns/tabs/README.md +84 -0
- package/03-patterns/tabs/demo.html +139 -0
- package/03-patterns/tabs/tabs.css +172 -0
- package/03-patterns/tabs/tabs.js +307 -0
- package/03-patterns/tooltip/README.md +96 -0
- package/03-patterns/tooltip/demo.html +78 -0
- package/03-patterns/tooltip/tooltip.css +89 -0
- package/03-patterns/tooltip/tooltip.js +288 -0
- package/03-patterns/tree/README.md +94 -0
- package/03-patterns/tree/demo.html +138 -0
- package/03-patterns/tree/tree.css +113 -0
- package/03-patterns/tree/tree.js +456 -0
- package/04-recipes/analysis-report/README.md +80 -0
- package/04-recipes/analysis-report/analysis-report.css +187 -0
- package/04-recipes/analysis-report/demo.html +274 -0
- package/04-recipes/data-showcase/README.md +45 -0
- package/04-recipes/data-showcase/demo.html +247 -0
- package/04-recipes/detail-page/README.md +93 -0
- package/04-recipes/detail-page/demo.html +55 -0
- package/04-recipes/detail-page/detail-page.css +190 -0
- package/04-recipes/detail-page/full.html +60 -0
- package/04-recipes/detail-page/null.html +60 -0
- package/04-recipes/detail-page/partial.html +60 -0
- package/04-recipes/detail-page/verify-skeleton.py +19 -0
- package/04-recipes/longform/README.md +93 -0
- package/04-recipes/longform/agc-memory.svg +4 -0
- package/04-recipes/longform/content.html +610 -0
- package/04-recipes/longform/content.md +51 -0
- package/04-recipes/longform/longform.html +627 -0
- package/04-recipes/report/README.md +176 -0
- package/04-recipes/report/demo.html +355 -0
- package/04-recipes/report/report.css +364 -0
- package/04-recipes/table/README.md +103 -0
- package/04-recipes/table/demo.html +455 -0
- package/04-recipes/table/table.css +372 -0
- package/04-recipes/tierA-tokens.css +189 -0
- package/09-assets/README.md +74 -0
- package/09-assets/bar/README.md +94 -0
- package/09-assets/bar/bar.css +166 -0
- package/09-assets/bar/bar.js +320 -0
- package/09-assets/bar/demo.html +176 -0
- package/09-assets/echarts-adapter/demo.html +192 -0
- package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
- package/09-assets/model-viewer/README.md +155 -0
- package/09-assets/model-viewer/demo.html +105 -0
- package/09-assets/model-viewer/model-viewer.css +143 -0
- package/09-assets/model-viewer/model-viewer.js +423 -0
- package/09-assets/scientific-plot/README.md +94 -0
- package/09-assets/scientific-plot/demo.html +252 -0
- package/09-assets/scientific-plot/scientific-plot.css +141 -0
- package/09-assets/scientific-plot/scientific-plot.js +610 -0
- package/09-assets/sparkline/README.md +153 -0
- package/09-assets/sparkline/demo.html +163 -0
- package/09-assets/sparkline/sparkline.css +158 -0
- package/09-assets/sparkline/sparkline.js +508 -0
- package/API.md +332 -0
- package/CHANGELOG.md +3138 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +89 -0
- package/ERRORS.md +1658 -0
- package/LICENSE +21 -0
- package/README.md +497 -2
- package/SECURITY.md +72 -0
- package/START-HERE.md +164 -0
- package/SUPPORT.md +109 -0
- package/adapters/presentation/README.md +113 -0
- package/adapters/presentation/check.js +101 -0
- package/adapters/presentation/deck.schema.json +74 -0
- package/adapters/presentation/to-doc.js +138 -0
- package/ai/START-HERE.md +104 -0
- package/ai/behaviors.json +380 -0
- package/ai/behaviors.schema.json +61 -0
- package/ai/capabilities.json +56 -0
- package/ai/cli.js +387 -0
- package/ai/components.json +1944 -0
- package/ai/components.meta.json +168 -0
- package/ai/components.schema.json +220 -0
- package/ai/contract.schema.json +147 -0
- package/ai/deprecations.json +55 -0
- package/ai/deprecations.schema.json +85 -0
- package/ai/motion-policy.json +22 -0
- package/ai/patch.js +323 -0
- package/ai/patch.schema.json +63 -0
- package/ai/profiles.json +92 -0
- package/ai/tokens.audience.json +55 -0
- package/ai/tokens.audience.schema.json +73 -0
- package/ai/tokens.json +762 -0
- package/ai/tokens.schema.json +58 -0
- package/ai/tokens.tree.json +752 -0
- package/ai/tokens.tree.schema.json +56 -0
- package/ai/validate.js +383 -0
- package/dist/01-tokens/behavior/dismissable.js +60 -0
- package/dist/01-tokens/behavior/emit.js +21 -0
- package/dist/01-tokens/behavior/focus-return.js +31 -0
- package/dist/01-tokens/behavior/roving.js +77 -0
- package/dist/01-tokens/behavior/typeahead.js +61 -0
- package/dist/01-tokens/focus-ring.css +1 -0
- package/dist/01-tokens/page.css +1 -0
- package/dist/01-tokens/polyfill.js +78 -0
- package/dist/01-tokens/scrollbar.css +1 -0
- package/dist/01-tokens/theme-toggle.js +61 -0
- package/dist/01-tokens/tokens.css +1 -0
- package/dist/01-tokens/typography.css +1 -0
- package/dist/02-primitives/badge/badge.css +1 -0
- package/dist/02-primitives/button/button.css +1 -0
- package/dist/02-primitives/card/card.css +1 -0
- package/dist/02-primitives/choice/choice.css +1 -0
- package/dist/02-primitives/combobox/combobox.css +1 -0
- package/dist/02-primitives/combobox/combobox.js +439 -0
- package/dist/02-primitives/date-range/date-range.css +1 -0
- package/dist/02-primitives/date-range/date-range.js +267 -0
- package/dist/02-primitives/input/input.css +1 -0
- package/dist/02-primitives/popover/popover.css +1 -0
- package/dist/02-primitives/popover/popover.js +257 -0
- package/dist/02-primitives/progress/progress.css +1 -0
- package/dist/02-primitives/select/select.css +1 -0
- package/dist/02-primitives/select/select.js +449 -0
- package/dist/02-primitives/separator/separator.css +1 -0
- package/dist/02-primitives/skeleton/skeleton.css +1 -0
- package/dist/02-primitives/switch/switch.css +1 -0
- package/dist/03-patterns/accordion/accordion.css +1 -0
- package/dist/03-patterns/accordion/accordion.js +219 -0
- package/dist/03-patterns/content/content.css +1 -0
- package/dist/03-patterns/drawer/drawer.css +1 -0
- package/dist/03-patterns/drawer/drawer.js +229 -0
- package/dist/03-patterns/dropdown/dropdown.css +1 -0
- package/dist/03-patterns/dropdown/dropdown.js +365 -0
- package/dist/03-patterns/form-validation/form-validation.css +1 -0
- package/dist/03-patterns/list/flip.js +117 -0
- package/dist/03-patterns/list/list.css +1 -0
- package/dist/03-patterns/nav/nav.css +1 -0
- package/dist/03-patterns/nav/nav.js +322 -0
- package/dist/03-patterns/nav/toc.js +76 -0
- package/dist/03-patterns/overlay/overlay.css +1 -0
- package/dist/03-patterns/overlay/overlay.js +398 -0
- package/dist/03-patterns/pagination/pagination.css +1 -0
- package/dist/03-patterns/pagination/pagination.js +273 -0
- package/dist/03-patterns/reveal/reveal.css +1 -0
- package/dist/03-patterns/reveal/reveal.js +138 -0
- package/dist/03-patterns/states/states.css +1 -0
- package/dist/03-patterns/tabs/tabs.css +1 -0
- package/dist/03-patterns/tabs/tabs.js +242 -0
- package/dist/03-patterns/tooltip/tooltip.css +1 -0
- package/dist/03-patterns/tooltip/tooltip.js +213 -0
- package/dist/03-patterns/tree/tree.css +1 -0
- package/dist/03-patterns/tree/tree.js +383 -0
- package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
- package/dist/04-recipes/detail-page/detail-page.css +1 -0
- package/dist/04-recipes/report/report.css +1 -0
- package/dist/04-recipes/table/table.css +1 -0
- package/dist/04-recipes/tierA-tokens.css +1 -0
- package/dist/09-assets/bar/bar.css +1 -0
- package/dist/09-assets/bar/bar.js +222 -0
- package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
- package/dist/09-assets/model-viewer/model-viewer.css +1 -0
- package/dist/09-assets/model-viewer/model-viewer.js +320 -0
- package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
- package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
- package/dist/09-assets/sparkline/sparkline.css +1 -0
- package/dist/09-assets/sparkline/sparkline.js +265 -0
- package/dist/COSTS.md +56 -0
- package/docs/AI-CONTRACT.md +197 -0
- package/docs/BACKLOG.md +127 -0
- package/docs/BENCHMARK.md +252 -0
- package/docs/GUIDANCE.md +154 -0
- package/docs/INVARIANT.md +372 -0
- package/docs/LAYER-BASELINE.md +158 -0
- package/docs/RELEASING.md +311 -0
- package/docs/RFC-THEME-SCOPE.md +141 -0
- package/docs/ROADMAP.md +182 -0
- package/index.html +82 -0
- package/package.json +107 -4
- package/types/index.d.ts +310 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Accordion — 折叠面板(APG: Accordion Pattern)
|
|
3
|
+
============================================================================
|
|
4
|
+
🔴 **重写**。真机实测指出的问题(截图为准):
|
|
5
|
+
|
|
6
|
+
① 「内容部分非常靠上方」—— 内容紧贴标题下的分隔线,
|
|
7
|
+
而且**整块内容是突然出现的**(没有展开的过程)
|
|
8
|
+
⇒ 看起来像"贴上去的一小块",廉价。
|
|
9
|
+
|
|
10
|
+
② 「表达方式不对」—— 展开后内容与标题**没有视觉从属关系**。
|
|
11
|
+
|
|
12
|
+
③ 「一个标题内部多列的折叠会有问题」—— 这是**真实场景**
|
|
13
|
+
(如"财务数据"下展开营收 / 净利 / 毛利率三列)
|
|
14
|
+
|
|
15
|
+
⇒ 本次重写依据 **Radix Accordion / Collapsible 的一手实现**
|
|
16
|
+
(实测抓自 jsdelivr:accordion.tsx 569 行 + collapsible 的 CSS 变量机制),
|
|
17
|
+
不是我自己的设计。
|
|
18
|
+
|
|
19
|
+
============================================================================
|
|
20
|
+
⭐ 核心机制:高度动画靠「JS 量尺寸 → CSS 变量 → CSS 过渡」
|
|
21
|
+
============================================================================
|
|
22
|
+
Radix 的做法(collapsible.tsx 实测原文):
|
|
23
|
+
|
|
24
|
+
style={{ '--radix-collapsible-content-height': height }} ← JS 量一次
|
|
25
|
+
hidden={!isOpen} ← 收起才移出无障碍树
|
|
26
|
+
{isOpen && children}
|
|
27
|
+
--------------------------------------------------------------------------
|
|
28
|
+
🔴 补:声明 --acc-h / --acc-locked-h(组件级变量)
|
|
29
|
+
|
|
30
|
+
是**运行时**高度:accordion.js 在展开前量出 inner 的高度,
|
|
31
|
+
用 写进来,
|
|
32
|
+
收起结束后 清掉。
|
|
33
|
+
|
|
34
|
+
⚠️ 为什么在这里声明(而不是 tokens.css):
|
|
35
|
+
它**只对本组件有意义**,别的组件不会用 ⇒ 不该进全局令牌表。
|
|
36
|
+
⚠️ 之前它**只被引用、没有任何地方定义** ⇒ CSS 变量不存在时
|
|
37
|
+
**不报错**, 声明**静默失效**(deps 门禁报出来的就是这个)。
|
|
38
|
+
-------------------------------------------------------------------------- */
|
|
39
|
+
:root {
|
|
40
|
+
--acc-h: 0px; /* 0 = 收起;JS 展开时覆盖成实际像素值 */
|
|
41
|
+
--acc-locked-h: auto; /* 保留:给锁高实验用,当前 JS 不设 */
|
|
42
|
+
}
|
|
43
|
+
/* 🔴 修:下面这几段说明文字**原本没有注释开头**,
|
|
44
|
+
只有末尾一个收尾符 ⇒ 中间 20 行被当成 CSS 代码解析
|
|
45
|
+
(CSS 的错误恢复会把它们并进下一个选择器,属"碰巧没炸")。
|
|
46
|
+
CSS 注释**不嵌套**且必须成对;缺开头比缺结尾更隐蔽 ——
|
|
47
|
+
缺结尾 ⇒ 浏览器吞掉后面所有内容,立刻看得见;
|
|
48
|
+
缺开头 ⇒ 正文变成选择器垃圾,可能一直不炸。
|
|
49
|
+
⇒ 已由 05-audit/token-parse-gate.py 兜住:孤儿收尾符 ⇒ 门禁红。
|
|
50
|
+
|
|
51
|
+
← 动画期间仍在树里
|
|
52
|
+
|
|
53
|
+
⇒ **JS 只做一件事:量一次高度写进 CSS 变量**,动画交给 CSS。
|
|
54
|
+
|
|
55
|
+
🔴 关键细节(Radix 源码注释原话):
|
|
56
|
+
"when closing we delay `present` to retrieve dimensions before closing"
|
|
57
|
+
⇒ **关闭时必须先量到尺寸再收起**,否则量到 0,动画就没了。
|
|
58
|
+
本组件用「保留一帧再收」复刻这一点(见 accordion.js)。
|
|
59
|
+
|
|
60
|
+
============================================================================
|
|
61
|
+
⭐ 为什么用 grid-template-rows 而不是 max-height
|
|
62
|
+
============================================================================
|
|
63
|
+
`max-height: 1000px` 那种写法的毛病:**你必须猜内容有多高**。
|
|
64
|
+
内容超过就"被截断",不到就"收起后还留一截空白"。
|
|
65
|
+
|
|
66
|
+
`grid-template-rows: 0fr → 1fr` 不需要知道高度 ——
|
|
67
|
+
`1fr` 就是"内容有多高就多高",`0fr` 就是"完全收起"。
|
|
68
|
+
|
|
69
|
+
⚠️ `fr` 动画需要配合 `overflow: hidden`,否则内容会溢出来。
|
|
70
|
+
========================================================================= */
|
|
71
|
+
|
|
72
|
+
.accordion {
|
|
73
|
+
--acc-dur: var(--dur-base, 240ms);
|
|
74
|
+
--acc-ease: var(--ease-out, cubic-bezier(0.2, 0, 0, 1));
|
|
75
|
+
|
|
76
|
+
border: 1px solid var(--border-decor);
|
|
77
|
+
border-radius: var(--r-md);
|
|
78
|
+
background: var(--surface);
|
|
79
|
+
/* 🔴 这里**不能**用 overflow:hidden —— 会裁掉 focus ring。
|
|
80
|
+
每一项自己裁(见 .accordion__item)。 */
|
|
81
|
+
overflow: visible;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.accordion--flush {
|
|
85
|
+
border: 0;
|
|
86
|
+
background: transparent;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ---------------------------------------------------------
|
|
90
|
+
一项 —— 高度动画的容器
|
|
91
|
+
--------------------------------------------------------- */
|
|
92
|
+
.accordion__item {
|
|
93
|
+
border-bottom: 1px solid var(--border-decor);
|
|
94
|
+
/* 🔴 关键:给高度动画一个裁切边界。
|
|
95
|
+
没有它,0fr 时内容会溢到下一项上。 */
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.accordion__item:last-child {
|
|
100
|
+
border-bottom: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ---------------------------------------------------------
|
|
104
|
+
Header(heading)—— APG 要求 button 在 heading 里面
|
|
105
|
+
--------------------------------------------------------- */
|
|
106
|
+
.accordion__heading {
|
|
107
|
+
margin: 0;
|
|
108
|
+
font-size: inherit;
|
|
109
|
+
font-weight: inherit;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* ---------------------------------------------------------
|
|
113
|
+
Trigger(原生 button)
|
|
114
|
+
--------------------------------------------------------- */
|
|
115
|
+
.accordion__trigger {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: var(--sp-3);
|
|
119
|
+
width: 100%;
|
|
120
|
+
min-height: 44px; /* WCAG 2.5.5 命中区 */
|
|
121
|
+
padding: var(--sp-3) var(--sp-4);
|
|
122
|
+
font: inherit;
|
|
123
|
+
font-size: var(--fs-base);
|
|
124
|
+
font-weight: 500;
|
|
125
|
+
text-align: start;
|
|
126
|
+
color: var(--text-primary);
|
|
127
|
+
background: transparent;
|
|
128
|
+
border: 0;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: background var(--dur-fast) var(--ease-out);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.accordion__trigger:focus-visible {
|
|
134
|
+
outline: 2px solid var(--accent);
|
|
135
|
+
outline-offset: -2px; /* 往内,避免被 overflow 裁掉 */
|
|
136
|
+
border-radius: var(--r-sm);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (hover: hover) and (pointer: fine) {
|
|
140
|
+
.accordion__trigger:not([aria-disabled="true"]):hover {
|
|
141
|
+
background: var(--surface-sunken);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.accordion__trigger[aria-disabled="true"] {
|
|
146
|
+
color: var(--text-tertiary);
|
|
147
|
+
cursor: not-allowed;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* 🔴 展开态:标题有底色,让"这一段是开着的"一眼可见 */
|
|
151
|
+
.accordion__trigger[aria-expanded="true"] {
|
|
152
|
+
background: var(--surface-sunken);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.accordion__label {
|
|
156
|
+
flex: 1 1 auto;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* 🔴 可选的副标题:标题下方一行小字 */
|
|
161
|
+
.accordion__hint {
|
|
162
|
+
display: block;
|
|
163
|
+
font-size: var(--fs-xs);
|
|
164
|
+
font-weight: 400;
|
|
165
|
+
color: var(--text-secondary);
|
|
166
|
+
margin-top: 2px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* ---------------------------------------------------------
|
|
170
|
+
展开指示 —— CSS 画的,不引图标资产
|
|
171
|
+
--------------------------------------------------------- */
|
|
172
|
+
.accordion__marker {
|
|
173
|
+
flex: 0 0 auto;
|
|
174
|
+
width: 8px;
|
|
175
|
+
height: 8px;
|
|
176
|
+
border-inline-end: 2px solid var(--text-tertiary);
|
|
177
|
+
border-bottom: 2px solid var(--text-tertiary);
|
|
178
|
+
transform: rotate(45deg) translate(-1px, -1px);
|
|
179
|
+
transition: transform var(--acc-dur) var(--acc-ease);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.accordion__trigger[aria-expanded="true"] .accordion__marker {
|
|
183
|
+
transform: rotate(-135deg) translate(-2px, -2px);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@media (forced-colors: active) {
|
|
187
|
+
.accordion__marker { border-color: currentColor; }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* ============================================================================
|
|
191
|
+
⭐ Content —— 高度动画的核心
|
|
192
|
+
============================================================================
|
|
193
|
+
`grid-template-rows: 0fr → 1fr`:
|
|
194
|
+
· 0fr = 完全收起(配合 item 的 overflow:hidden,内容被裁掉)
|
|
195
|
+
· 1fr = 内容有多高就多高(**不需要猜高度**,比 max-height 强在这)
|
|
196
|
+
========================================================================= */
|
|
197
|
+
.accordion__panel {
|
|
198
|
+
display: grid;
|
|
199
|
+
grid-template-rows: 0fr;
|
|
200
|
+
transition: grid-template-rows var(--acc-dur) var(--acc-ease);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.accordion__panel[data-state="open"] {
|
|
204
|
+
grid-template-rows: 1fr;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* 🔴 退场动画的起点(JS 量的,抄 Radix 的 --radix-collapsible-content-height)
|
|
208
|
+
用途:0fr 过渡在某些浏览器里会"跳",先给一个确定的 px 起点更稳。
|
|
209
|
+
⚠️ 只有 JS 在**关闭那一刻**写了这个变量,其他时候不该有。 */
|
|
210
|
+
.accordion__panel[style*="--acc-h"] {
|
|
211
|
+
transition: grid-template-rows var(--acc-dur) var(--acc-ease),
|
|
212
|
+
max-height var(--acc-dur) var(--acc-ease);
|
|
213
|
+
/* 🔴 --acc-h 由 accordion.js 在展开前动态测量写入
|
|
214
|
+
(panel.style.setProperty('--acc-h', h + 'px')),
|
|
215
|
+
收起结束后 removeProperty 清掉。
|
|
216
|
+
⚠️ 第二个参数是 **fallback**:JS 没设时用 0px(收起态),
|
|
217
|
+
这样这条声明**永远有效**,不会静默失效。 */
|
|
218
|
+
max-height: var(--acc-h, 0px);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.accordion__panel[style*="--acc-h"][data-state="closed"] {
|
|
222
|
+
max-height: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* 🔴 被 0fr/1fr 控制高度的就是它。
|
|
226
|
+
⚠️ min-height:0 是 grid item 的必要条件(否则内容撑破 0fr)。 */
|
|
227
|
+
/* 🔴 补(accordion 契约抓到「收起的面板没有真正 display:none」)
|
|
228
|
+
|
|
229
|
+
真因:`.accordion__panel { display: grid }` **覆盖了 `hidden` 属性的
|
|
230
|
+
`display: none`** —— `hidden` 在 HTML 规范里只是 `display: none` 的
|
|
231
|
+
**UA 样式**,任何作者声明的 `display` 都能盖掉它。
|
|
232
|
+
|
|
233
|
+
实测:JS 已正确设了 `hidden=""`,但 getComputedStyle().display 仍是 `grid`。
|
|
234
|
+
|
|
235
|
+
⚠️ 这类 bug 很隐蔽:`hidden` 属性**看起来**设了,
|
|
236
|
+
读屏软件也真的读不到内容(因为 hidden 已在无障碍树里生效),
|
|
237
|
+
但"CSS 层面的 display"没生效这件事没人会发现。
|
|
238
|
+
|
|
239
|
+
⇒ 修法:显式声明 hidden 时用 `display: none !important`。 */
|
|
240
|
+
.accordion__panel[hidden] {
|
|
241
|
+
display: none !important;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
.accordion__panel-inner {
|
|
246
|
+
min-height: 0;
|
|
247
|
+
overflow: hidden;
|
|
248
|
+
padding: 0 var(--sp-4);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* ⭐ 内边距放在**内层**,不放外层 ——
|
|
252
|
+
放外层的话,收起时上下 padding 仍然存在(0fr 只算内容高),
|
|
253
|
+
收起后会留下一截空白。 */
|
|
254
|
+
.accordion__trigger[aria-expanded="true"] + .accordion__panel .accordion__panel-inner {
|
|
255
|
+
padding-top: var(--sp-1);
|
|
256
|
+
padding-bottom: var(--sp-4);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* ============================================================================
|
|
260
|
+
🔴 修「收起后点另一项,第一次没反应」(真机实测反馈)
|
|
261
|
+
============================================================================
|
|
262
|
+
⭐ 真因(**实测量化到的**,不是猜的):
|
|
263
|
+
|
|
264
|
+
收起动画期间,**下方所有项跟着上移**。
|
|
265
|
+
实测:第 2 项的 trigger 在动画里 **top 从 489 → 358(上移 131px)**。
|
|
266
|
+
手指瞄准的是落下那一瞬间的位置,等浏览器派发 touch 时元素已移开
|
|
267
|
+
⇒ **点在空处,什么也没发生** —— 用户以为要点两次。
|
|
268
|
+
|
|
269
|
+
⚠️ 我试过但**无效**的两个办法(别再走回头路):
|
|
270
|
+
① `pointer-events: none` 让事件穿透
|
|
271
|
+
—— 事件穿过去了,但**目标位置本身是错的**(点在半空中,穿透给谁?)
|
|
272
|
+
⇒ 实测:去掉它与留着它,结果完全一样。
|
|
273
|
+
② 动画期间锁住点击 + 结束后补偿
|
|
274
|
+
—— 补偿逻辑实测没生效,第一次点击被彻底丢弃,**比原 bug 更糟**。
|
|
275
|
+
|
|
276
|
+
⇒ 真正的解法:**收起动画期间锁住整个列表高度**,不产生位移。
|
|
277
|
+
trigger 根本不动 ⇒ 手指瞄准的位置永远是对的。
|
|
278
|
+
代价:收起过程中下方留白(视觉像"内容收进去了,位置先留着"),
|
|
279
|
+
240ms 后空白消失 —— 这个代价比"要点两次"小得多。
|
|
280
|
+
========================================================================= */
|
|
281
|
+
/* 🔴 删除这条死规则(deps 门禁报「引用了未定义令牌 --acc-locked-h」)
|
|
282
|
+
JS 侧注释已写明「曾加过锁高,实测**无效**,已撤销」—— 锁的是**列表**高度,
|
|
283
|
+
而第 1 项是在列表**内部**收缩的,第 2 项照样上移 ⇒ 固有代价,无法避免。
|
|
284
|
+
⇒ CSS 侧忘了删;--acc-locked-h 从未被 JS 设置过
|
|
285
|
+
⇒ `height: var(--acc-locked-h)` **静默失效**(CSS 变量不存在不报错)。
|
|
286
|
+
⚠️ 顺带:过去这里还挂过一个"动画中"的状态类,全库没有任何 JS 会加它
|
|
287
|
+
⇒ 整条规则是死的。0.4.0 收敛状态表达时一并清掉了。 */
|
|
288
|
+
|
|
289
|
+
/* 收起中的 panel 不吃指针(顺带的正确性保证,不是主要手段) */
|
|
290
|
+
.accordion__panel[data-state="closed"] {
|
|
291
|
+
pointer-events: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* 展开中要正常接收(面板里的链接、按钮要能点) */
|
|
295
|
+
.accordion__panel[data-state="open"] {
|
|
296
|
+
pointer-events: auto;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* 收起完成、已 hidden 的那一帧:键盘焦点也不该落在里面 */
|
|
300
|
+
.accordion__panel[hidden] {
|
|
301
|
+
visibility: hidden;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* ============================================================================
|
|
305
|
+
⭐ 多列内容(明确提出的需求:「一个标题内部多列」)
|
|
306
|
+
============================================================================
|
|
307
|
+
为什么单独一套:多列内容(财务三列、指标卡)**行高与单列表不同**,
|
|
308
|
+
而且**窄屏必须能塌成一列**,否则手机上会挤成一团。
|
|
309
|
+
|
|
310
|
+
用法:给 `.accordion__panel-inner` 加 `cols-auto` / `cols-2` / `cols-3`
|
|
311
|
+
========================================================================= */
|
|
312
|
+
|
|
313
|
+
/* auto:按内容宽度自动分列,够宽就并排,窄了自动换行(最省心) */
|
|
314
|
+
.accordion__panel-inner.cols-auto {
|
|
315
|
+
display: grid;
|
|
316
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
317
|
+
gap: var(--sp-3);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/* 固定两列 / 三列 —— ≥720px 时分列,窄屏塌成一列 */
|
|
321
|
+
.accordion__panel-inner.cols-2,
|
|
322
|
+
.accordion__panel-inner.cols-3 {
|
|
323
|
+
display: grid;
|
|
324
|
+
gap: var(--sp-3);
|
|
325
|
+
grid-template-columns: 1fr;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
@media (min-width: 720px) {
|
|
329
|
+
.accordion__panel-inner.cols-2 { grid-template-columns: repeat(2, 1fr); }
|
|
330
|
+
.accordion__panel-inner.cols-3 { grid-template-columns: repeat(3, 1fr); }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* ============================================================================
|
|
334
|
+
🔴 **删掉我原来发明的 `.acc-cell`**
|
|
335
|
+
============================================================================
|
|
336
|
+
真机实测反馈:「这个多列内容我没看懂你想表达什么,我感觉你做错了」。
|
|
337
|
+
|
|
338
|
+
我原来做的是**四个卡片**(营业收入/净利润/毛利率/现金流),
|
|
339
|
+
在窄屏排成 **3 + 1** —— 最后那个孤零零换行,视觉上"缺了一块"。
|
|
340
|
+
|
|
341
|
+
⭐ 更根本的问题:**我根本没搞懂 需求是什么。**
|
|
342
|
+
他说的是「**一个标题内部多列的折叠**」——
|
|
343
|
+
而我做的"四个卡片"是**并列的四项**,不是**一行的多列**。
|
|
344
|
+
|
|
345
|
+
真正需要这个的是**数据表**:一行一个公司,点标题展开,
|
|
346
|
+
下面是这一行的**多列明细**(各项指标)。
|
|
347
|
+
|
|
348
|
+
⇒ 正确做法用 **`<table>` + `<td colspan>`**:
|
|
349
|
+
HTML spec 明确 `colspan` 就是为"跨列"设计的
|
|
350
|
+
(实测 HTML spec 抓到 colspan 定义),
|
|
351
|
+
且表格有**列对齐**(数字右对齐、标题左对齐天然成立)——
|
|
352
|
+
卡片网格做不到这一点。
|
|
353
|
+
|
|
354
|
+
⇒ 真正的组件能力应该是:
|
|
355
|
+
`.accordion__table` —— 面板内嵌表格(多列数据的正确形态)
|
|
356
|
+
========================================================================= */
|
|
357
|
+
|
|
358
|
+
/* ============================================================================
|
|
359
|
+
面板内嵌表格 —— 「一个标题内部多列」的正确形态
|
|
360
|
+
============================================================================
|
|
361
|
+
用法(面板内):
|
|
362
|
+
<table class="acc-table">
|
|
363
|
+
<thead><tr><th>指标</th><th>本期</th><th>同比</th></tr></thead>
|
|
364
|
+
<tbody><tr><td>营业收入</td><td class="num">128,430</td>"
|
|
365
|
+
<td class="num up">+12.4%</td></tr></tbody>
|
|
366
|
+
</table>
|
|
367
|
+
|
|
368
|
+
为什么用 table 而不是 div 网格:
|
|
369
|
+
① **列对齐**是表格的天然能力(数字右对齐),div 网格要手写一堆规则
|
|
370
|
+
② `<th scope>` 让读屏知道每个数字属于哪一列
|
|
371
|
+
③ 窄屏时表格可以**横向滚动**(下面有处理),卡片只能换行
|
|
372
|
+
========================================================================= */
|
|
373
|
+
.acc-table {
|
|
374
|
+
width: 100%;
|
|
375
|
+
border-collapse: collapse;
|
|
376
|
+
font-size: var(--fs-sm);
|
|
377
|
+
/* 🔴 窄屏:表格**横向滚动**而不是挤压换行
|
|
378
|
+
(表格一旦换行,列头与数据就对不上了) */
|
|
379
|
+
display: block;
|
|
380
|
+
overflow-x: auto;
|
|
381
|
+
-webkit-overflow-scrolling: touch;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@media (min-width: 600px) {
|
|
385
|
+
.acc-table { display: table; }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* 🔴 <caption> 必须**视觉隐藏但保留在无障碍树** ——
|
|
389
|
+
读屏用户需要知道这张表是什么,视觉上不需要看到。
|
|
390
|
+
(不能用我之前写的 .visually-hidden —— 那个类本库里不存在,
|
|
391
|
+
只有 switch 的 .switch__label--sr。) */
|
|
392
|
+
.acc-table caption {
|
|
393
|
+
position: absolute;
|
|
394
|
+
width: 1px;
|
|
395
|
+
height: 1px;
|
|
396
|
+
margin: -1px;
|
|
397
|
+
padding: 0;
|
|
398
|
+
overflow: hidden;
|
|
399
|
+
clip: rect(0 0 0 0);
|
|
400
|
+
clip-path: inset(50%);
|
|
401
|
+
white-space: nowrap;
|
|
402
|
+
border: 0;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.acc-table th,
|
|
406
|
+
.acc-table td {
|
|
407
|
+
padding: var(--sp-2) var(--sp-3);
|
|
408
|
+
text-align: start;
|
|
409
|
+
border-bottom: 1px solid var(--border-decor);
|
|
410
|
+
white-space: nowrap; /* 数字不折行 */
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.acc-table th {
|
|
414
|
+
font-size: var(--fs-xs);
|
|
415
|
+
font-weight: 500;
|
|
416
|
+
color: var(--text-secondary);
|
|
417
|
+
/* 🔴 表头在横向滚动时**固定在左侧**——
|
|
418
|
+
否则滑到右边就不知道这一列是什么了 */
|
|
419
|
+
position: sticky;
|
|
420
|
+
inset-inline-start: 0;
|
|
421
|
+
background: var(--surface);
|
|
422
|
+
z-index: 1;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.acc-table td {
|
|
426
|
+
color: var(--text-primary);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.acc-table .num {
|
|
430
|
+
text-align: end;
|
|
431
|
+
font-family: var(--mono);
|
|
432
|
+
font-variant-numeric: tabular-nums; /* 数字等宽对齐 */
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.acc-table .up { color: var(--danger); } /* A 股:涨红 */
|
|
436
|
+
.acc-table .down { color: var(--success); } /* 跌绿 */
|
|
437
|
+
|
|
438
|
+
.acc-table tbody tr:last-child td { border-bottom: 0; }
|
|
439
|
+
|
|
440
|
+
@media (hover: hover) and (pointer: fine) {
|
|
441
|
+
.acc-table tbody tr:hover td { background: var(--surface-sunken); }
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* ---------------------------------------------------------
|
|
445
|
+
reduced-motion —— 前庭功能障碍者会因动画眩晕(WCAG 2.3.3)
|
|
446
|
+
--------------------------------------------------------- */
|
|
447
|
+
@media (prefers-reduced-motion: reduce) {
|
|
448
|
+
.accordion__panel,
|
|
449
|
+
.accordion__marker,
|
|
450
|
+
.accordion__trigger {
|
|
451
|
+
transition: none;
|
|
452
|
+
}
|
|
453
|
+
}
|