agentcss 0.25.1 → 0.25.2
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/02-primitives/button/README.md +7 -0
- package/02-primitives/button/demo.html +52 -0
- package/02-primitives/card/README.md +6 -1
- package/02-primitives/card/demo.html +13 -0
- package/02-primitives/choice/choice.css +10 -0
- package/02-primitives/choice/demo.html +38 -0
- package/02-primitives/date-range/README.md +1 -1
- package/02-primitives/date-range/demo.html +41 -1
- package/02-primitives/input/README.md +3 -2
- package/02-primitives/input/demo.html +42 -0
- package/03-patterns/accordion/demo.html +113 -0
- package/03-patterns/content/demo.html +17 -0
- package/03-patterns/drawer/README.md +11 -1
- package/03-patterns/drawer/drawer.css +22 -6
- package/03-patterns/drawer/drawer.js +16 -1
- package/03-patterns/dropdown/README.md +10 -8
- package/03-patterns/dropdown/demo.html +5 -0
- package/03-patterns/dropdown/dropdown.js +8 -0
- package/03-patterns/form-validation/demo.html +20 -0
- package/03-patterns/list/demo.html +10 -0
- package/03-patterns/overlay/overlay.js +14 -1
- package/03-patterns/pagination/demo.html +23 -0
- package/03-patterns/states/demo.html +39 -1
- package/03-patterns/tabs/demo.html +34 -0
- package/03-patterns/tooltip/tooltip.js +8 -4
- package/04-recipes/app-shell/demo.html +27 -0
- package/04-recipes/table/demo.html +34 -0
- package/09-assets/bar/bar.js +8 -4
- package/09-assets/bar/demo.html +27 -0
- package/CHANGELOG.md +66 -1
- package/START-HERE.md +6 -6
- package/ai/components.json +6 -3
- package/dist/02-primitives/choice/choice.css +1 -1
- package/dist/03-patterns/drawer/drawer.css +1 -1
- package/dist/03-patterns/drawer/drawer.js +10 -1
- package/dist/03-patterns/dropdown/dropdown.js +4 -0
- package/dist/03-patterns/overlay/overlay.js +7 -1
- package/dist/03-patterns/tooltip/tooltip.js +3 -3
- package/dist/09-assets/bar/bar.js +4 -3
- package/dist/COSTS.md +7 -7
- package/docs/ACCESSIBILITY.md +1 -1
- package/index.html +1 -1
- package/llms-full.txt +3 -3
- package/package.json +1 -1
|
@@ -46,6 +46,13 @@
|
|
|
46
46
|
变体:`primary` / `secondary` / `ghost` / `danger`
|
|
47
47
|
尺寸:`sm`(32) / `md`(44) / `lg`(52)
|
|
48
48
|
|
|
49
|
+
> ⚠️ `.btn--icon.btn--sm` 是 **32×32**,只满足 WCAG 2.2 的 AA(24px),
|
|
50
|
+
> **不满足 44px 的 AAA**。它只适用于表格行、标签条这类鼠标为主、相邻控件
|
|
51
|
+
> 本身就很密的位置;触屏主流程请用 `md`。
|
|
52
|
+
> (所以演示页不放它:`button-check` 第 ③ 条要求整页可点元素 ≥44px,
|
|
53
|
+
> 放进来必然红 —— 那个红是对的。同类取舍见 `upload` 的 32px 移除按钮,
|
|
54
|
+
> 它在 `05-audit/tap-target.js` 里是**登记过的**例外。)
|
|
55
|
+
|
|
49
56
|
---
|
|
50
57
|
|
|
51
58
|
## 🔴 最关键的一个判断:`disabled` 还是 `aria-disabled`
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
.cell p { margin: 0 0 var(--sp-4); font-size: var(--fs-xs);
|
|
17
17
|
color: var(--text-tertiary); line-height: 1.55; }
|
|
18
18
|
.row { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: center; }
|
|
19
|
+
/* 给 btn--block 一个"容器边界",否则它会铺满整页、看不出"占满容器"这件事 */
|
|
20
|
+
.narrow { max-width: 280px; }
|
|
19
21
|
/* 反例演示用 */
|
|
20
22
|
.btn--naive { height: 44px; padding: 0 var(--sp-5); border: none; border-radius: var(--r-sm);
|
|
21
23
|
background: var(--accent); color: #fff; cursor: pointer; font-size: var(--fs-sm);
|
|
@@ -126,6 +128,56 @@
|
|
|
126
128
|
sm 只在表格行内等鼠标场景用。
|
|
127
129
|
</p>
|
|
128
130
|
|
|
131
|
+
<h2 class="rule-bottom">两种形态:方形图标按钮 / 占满一行</h2>
|
|
132
|
+
<div class="grid">
|
|
133
|
+
<div class="cell">
|
|
134
|
+
<h3><code>.btn--icon</code> · 只有图标</h3>
|
|
135
|
+
<p>
|
|
136
|
+
宽高相等(<code>--md</code> 44、<code>--lg</code> 52、<code>--sm</code> 32),所以图标必须是<strong>唯一内容</strong>。
|
|
137
|
+
⇒ 读屏读不到文字,必须显式给 <code>aria-label</code>,
|
|
138
|
+
否则念出来只有"按钮"两个字。
|
|
139
|
+
</p>
|
|
140
|
+
<div class="row">
|
|
141
|
+
<button class="btn btn--md btn--secondary btn--icon" aria-label="刷新数据">
|
|
142
|
+
<svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor"
|
|
143
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
144
|
+
aria-hidden="true" focusable="false"><path d="M21 12a9 9 0 1 1-2.6-6.4M21 3v6h-6"/></svg>
|
|
145
|
+
</button>
|
|
146
|
+
<button class="btn btn--md btn--primary btn--icon" aria-label="新建">
|
|
147
|
+
<svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor"
|
|
148
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
149
|
+
aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14"/></svg>
|
|
150
|
+
</button>
|
|
151
|
+
<button class="btn btn--md btn--secondary btn--icon" aria-label="收起侧栏">
|
|
152
|
+
<svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor"
|
|
153
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
154
|
+
aria-hidden="true" focusable="false"><path d="M15 6l-6 6 6 6"/></svg>
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
<p style="margin-top:var(--sp-3); font-size:var(--fs-xs); color:var(--text-tertiary)">
|
|
158
|
+
<code>.btn--icon.btn--sm</code> 是 32×32:只够 WCAG 2.2 的 AA(24px),
|
|
159
|
+
<strong>不满足 44px 的 AAA</strong> ⇒ 所以这里<strong>故意不演示</strong>它。
|
|
160
|
+
它只该出现在表格行、标签条这类鼠标为主、相邻控件本身就很密的地方;
|
|
161
|
+
触屏主流程请用 md。契约第 ③ 条要求本页所有可点元素 ≥44px,
|
|
162
|
+
放一颗 32px 的按钮进来就会红 —— 那个红是对的。
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="cell">
|
|
166
|
+
<h3><code>.btn--block</code> · 占满容器</h3>
|
|
167
|
+
<p>
|
|
168
|
+
不是 <code>width:100%</code> 的按钮,而是 <code>display:flex</code> 的容器
|
|
169
|
+
⇒ 内容自动居中,多个子元素(图标 + 文字)也不会各靠一边。
|
|
170
|
+
</p>
|
|
171
|
+
<div class="narrow">
|
|
172
|
+
<button class="btn btn--md btn--primary btn--block">提交审批</button>
|
|
173
|
+
</div>
|
|
174
|
+
<p style="margin-top:var(--sp-3); font-size:var(--fs-xs); color:var(--text-tertiary)">
|
|
175
|
+
外面这个 280px 的框就是它的容器:按钮正好铺满,不多不少。
|
|
176
|
+
宽度来自容器而不是按钮自己 ⇒ 放进窄侧栏、弹窗底部都不会溢。
|
|
177
|
+
</p>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
129
181
|
<h2 class="rule-bottom">对比:常见的错写法 vs 本库写法</h2>
|
|
130
182
|
<div class="cmp cmp--wide-first">
|
|
131
183
|
<div class="cmp__pane cmp__bad" data-bad="button|gw|>=3">
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| **来源** | 原创。2px 抬起一条来自对 `animal-island-ui` 的观察(那套设计里最认同的一条) |
|
|
6
6
|
| **实测** | `states.py` 零缺失(card 形态:focus HIGH / hover LOW) |
|
|
7
7
|
| **适用** | 精简档 / B / C,纯 CSS |
|
|
8
|
-
| **依赖** | `01-tokens/tokens.css` + `01-tokens/typography.css`(`.note` 提示框) + `01-tokens/page.css`(页面骨架:`.wrap` / `.lede` / `.note
|
|
8
|
+
| **依赖** | `01-tokens/tokens.css` + `01-tokens/typography.css`(`.note` 提示框) + `01-tokens/page.css`(页面骨架:`.wrap` / `.lede` / `.note`)。底栏要放**按钮**时再加 `02-primitives/button/button.css`(本目录 demo 已引入) |
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -71,6 +71,11 @@
|
|
|
71
71
|
</div>
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
> 底栏右侧放**按钮**也行(dense 列表里更常见),但要额外引入
|
|
75
|
+
> `02-primitives/button/button.css` —— 卡片本身不定义按钮样式。
|
|
76
|
+
> ⚠️ 别放**裸链接**当主操作:文字链接的命中区只有一行高(约 17px),
|
|
77
|
+
> 触屏上点不中;卡片契约第 ③ 条要求可点元素 ≥44px,会直接红。
|
|
78
|
+
|
|
74
79
|
依赖:`01-tokens/tokens.css` + `01-tokens/typography.css`(正文)+
|
|
75
80
|
`01-tokens/page.css`(`.wrap` / `.small` 等页面骨架)。
|
|
76
81
|
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
<link rel="stylesheet" href="../../01-tokens/typography.css">
|
|
10
10
|
<link rel="stylesheet" href="../../01-tokens/page.css">
|
|
11
11
|
<link rel="stylesheet" href="card.css">
|
|
12
|
+
<!-- 底栏里的动作按钮:卡片本身不定义按钮样式,演示页直接引 button.css
|
|
13
|
+
(同一个库里的组件组合,不是复制一份按钮样式)。 -->
|
|
14
|
+
<link rel="stylesheet" href="../button/button.css">
|
|
12
15
|
<style>
|
|
13
16
|
p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.6; }
|
|
14
17
|
.grid3 { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
|
|
@@ -113,6 +116,16 @@ p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.6
|
|
|
113
116
|
<p class="card__desc">用 inset box-shadow 做内描边,不是改 border-width —— 同样为了不跳动。</p>
|
|
114
117
|
</div>
|
|
115
118
|
</div>
|
|
119
|
+
<div class="card card--compact">
|
|
120
|
+
<div class="card__body">
|
|
121
|
+
<h3 class="card__title">compact</h3>
|
|
122
|
+
<p class="card__desc">内边距 24→16、标题降到正文大小。用在"一屏要放十几张"的清单里。</p>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="card__footer">
|
|
125
|
+
<span class="small">更新于 09-12</span>
|
|
126
|
+
<button class="btn btn--md btn--secondary">查看</button>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
116
129
|
</div>
|
|
117
130
|
|
|
118
131
|
<h2 class="rule-bottom">整卡可点:Tab 一下试试</h2>
|
|
@@ -59,6 +59,11 @@
|
|
|
59
59
|
min-height: 44px; /* 触摸目标 44px:视觉方框只有 20px */
|
|
60
60
|
cursor: pointer;
|
|
61
61
|
user-select: none;
|
|
62
|
+
/* 🔴 0.25.2 补:`.choice__hint` 要能落到标签**下方**(README 的承诺)。
|
|
63
|
+
没有 wrap 时,它作为第三个 flex item 会被挤到标签右侧、
|
|
64
|
+
还因为 label 是 flex:1 而被推到最右边 —— 文档写"下方",实际在右边。
|
|
65
|
+
只有存在 hint 时才换行,单子元素的既有布局一个像素都不动。 */
|
|
66
|
+
flex-wrap: wrap;
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
.choice__label {
|
|
@@ -187,6 +192,11 @@
|
|
|
187
192
|
font-size: var(--fs-xs);
|
|
188
193
|
color: var(--text-tertiary);
|
|
189
194
|
line-height: 1.5;
|
|
195
|
+
/* 独占一行,并与标签**文字**左对齐:
|
|
196
|
+
缩进 = 勾选框 20px + label 内 gap(--sp-2)。
|
|
197
|
+
(20px 与 `.choice__mark` 的 width 是同一个值,改一处要连着改。) */
|
|
198
|
+
flex: 1 0 100%;
|
|
199
|
+
margin-inline-start: calc(20px + var(--sp-2));
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
/* ============================================================================
|
|
@@ -63,6 +63,21 @@ p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.6
|
|
|
63
63
|
<p class="small" style="margin-top:var(--sp-3)">
|
|
64
64
|
整个 label 都能点(input 透明铺满了它),但视觉方框只有 20px——<strong>触摸目标是 44px</strong>。
|
|
65
65
|
</p>
|
|
66
|
+
|
|
67
|
+
<div class="choice choice--checkbox">
|
|
68
|
+
<input class="choice__input" type="checkbox" id="c1b" aria-describedby="c1b-hint">
|
|
69
|
+
<label class="choice__label" for="c1b">
|
|
70
|
+
<span class="choice__mark"></span>
|
|
71
|
+
<span>订阅月度报告</span>
|
|
72
|
+
</label>
|
|
73
|
+
<span class="choice__hint" id="c1b-hint">每月 1 日发一封,可随时退订</span>
|
|
74
|
+
</div>
|
|
75
|
+
<p class="small" style="margin-top:var(--sp-3)">
|
|
76
|
+
<code>.choice__hint</code> 是<strong>解释</strong>,不是标签的一部分:
|
|
77
|
+
它排在标签下方、和文字左对齐,并且用 <code>aria-describedby</code> 关联 ——
|
|
78
|
+
读屏念"订阅月度报告,复选框",再补一句说明。
|
|
79
|
+
(写进 label 里会变成名字的一部分,念起来像"订阅月度报告每月1日发一封可随时退订"。)
|
|
80
|
+
</p>
|
|
66
81
|
</div>
|
|
67
82
|
|
|
68
83
|
<h2 class="rule-bottom">indeterminate(第三态)</h2>
|
|
@@ -169,6 +184,29 @@ p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.6
|
|
|
169
184
|
<span class="kbd">↑</span><span class="kbd">↓</span> 选择、<span class="kbd">Enter</span> 确认、Esc 关闭全部保留。
|
|
170
185
|
箭头写了 <code>pointer-events:none</code>,否则它会吃掉点击。
|
|
171
186
|
</p>
|
|
187
|
+
|
|
188
|
+
<!-- 选项文字会换行 / 多选列表:高度必须放开,否则第二行被裁掉 -->
|
|
189
|
+
<div class="field" style="margin-top:var(--sp-5)">
|
|
190
|
+
<label class="field__label" for="s2">导出字段(可多选)</label>
|
|
191
|
+
<div class="select">
|
|
192
|
+
<select class="select__control select__control--auto" id="s2" multiple size="4"
|
|
193
|
+
aria-describedby="s2-hint">
|
|
194
|
+
<option selected>科目编码</option>
|
|
195
|
+
<option selected>科目名称</option>
|
|
196
|
+
<option>期初余额(跨年调整后,含上年重分类的说明会换行)</option>
|
|
197
|
+
<option>本期发生额(借贷方分开列示,便于与总账核对)</option>
|
|
198
|
+
<option>期末余额</option>
|
|
199
|
+
</select>
|
|
200
|
+
</div>
|
|
201
|
+
<span class="field__hint" id="s2-hint">
|
|
202
|
+
按住 <span class="kbd">Ctrl</span> / <span class="kbd">⌘</span> 多选
|
|
203
|
+
</span>
|
|
204
|
+
</div>
|
|
205
|
+
<p class="small" style="margin-top:var(--sp-3)">
|
|
206
|
+
<code>.select__control--auto</code>:固定 44px 高度遇到换行文字会把第二行<strong>裁掉</strong>,
|
|
207
|
+
所以多选列表 / 长选项要把高度放开(<code>height:auto</code> + <code>min-height:44px</code>)。
|
|
208
|
+
这是原生 select,箭头就不需要了 —— 它本来就不是"点开下拉"的交互。
|
|
209
|
+
</p>
|
|
172
210
|
</div>
|
|
173
211
|
|
|
174
212
|
<h2 class="rule-bottom">disabled</h2>
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
| `[data-dr-error]` | 错误容器,`role="alert"` |
|
|
38
38
|
| `[data-dr-summary]` | 选中区间的摘要(如「共 92 天」)|
|
|
39
39
|
| `[data-dr-clear]` | 清除,**不可省** |
|
|
40
|
-
| `.drange--disabled` |
|
|
40
|
+
| `.drange--disabled` | 视觉禁用(预设与清除置灰、hover 不变色)。**它只管观感** —— 真正不可用还要给内部 `input` / `button` 加原生 `disabled`,见 demo 第 3 节 |
|
|
41
41
|
|
|
42
42
|
⚠️ 标记名是 **`data-dr-*`**(`dr` 缩写),不是 `data-drange-*`。
|
|
43
43
|
|
|
@@ -76,6 +76,36 @@
|
|
|
76
76
|
<div class="log" id="log2">(试着填一个 2019 年或 2027 年 ⇒ 会报错)</div>
|
|
77
77
|
</div>
|
|
78
78
|
|
|
79
|
+
<h2 class="rule-bottom">3 · 只读区间:<code>drange--disabled</code> + 原生 <code>disabled</code></h2>
|
|
80
|
+
<p class="note">
|
|
81
|
+
<strong>一件事要拆成两半做,缺一半就假。</strong>
|
|
82
|
+
<br>· <code>.drange--disabled</code> 负责<strong>观感</strong>:预设与清除置灰、hover 不再变色;
|
|
83
|
+
<br>· 原生 <code>disabled</code> 属性负责<strong>行为</strong>:点不动、Tab 跳过、
|
|
84
|
+
读屏念"不可用"。
|
|
85
|
+
<br>只有类名 ⇒ 看着灰但点得动(最糟的一种);只有属性 ⇒ 灰得不对,hover 还会亮。
|
|
86
|
+
</p>
|
|
87
|
+
<div class="pad">
|
|
88
|
+
<div class="drange drange--disabled" id="d3">
|
|
89
|
+
<div class="drange__field">
|
|
90
|
+
<label class="drange__label" for="f3">开始</label>
|
|
91
|
+
<input class="drange__input" type="date" id="f3" data-dr-from value="2026-01-01" disabled>
|
|
92
|
+
</div>
|
|
93
|
+
<span class="drange__sep" aria-hidden="true">→</span>
|
|
94
|
+
<div class="drange__field">
|
|
95
|
+
<label class="drange__label" for="t3">结束</label>
|
|
96
|
+
<input class="drange__input" type="date" id="t3" data-dr-to value="2026-03-31" disabled>
|
|
97
|
+
</div>
|
|
98
|
+
<button class="drange__clear" type="button" data-dr-clear disabled>清除</button>
|
|
99
|
+
<div class="drange__error" data-dr-error role="alert" hidden></div>
|
|
100
|
+
<div class="drange__summary" data-dr-summary aria-live="polite"></div>
|
|
101
|
+
<div class="drange__presets" data-dr-presets></div>
|
|
102
|
+
</div>
|
|
103
|
+
<p class="small">
|
|
104
|
+
这一块是<strong>已发布报表的冻结区间</strong>:读者要看懂区间,但不能改它。
|
|
105
|
+
留着可编辑只会让人以为自己填错了。
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
79
109
|
|
|
80
110
|
|
|
81
111
|
<h2 class="rule-bottom">对比:错写法 vs 本库写法</h2>
|
|
@@ -131,9 +161,19 @@
|
|
|
131
161
|
presets: ['thisQ', 'lastQ', 'lastM', 'yoy'],
|
|
132
162
|
onChange: function (v, ok) {
|
|
133
163
|
log2.textContent = 'from=' + (v.from || '(空)') + ' to=' + (v.to || '(空)') +
|
|
134
|
-
|
|
164
|
+
' valid=' + ok + '(范围 2020-01-01 ~ 2026-12-31)';
|
|
135
165
|
},
|
|
136
166
|
});
|
|
167
|
+
|
|
168
|
+
/* 只读区间:先 create(预设按钮是 JS 生成的),再把内部控件逐个设 disabled。
|
|
169
|
+
⚠️ 顺序不能反 —— 反了的话 bindPresets 会重建一批可点的按钮,
|
|
170
|
+
类名还在、却又能点了("看着灰但点得动"那种假禁用)。 */
|
|
171
|
+
var d3 = document.getElementById('d3');
|
|
172
|
+
DateRange.create(d3, { presets: ['thisQ', 'lastQ'] });
|
|
173
|
+
Array.prototype.forEach.call(
|
|
174
|
+
d3.querySelectorAll('input, button'),
|
|
175
|
+
function (el) { el.disabled = true; }
|
|
176
|
+
);
|
|
137
177
|
})();
|
|
138
178
|
</script>
|
|
139
179
|
</body>
|
|
@@ -124,8 +124,9 @@ python 05-audit/states.py 02-primitives/input/input.css
|
|
|
124
124
|
| `.field__input--sm` | 小尺寸(表格 / 紧凑栏) | 表格行内、侧栏等密度高的场景 |
|
|
125
125
|
| `.field__input--textarea` | 多行:`height:auto` + `min-height:88px` + `padding:--sp-3` + `resize:vertical` | 备注、说明、地址等会换行的输入;直接拿 `.field__input` 配 `<textarea>` 会被 44px 固定高度裁掉 |
|
|
126
126
|
|
|
127
|
-
>
|
|
128
|
-
>
|
|
127
|
+
> 这三档在 demo 的「尺寸与布局」一节里都有实例。
|
|
128
|
+
> 早先这里写的是"demo 里没有演示" —— 那是个坏主意:没有渲染过的 CSS
|
|
129
|
+
> 等于没人验证过(`--textarea` 一旦被别的规则盖掉,谁都不会发现)。
|
|
129
130
|
|
|
130
131
|
## 🔴 移动端必填:inputmode 与 autocomplete
|
|
131
132
|
|
|
@@ -106,6 +106,48 @@
|
|
|
106
106
|
|
|
107
107
|
</div>
|
|
108
108
|
|
|
109
|
+
<h2 class="rule-bottom">尺寸与布局:小尺寸 / 多行 / 标签在左</h2>
|
|
110
|
+
<p class="note">
|
|
111
|
+
这三档不是"好看的选项",是<strong>三种不同的约束</strong>:
|
|
112
|
+
密度(表格行内)、行数(会换行的说明)、方向(标签在左的表单)。
|
|
113
|
+
写错哪一个都是"内容被裁掉"或"标签跑到控件上面"。
|
|
114
|
+
</p>
|
|
115
|
+
<div class="grid">
|
|
116
|
+
|
|
117
|
+
<div class="cell">
|
|
118
|
+
<h3><code>field__input--sm</code></h3>
|
|
119
|
+
<p>视觉 36px、命中区仍 <strong>44px</strong>(min-height 兜底)。用在表格行内、侧栏这类密度高的地方。</p>
|
|
120
|
+
<div class="field">
|
|
121
|
+
<label class="field__label" for="sm1">科目编码</label>
|
|
122
|
+
<input class="field__input field__input--sm" id="sm1" value="1122" autocomplete="off">
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="cell">
|
|
127
|
+
<h3><code>field__input--textarea</code></h3>
|
|
128
|
+
<p>直接拿 <code>.field__input</code> 配 <code><textarea></code> 会被 44px 固定高度<strong>裁掉</strong>。这一档放开高度、留 88px 起,并允许纵向拉伸。</p>
|
|
129
|
+
<div class="field">
|
|
130
|
+
<label class="field__label" for="ta1">备注</label>
|
|
131
|
+
<textarea class="field__input field__input--textarea" id="ta1" rows="3"
|
|
132
|
+
placeholder="差异原因、审批说明…"></textarea>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div class="cell">
|
|
137
|
+
<h3><code>field--row</code></h3>
|
|
138
|
+
<p>标签在左、控件在右,标签宽度固定 88px ⇒ 一列输入框的<strong>起点能对齐</strong>。480px 以下自动回退纵向。</p>
|
|
139
|
+
<div class="field field--row">
|
|
140
|
+
<label class="field__label" for="rw1">账期</label>
|
|
141
|
+
<input class="field__input" id="rw1" value="2026-09" autocomplete="off">
|
|
142
|
+
</div>
|
|
143
|
+
<div class="field field--row">
|
|
144
|
+
<label class="field__label" for="rw2">口径</label>
|
|
145
|
+
<input class="field__input" id="rw2" value="合并报表" autocomplete="off">
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
</div>
|
|
150
|
+
|
|
109
151
|
<h2 class="rule-bottom">对比:常见写法 vs 本库写法</h2>
|
|
110
152
|
<div class="cmp cmp--wide-first">
|
|
111
153
|
<div class="cmp__pane cmp__bad" data-bad=".field__error|count|=0">
|
|
@@ -158,6 +158,119 @@ p { margin: 0 0 var(--sp-3); }
|
|
|
158
158
|
</div>
|
|
159
159
|
</div>
|
|
160
160
|
|
|
161
|
+
<h2 class="rule-top">面板里怎么排:分列 / 表格 / 标题下的一句话</h2>
|
|
162
|
+
<p class="note">
|
|
163
|
+
这一块同时演示四个"藏在面板里"的类,所以<strong>四个都展开</strong>(多开模式):
|
|
164
|
+
<br>· <code>.accordion--flush</code> 去掉外框,融进已有卡片或侧栏
|
|
165
|
+
<br>· <code>accordion__hint</code> 在标题下写"展开后有什么",减少无谓展开
|
|
166
|
+
<br>· <code>cols-2</code> / <code>cols-3</code> / <code>cols-auto</code> 给面板内容分列(≥720px 才分列)
|
|
167
|
+
<br>· <code>.acc-table</code> 面板里的表格:窄屏<strong>横向滚动</strong>,不挤压换行
|
|
168
|
+
</p>
|
|
169
|
+
<div class="accordion accordion--flush" data-accordion data-accordion-multi>
|
|
170
|
+
<div class="accordion__item">
|
|
171
|
+
<h3 class="accordion__heading">
|
|
172
|
+
<button class="accordion__trigger" aria-expanded="true">
|
|
173
|
+
<span class="accordion__label">
|
|
174
|
+
指标口径
|
|
175
|
+
<span class="accordion__hint">展开可看 4 个字段的定义(不展开也能看到这句)</span>
|
|
176
|
+
</span>
|
|
177
|
+
<span class="accordion__marker" aria-hidden="true"></span>
|
|
178
|
+
</button>
|
|
179
|
+
</h3>
|
|
180
|
+
<div class="accordion__panel">
|
|
181
|
+
<div class="accordion__panel-inner cols-2">
|
|
182
|
+
<p><strong>营业总收入</strong>:含主营业务与其他业务收入,不含投资收益。</p>
|
|
183
|
+
<p><strong>营业成本</strong>:与收入同口径,不含期间费用。</p>
|
|
184
|
+
<p><strong>期间费用</strong>:销售、管理、研发、财务四项之和。</p>
|
|
185
|
+
<p><strong>归母净利润</strong>:扣除少数股东损益后的净利润。</p>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div class="accordion__item">
|
|
191
|
+
<h3 class="accordion__heading">
|
|
192
|
+
<button class="accordion__trigger" aria-expanded="true">
|
|
193
|
+
<span class="accordion__label">
|
|
194
|
+
三期对比
|
|
195
|
+
<span class="accordion__hint">三列并排,适合"同类不同期"</span>
|
|
196
|
+
</span>
|
|
197
|
+
<span class="accordion__marker" aria-hidden="true"></span>
|
|
198
|
+
</button>
|
|
199
|
+
</h3>
|
|
200
|
+
<div class="accordion__panel">
|
|
201
|
+
<div class="accordion__panel-inner cols-3">
|
|
202
|
+
<p><strong>2024</strong><br>收入 1,284,300 万元</p>
|
|
203
|
+
<p><strong>2025</strong><br>收入 1,402,110 万元</p>
|
|
204
|
+
<p><strong>2026</strong><br>收入 1,536,880 万元</p>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div class="accordion__item">
|
|
210
|
+
<h3 class="accordion__heading">
|
|
211
|
+
<button class="accordion__trigger" aria-expanded="true">
|
|
212
|
+
<span class="accordion__label">
|
|
213
|
+
自适应列
|
|
214
|
+
<span class="accordion__hint">按内容宽度自动分列,窄了自己塌成一列</span>
|
|
215
|
+
</span>
|
|
216
|
+
<span class="accordion__marker" aria-hidden="true"></span>
|
|
217
|
+
</button>
|
|
218
|
+
</h3>
|
|
219
|
+
<div class="accordion__panel">
|
|
220
|
+
<div class="accordion__panel-inner cols-auto">
|
|
221
|
+
<p>字段:证券代码</p>
|
|
222
|
+
<p>字段:行业分类</p>
|
|
223
|
+
<p>字段:上市日期</p>
|
|
224
|
+
<p>字段:交易所</p>
|
|
225
|
+
<p>字段:审计机构</p>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div class="accordion__item">
|
|
231
|
+
<h3 class="accordion__heading">
|
|
232
|
+
<button class="accordion__trigger" aria-expanded="true">
|
|
233
|
+
<span class="accordion__label">
|
|
234
|
+
附表:近三期数据
|
|
235
|
+
<span class="accordion__hint">表格不换行,窄屏横向滚动</span>
|
|
236
|
+
</span>
|
|
237
|
+
<span class="accordion__marker" aria-hidden="true"></span>
|
|
238
|
+
</button>
|
|
239
|
+
</h3>
|
|
240
|
+
<div class="accordion__panel">
|
|
241
|
+
<div class="accordion__panel-inner">
|
|
242
|
+
<table class="acc-table">
|
|
243
|
+
<caption>营业总收入与同比(单位:万元)</caption>
|
|
244
|
+
<thead>
|
|
245
|
+
<tr>
|
|
246
|
+
<th scope="col">期间</th>
|
|
247
|
+
<th scope="col" class="num">营业总收入</th>
|
|
248
|
+
<th scope="col" class="num">同比</th>
|
|
249
|
+
</tr>
|
|
250
|
+
</thead>
|
|
251
|
+
<tbody>
|
|
252
|
+
<tr>
|
|
253
|
+
<th scope="row">2024 年度</th>
|
|
254
|
+
<td class="num">1,284,300</td>
|
|
255
|
+
<td class="num">—</td>
|
|
256
|
+
</tr>
|
|
257
|
+
<tr>
|
|
258
|
+
<th scope="row">2025 年度</th>
|
|
259
|
+
<td class="num">1,402,110</td>
|
|
260
|
+
<td class="num up">+9.17%</td>
|
|
261
|
+
</tr>
|
|
262
|
+
<tr>
|
|
263
|
+
<th scope="row">2026 年度</th>
|
|
264
|
+
<td class="num">1,536,880</td>
|
|
265
|
+
<td class="num up">+9.61%</td>
|
|
266
|
+
</tr>
|
|
267
|
+
</tbody>
|
|
268
|
+
</table>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
161
274
|
<h2 class="rule-top">结构要求(APG 原文)</h2>
|
|
162
275
|
<div class="box">
|
|
163
276
|
<p><strong>heading 包住 button</strong>,不是 button 套 heading:</p>
|
|
@@ -81,6 +81,23 @@
|
|
|
81
81
|
<h2>4 · 代码与链接</h2>
|
|
82
82
|
<pre><code>const f = (x) => x * 2; // 纯 ES5 时代写法</code></pre>
|
|
83
83
|
<p>详细口径见 <a href="#main">内部数据字典</a>。</p>
|
|
84
|
+
|
|
85
|
+
<h2>5 · 待办清单</h2>
|
|
86
|
+
<p>Markdown 的 <code>- [x]</code> 语法渲染成的样子。它是<strong>正文里的一行</strong>,
|
|
87
|
+
所以只去掉列表圆点、把勾选框对齐到行的左缘,其余跟普通列表一致。</p>
|
|
88
|
+
<ul>
|
|
89
|
+
<li class="task-list-item">
|
|
90
|
+
<label><input type="checkbox" checked disabled> 核对 2026 Q1 收入口径</label>
|
|
91
|
+
</li>
|
|
92
|
+
<li class="task-list-item">
|
|
93
|
+
<label><input type="checkbox" checked disabled> 补齐 26 家公司的三张表</label>
|
|
94
|
+
</li>
|
|
95
|
+
<li class="task-list-item">
|
|
96
|
+
<label><input type="checkbox" disabled> 复核应收账款周转天数</label>
|
|
97
|
+
</li>
|
|
98
|
+
</ul>
|
|
99
|
+
<p><strong>为什么勾选框要带 <code>disabled</code></strong>:这是<em>已渲染的正文</em>,
|
|
100
|
+
不是可填的表单。可点的复选框会让读者以为"改了会保存"。</p>
|
|
84
101
|
</div>
|
|
85
102
|
|
|
86
103
|
|
|
@@ -40,11 +40,21 @@
|
|
|
40
40
|
|
|
41
41
|
| 部件 | 说明 |
|
|
42
42
|
|---|---|
|
|
43
|
-
| `.drawer--right`(默认)/ `.drawer--left` / `.drawer--top` / `.drawer--bottom` | 四个进入方向。左右是侧栏(宽度由
|
|
43
|
+
| `.drawer--right`(默认)/ `.drawer--left` / `.drawer--top` / `.drawer--bottom` | 四个进入方向。左右是侧栏(宽度由 `min(420px, 92vw)` 定),上下是**抽屉式面板**(`min(60vh, 420px)` 高、整宽),适合移动端底部操作区 |
|
|
44
44
|
| `.drawer__head` / `__title` / `__close` | 头部与关闭按钮 |
|
|
45
45
|
| `.drawer__body` | 内容 |
|
|
46
46
|
| `.drawer__foot` | 底部操作区 |
|
|
47
47
|
|
|
48
|
+
> ⚠️ **左右是逻辑轴,不是物理轴**:`--left` = 内联起点、`--right` = 内联终点。
|
|
49
|
+
> LTR 下就是字面意思;`dir="rtl"` 时整个外壳镜像(`--right` 会出现在左边)。
|
|
50
|
+
> 抽屉是"布局家具",整页镜像时必须跟着镜像 —— 只有"指向某侧的箭头"
|
|
51
|
+
> (如 tooltip 的小三角)才该保持物理方向。
|
|
52
|
+
> JS 另外接受 `start` / `end` 两个别名,落到同两个类,这样跨方向写一份配置就够。
|
|
53
|
+
|
|
54
|
+
> 🔴 0.25.2 修:`.drawer--left` / `--bottom` **此前只改了边框和动画,位置没动** ——
|
|
55
|
+
> 两个方向都出现在和默认方向一样的位置上,不报错、控制台干净,
|
|
56
|
+
> 因为四个方位**从来没有判据量过落位**。现在 `drawer-check` 逐个量矩形贴哪条边。
|
|
57
|
+
|
|
48
58
|
## 启用
|
|
49
59
|
|
|
50
60
|
```js
|
|
@@ -26,7 +26,10 @@
|
|
|
26
26
|
统一走令牌后,暗色跟随自动生效。 */
|
|
27
27
|
background: var(--scrim);
|
|
28
28
|
display: flex;
|
|
29
|
-
/*
|
|
29
|
+
/* 默认停在内联终点侧(LTR 右 / RTL 左)。
|
|
30
|
+
🔴 0.25.2 修:原来只有这一条,于是 `--left` / `--bottom` **只改了边框和动画、
|
|
31
|
+
位置一点没动**。1280×800 实测:left 的 left=860(应 0)、bottom 的 top=0(应贴底)。
|
|
32
|
+
两个方向是错的,却控制台干净、契约全绿。⇒ 落位交给各方向的 auto margin / align-self。 */
|
|
30
33
|
justify-content: flex-end;
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -44,11 +47,24 @@
|
|
|
44
47
|
overflow: hidden;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
/* ---------- 四个方向 ----------
|
|
51
|
+
⚠️ 名字沿用 0.x 的物理叫法(left / right),**实现是逻辑轴**:
|
|
52
|
+
`--left` = 内联起点(LTR 左 / RTL 右),`--right` = 内联终点。
|
|
53
|
+
抽屉是"布局家具",整页镜像时必须跟着镜像;只有"指向某侧的箭头"
|
|
54
|
+
(tooltip 的小三角)才该保持物理方向。本文件本来写的就全是逻辑属性
|
|
55
|
+
(border-inline-start/end),语义一直是逻辑的,这里只是让它落地。
|
|
56
|
+
|
|
57
|
+
落位靠抽屉自己的 auto margin / align-self(容器是 flex row):
|
|
58
|
+
主轴 auto margin 吃掉剩余空间(优先于 justify-content);
|
|
59
|
+
交叉轴 align-self 把固定高度的抽屉推到上/下边。
|
|
60
|
+
`--right` 不需要额外规则:容器默认的 `justify-content: flex-end`
|
|
61
|
+
就落在内联终点侧 —— 这也解释了为什么它一直是唯一没坏的方向。 */
|
|
62
|
+
.drawer--left { margin-inline-end: auto; /* 推到内联起点 */
|
|
63
|
+
border-inline-start: 0; border-inline-end: 1px solid var(--border-decor); }
|
|
64
|
+
.drawer--top { align-self: flex-start; width: 100%; height: min(60vh, 420px);
|
|
65
|
+
border-inline-start: 0; border-bottom: 1px solid var(--border-decor); }
|
|
66
|
+
.drawer--bottom { align-self: flex-end; width: 100%; height: min(60vh, 420px);
|
|
67
|
+
border-inline-start: 0; border-top: 1px solid var(--border-decor); }
|
|
52
68
|
|
|
53
69
|
/* ---------- 头 ---------- */
|
|
54
70
|
.drawer__head {
|
|
@@ -188,9 +188,24 @@
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/* 方位 ⇒ 类名。两个理由都用完整字面量,不拼 `'drawer--' + place`:
|
|
192
|
+
① 拼出来的名字源码里 grep 不到,改 CSS 时无法反查谁在用,
|
|
193
|
+
覆盖率门禁也认不出(4 个方位因此长期被记成"只被 README 认领")。
|
|
194
|
+
② 它是**白名单**:`{place:'tp'}` 原本会拼出 `drawer--tp`,没有任何 CSS
|
|
195
|
+
命中 ⇒ 抽屉按默认规则贴右侧、**不报错**。现在未知值退回 right。
|
|
196
|
+
`start`/`end` 是逻辑别名,落到同两个类(见 drawer.css「四个方向」)。 */
|
|
197
|
+
var PLACE_CLASS = {
|
|
198
|
+
right: 'drawer--right', end: 'drawer--right',
|
|
199
|
+
left: 'drawer--left', start: 'drawer--left',
|
|
200
|
+
top: 'drawer--top',
|
|
201
|
+
bottom: 'drawer--bottom'
|
|
202
|
+
};
|
|
203
|
+
|
|
191
204
|
function open(opt) {
|
|
192
205
|
opt = opt || {};
|
|
193
206
|
var place = opt.place || 'right';
|
|
207
|
+
var placeCls = PLACE_CLASS[place];
|
|
208
|
+
if (!placeCls) placeCls = PLACE_CLASS.right;
|
|
194
209
|
|
|
195
210
|
/* ⭐ 记住"打开那一刻的焦点"—— 关闭时要还回去。
|
|
196
211
|
(必须在插入 DOM **之前**记录,否则会记到新节点上。)
|
|
@@ -206,7 +221,7 @@
|
|
|
206
221
|
if (opt.label) host.setAttribute('aria-label', opt.label);
|
|
207
222
|
|
|
208
223
|
var d = document.createElement('aside');
|
|
209
|
-
d.className = 'drawer
|
|
224
|
+
d.className = 'drawer ' + placeCls;
|
|
210
225
|
d.setAttribute('role', 'dialog');
|
|
211
226
|
d.setAttribute('aria-modal', 'true');
|
|
212
227
|
if (!d.id) d.id = 'drawer-' + (new Date()).getTime();
|
|
@@ -26,11 +26,13 @@
|
|
|
26
26
|
<button class="dd__btn" data-dd-btn aria-haspopup="menu" aria-expanded="false">
|
|
27
27
|
<span>操作</span><span class="dd__caret" aria-hidden="true"></span>
|
|
28
28
|
</button>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
|
|
29
|
+
<!-- ⚠️ 必须是 ul + li:JS 按 `li` 逐个补 role="menuitem" / tabindex="-1"。
|
|
30
|
+
写成 <div>/<button> 的列表,键盘导航会整个失效(没有可被 JS 接管的项)。 -->
|
|
31
|
+
<ul class="dd__menu" data-dd-menu hidden>
|
|
32
|
+
<li data-value="edit">编辑</li>
|
|
33
|
+
<li data-dd-sep></li>
|
|
34
|
+
<li data-value="del">删除</li>
|
|
35
|
+
</ul>
|
|
34
36
|
</div>
|
|
35
37
|
```
|
|
36
38
|
|
|
@@ -38,9 +40,9 @@
|
|
|
38
40
|
|---|---|
|
|
39
41
|
| `.dd` | 根 |
|
|
40
42
|
| `.dd__btn` / `[data-dd-btn]` | 触发按钮 |
|
|
41
|
-
| `.dd__menu` / `[data-dd-menu]` |
|
|
42
|
-
| `.dd__item` |
|
|
43
|
-
| `.dd__sep` / `[data-dd-sep]` |
|
|
43
|
+
| `.dd__menu` / `[data-dd-menu]` | 菜单本体(`<ul>`),**必需** |
|
|
44
|
+
| `.dd__item` | 菜单项(`<li>`),带 `data-value`。**类名由 JS 自动补**,不用手写 |
|
|
45
|
+
| `.dd__sep` / `[data-dd-sep]` | 分隔线。只写 `data-dd-sep` 即可:`role="separator"` + `aria-hidden` + `.dd__sep` 都由 JS 补(漏写类名时它渲染高度是 **0px**,两组菜单项直接贴着) |
|
|
44
46
|
| `.dd__check` | 多选勾选位 |
|
|
45
47
|
| `.dd--end` | 菜单右对齐 |
|
|
46
48
|
|
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
</ul>
|
|
62
62
|
</div>
|
|
63
63
|
<div class="log" id="log">(选中项会显示在这里)</div>
|
|
64
|
+
<p class="small">
|
|
65
|
+
菜单里的那条<strong>分隔线</strong>只写 <code>data-dd-sep</code> 就行:
|
|
66
|
+
<code>role="separator"</code> 与 <code>.dd__sep</code> 由组件补。
|
|
67
|
+
方向键会跳过它 —— 分隔线不是可选项,让它能被"选中"是错的。
|
|
68
|
+
</p>
|
|
64
69
|
</div>
|
|
65
70
|
|
|
66
71
|
<h2>2 · 带勾选(选中性不只靠颜色)</h2>
|