@greypan/web-ui 3.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.CN.md +495 -125
  2. package/README.md +504 -125
  3. package/dist/_virtual/{_@oxc-project_runtime@0.140.0 → _@oxc-project_runtime@0.146.0}/helpers/esm/decorate.js +1 -1
  4. package/dist/assets/glass.js +1 -1
  5. package/dist/assets/glass.js.map +1 -1
  6. package/dist/assets/menu-portal.js +1 -1
  7. package/dist/assets/menu-portal.js.map +1 -1
  8. package/dist/assets/overlay-motion.js +1 -1
  9. package/dist/assets/overlay-motion.js.map +1 -1
  10. package/dist/assets/toast-containers.js +1 -1
  11. package/dist/assets/toast-containers.js.map +1 -1
  12. package/dist/components/autocomplete/index.d.ts +12 -12
  13. package/dist/components/autocomplete/index.js +162 -111
  14. package/dist/components/autocomplete/index.js.map +1 -1
  15. package/dist/components/autocomplete/style.js +1 -1
  16. package/dist/components/autocomplete/style.js.map +1 -1
  17. package/dist/components/avatar/index.d.ts +0 -1
  18. package/dist/components/avatar/index.js +8 -13
  19. package/dist/components/avatar/index.js.map +1 -1
  20. package/dist/components/back-top/index.js +2 -2
  21. package/dist/components/back-top/index.js.map +1 -1
  22. package/dist/components/back-top/style.js +1 -1
  23. package/dist/components/back-top/style.js.map +1 -1
  24. package/dist/components/badge/index.d.ts +1 -0
  25. package/dist/components/badge/index.js +12 -14
  26. package/dist/components/badge/index.js.map +1 -1
  27. package/dist/components/button/index.d.ts +2 -0
  28. package/dist/components/button/index.js +52 -38
  29. package/dist/components/button/index.js.map +1 -1
  30. package/dist/components/button/style.js +1 -1
  31. package/dist/components/button/style.js.map +1 -1
  32. package/dist/components/button-group/index.d.ts +1 -2
  33. package/dist/components/button-group/index.js +21 -23
  34. package/dist/components/button-group/index.js.map +1 -1
  35. package/dist/components/button-group/style.js +1 -1
  36. package/dist/components/button-group/style.js.map +1 -1
  37. package/dist/components/checkbox/index.d.ts +4 -7
  38. package/dist/components/checkbox/index.js +56 -38
  39. package/dist/components/checkbox/index.js.map +1 -1
  40. package/dist/components/checkbox/style.js +1 -1
  41. package/dist/components/checkbox/style.js.map +1 -1
  42. package/dist/components/checkbox-group/index.d.ts +4 -10
  43. package/dist/components/checkbox-group/index.js +74 -60
  44. package/dist/components/checkbox-group/index.js.map +1 -1
  45. package/dist/components/collapse/index.d.ts +66 -0
  46. package/dist/components/collapse/index.js +159 -0
  47. package/dist/components/collapse/index.js.map +1 -0
  48. package/dist/components/collapse/style.js +6 -0
  49. package/dist/components/collapse/style.js.map +1 -0
  50. package/dist/components/context-menu/index.d.ts +29 -0
  51. package/dist/components/context-menu/index.js +168 -53
  52. package/dist/components/context-menu/index.js.map +1 -1
  53. package/dist/components/dialog/index.d.ts +6 -0
  54. package/dist/components/dialog/index.js +34 -13
  55. package/dist/components/dialog/index.js.map +1 -1
  56. package/dist/components/dialog/style.js +1 -1
  57. package/dist/components/dialog/style.js.map +1 -1
  58. package/dist/components/drawer/index.d.ts +45 -0
  59. package/dist/components/drawer/index.js +270 -56
  60. package/dist/components/drawer/index.js.map +1 -1
  61. package/dist/components/drawer/style.js +1 -1
  62. package/dist/components/drawer/style.js.map +1 -1
  63. package/dist/components/dropdown/index.d.ts +2 -0
  64. package/dist/components/dropdown/index.js +24 -14
  65. package/dist/components/dropdown/index.js.map +1 -1
  66. package/dist/components/dropdown-divider/index.js +1 -1
  67. package/dist/components/dropdown-header/index.js +1 -1
  68. package/dist/components/dropdown-header/style.js +1 -1
  69. package/dist/components/dropdown-header/style.js.map +1 -1
  70. package/dist/components/dropdown-item/index.js +3 -2
  71. package/dist/components/dropdown-item/index.js.map +1 -1
  72. package/dist/components/dropdown-item/style.js +1 -1
  73. package/dist/components/dropdown-item/style.js.map +1 -1
  74. package/dist/components/empty/index.d.ts +1 -0
  75. package/dist/components/empty/index.js +24 -22
  76. package/dist/components/empty/index.js.map +1 -1
  77. package/dist/components/empty/style.js +1 -1
  78. package/dist/components/empty/style.js.map +1 -1
  79. package/dist/components/icon/index.js +1 -1
  80. package/dist/components/index.d.ts +1 -0
  81. package/dist/components/index.js +21 -20
  82. package/dist/components/input/index.d.ts +2 -3
  83. package/dist/components/input/index.js +62 -52
  84. package/dist/components/input/index.js.map +1 -1
  85. package/dist/components/input/style.js +1 -1
  86. package/dist/components/input/style.js.map +1 -1
  87. package/dist/components/input-number/index.d.ts +2 -3
  88. package/dist/components/input-number/index.js +58 -38
  89. package/dist/components/input-number/index.js.map +1 -1
  90. package/dist/components/input-number/style.js +1 -1
  91. package/dist/components/input-number/style.js.map +1 -1
  92. package/dist/components/layout/index.d.ts +76 -3
  93. package/dist/components/layout/index.js +250 -39
  94. package/dist/components/layout/index.js.map +1 -1
  95. package/dist/components/layout/style.js +1 -1
  96. package/dist/components/layout/style.js.map +1 -1
  97. package/dist/components/option/index.js +1 -1
  98. package/dist/components/option/style.js +1 -1
  99. package/dist/components/option/style.js.map +1 -1
  100. package/dist/components/popover/index.d.ts +2 -1
  101. package/dist/components/popover/index.js +14 -8
  102. package/dist/components/popover/index.js.map +1 -1
  103. package/dist/components/popover/style.js +1 -1
  104. package/dist/components/popover/style.js.map +1 -1
  105. package/dist/components/radio/index.d.ts +4 -7
  106. package/dist/components/radio/index.js +51 -37
  107. package/dist/components/radio/index.js.map +1 -1
  108. package/dist/components/radio/style.js +1 -1
  109. package/dist/components/radio/style.js.map +1 -1
  110. package/dist/components/radio-group/index.d.ts +4 -10
  111. package/dist/components/radio-group/index.js +70 -52
  112. package/dist/components/radio-group/index.js.map +1 -1
  113. package/dist/components/segmented/index.d.ts +14 -12
  114. package/dist/components/segmented/index.js +132 -54
  115. package/dist/components/segmented/index.js.map +1 -1
  116. package/dist/components/segmented/style.js +1 -1
  117. package/dist/components/segmented/style.js.map +1 -1
  118. package/dist/components/segmented-trigger/index.d.ts +1 -2
  119. package/dist/components/segmented-trigger/index.js +23 -21
  120. package/dist/components/segmented-trigger/index.js.map +1 -1
  121. package/dist/components/segmented-trigger/style.js +1 -1
  122. package/dist/components/segmented-trigger/style.js.map +1 -1
  123. package/dist/components/select/index.d.ts +13 -8
  124. package/dist/components/select/index.js +114 -75
  125. package/dist/components/select/index.js.map +1 -1
  126. package/dist/components/select/style.js +1 -1
  127. package/dist/components/select/style.js.map +1 -1
  128. package/dist/components/slider/index.d.ts +6 -7
  129. package/dist/components/slider/index.js +99 -64
  130. package/dist/components/slider/index.js.map +1 -1
  131. package/dist/components/slider/style.js +1 -1
  132. package/dist/components/slider/style.js.map +1 -1
  133. package/dist/components/spinner/index.d.ts +0 -2
  134. package/dist/components/spinner/index.js +14 -13
  135. package/dist/components/spinner/index.js.map +1 -1
  136. package/dist/components/spinner/style.js +1 -1
  137. package/dist/components/spinner/style.js.map +1 -1
  138. package/dist/components/svg-draw-lines/index.js +1 -1
  139. package/dist/components/switch/index.d.ts +13 -6
  140. package/dist/components/switch/index.js +102 -41
  141. package/dist/components/switch/index.js.map +1 -1
  142. package/dist/components/switch/style.js +1 -1
  143. package/dist/components/switch/style.js.map +1 -1
  144. package/dist/components/textarea/index.d.ts +5 -6
  145. package/dist/components/textarea/index.js +74 -67
  146. package/dist/components/textarea/index.js.map +1 -1
  147. package/dist/components/textarea/style.js +1 -1
  148. package/dist/components/textarea/style.js.map +1 -1
  149. package/dist/components/theme/index.js +1 -1
  150. package/dist/components/theme/style.js +1 -1
  151. package/dist/components/theme/style.js.map +1 -1
  152. package/dist/components/toast/style.js +1 -1
  153. package/dist/components/toast/style.js.map +1 -1
  154. package/dist/components/toast/toast.js +12 -12
  155. package/dist/components/toast/toast.js.map +1 -1
  156. package/dist/components/tooltip/index.js +3 -3
  157. package/dist/components/tooltip/index.js.map +1 -1
  158. package/dist/components/tooltip/style.js +1 -1
  159. package/dist/components/tooltip/style.js.map +1 -1
  160. package/dist/icons/generated/heroicons-arrow-down-16-solid.d.ts +6 -0
  161. package/dist/icons/generated/heroicons-arrow-up-16-solid.d.ts +6 -0
  162. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.d.ts +6 -0
  163. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js +10 -0
  164. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js.map +1 -0
  165. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.d.ts +6 -0
  166. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js +10 -0
  167. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js.map +1 -0
  168. package/dist/icons/generated/lucide-clapperboard.d.ts +6 -0
  169. package/dist/icons/generated/lucide-clapperboard.js +10 -0
  170. package/dist/icons/generated/lucide-clapperboard.js.map +1 -0
  171. package/dist/icons/generated/lucide-code.d.ts +6 -0
  172. package/dist/icons/generated/lucide-code.js +10 -0
  173. package/dist/icons/generated/lucide-code.js.map +1 -0
  174. package/dist/icons/generated/lucide-ellipsis-vertical.d.ts +6 -0
  175. package/dist/icons/generated/lucide-ellipsis-vertical.js +10 -0
  176. package/dist/icons/generated/lucide-ellipsis-vertical.js.map +1 -0
  177. package/dist/icons/generated/lucide-eye.d.ts +6 -0
  178. package/dist/icons/generated/lucide-eye.js +10 -0
  179. package/dist/icons/generated/lucide-eye.js.map +1 -0
  180. package/dist/icons/generated/lucide-headphones.d.ts +6 -0
  181. package/dist/icons/generated/lucide-headphones.js +10 -0
  182. package/dist/icons/generated/lucide-headphones.js.map +1 -0
  183. package/dist/icons/generated/lucide-link.d.ts +6 -0
  184. package/dist/icons/generated/lucide-link.js +10 -0
  185. package/dist/icons/generated/lucide-link.js.map +1 -0
  186. package/dist/icons/generated/lucide-list-filter.d.ts +6 -0
  187. package/dist/icons/generated/lucide-list-filter.js +10 -0
  188. package/dist/icons/generated/lucide-list-filter.js.map +1 -0
  189. package/dist/icons/generated/lucide-list-restart.d.ts +6 -0
  190. package/dist/icons/generated/lucide-list-restart.js +10 -0
  191. package/dist/icons/generated/lucide-list-restart.js.map +1 -0
  192. package/dist/icons/generated/lucide-pen-line.d.ts +6 -0
  193. package/dist/icons/generated/lucide-pen-line.js +10 -0
  194. package/dist/icons/generated/lucide-pen-line.js.map +1 -0
  195. package/dist/icons/generated/lucide-play.d.ts +6 -0
  196. package/dist/icons/generated/lucide-play.js +10 -0
  197. package/dist/icons/generated/lucide-play.js.map +1 -0
  198. package/dist/icons/generated/lucide-sliders-horizontal.d.ts +6 -0
  199. package/dist/icons/generated/lucide-sliders-horizontal.js +10 -0
  200. package/dist/icons/generated/lucide-sliders-horizontal.js.map +1 -0
  201. package/dist/icons/generated/lucide-tag.d.ts +6 -0
  202. package/dist/icons/generated/lucide-tag.js +10 -0
  203. package/dist/icons/generated/lucide-tag.js.map +1 -0
  204. package/dist/icons/generated/tabler-sort-ascending-letters.d.ts +6 -0
  205. package/dist/icons/generated/tabler-sort-ascending-letters.js +10 -0
  206. package/dist/icons/generated/tabler-sort-ascending-letters.js.map +1 -0
  207. package/dist/icons/index.d.ts +15 -0
  208. package/dist/icons/index.js +18 -3
  209. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js +1 -3
  210. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -1
  211. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +2 -1
  212. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -1
  213. package/dist/shared/events/user-change.js.map +1 -1
  214. package/dist/shared/form-association/index.js +41 -0
  215. package/dist/shared/form-association/index.js.map +1 -0
  216. package/dist/shared/gesture/drag-gesture.js +133 -0
  217. package/dist/shared/gesture/drag-gesture.js.map +1 -0
  218. package/dist/shared/gesture/physics.js +45 -0
  219. package/dist/shared/gesture/physics.js.map +1 -0
  220. package/dist/shared/group-management/index.js +111 -0
  221. package/dist/shared/group-management/index.js.map +1 -0
  222. package/dist/shared/menu-portal/menu-portal.js +22 -10
  223. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  224. package/dist/shared/menu-portal/menu-tree.js +22 -7
  225. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  226. package/dist/shared/option-portal/index.js +65 -0
  227. package/dist/shared/option-portal/index.js.map +1 -0
  228. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  229. package/dist/shared/overlay/nested-drawer-layers.js +55 -0
  230. package/dist/shared/overlay/nested-drawer-layers.js.map +1 -0
  231. package/dist/shared/overlay/overlay.js +1 -1
  232. package/dist/shared/overlay/overlay.js.map +1 -1
  233. package/dist/shared/overlay/portal.js +47 -13
  234. package/dist/shared/overlay/portal.js.map +1 -1
  235. package/dist/shared/overlay/presence.js.map +1 -1
  236. package/dist/shared/visible-area/index.js +69 -0
  237. package/dist/shared/visible-area/index.js.map +1 -0
  238. package/package.json +8 -4
package/README.CN.md CHANGED
@@ -31,6 +31,29 @@ import '@greypan/web-ui'
31
31
 
32
32
  ## 框架集成
33
33
 
34
+ ### 跨框架 API 约定
35
+
36
+ `web-ui-*` 元素暴露三面 API,**DOM / JavaScript API 是事实来源**:Property 使用 camelCase,Attribute 使用
37
+ kebab-case,Event 使用 kebab-case。
38
+
39
+ | 表面 | 命名 | 示例 |
40
+ | --------- | ---------- | --------------------------------------------- |
41
+ | Property | camelCase | `open`、`sidebarCollapsed`、`noScrollLock` |
42
+ | Attribute | kebab-case | `open`、`sidebar-collapsed`、`no-scroll-lock` |
43
+ | Event | kebab-case | `open-change`、`sidebar-collapsed-change` |
44
+
45
+ - **布尔 Attribute** 遵循原生 HTML 存在语义:不存在 → `false`,存在 → `true`。框架绑定写入的
46
+ `disabled="false"` 是字符串 `"false"`,会被视为 true——**动态布尔必须绑定 Property**(camelCase),
47
+ 才能把 `false` 写成真实 property。
48
+ - **Vue**:动态绑定必须走 **Property**,使用 camelCase 属性名(`:sidebarCollapsed="x"`、`:open="x"`)。
49
+ kebab-case 绑定(`:sidebar-collapsed="x"`)会被写成字符串 attribute,无法表达 `false`,请使用 camelCase
50
+ property。`.prop` 修饰符只在 camelCase 属性名下有效(`:sidebarCollapsed.prop="x"`)。String/Number 值可
51
+ 保留 kebab-case attribute(`:max-height="120"`)。带值控件(`web-ui-input`、`web-ui-select`、
52
+ `web-ui-autocomplete` 等)支持 `v-model`,编译为元素的 `value` property + `input` 事件。
53
+ - **React**:React 19 对 custom element 的 props 直接写 DOM property,因此使用 camelCase props
54
+ (`open={open}`、`noScrollLock`、`value={value}`)。**不要把复杂数据(对象、数组)放进 attribute 字符串**,
55
+ 一律绑定为 property。kebab-case JSX prop 在 custom element 上会写成 attribute。
56
+
34
57
  ### React
35
58
 
36
59
  需要 `@types/react >= 19` 作为可选 peer 依赖。
@@ -127,6 +150,20 @@ import '@greypan/web-ui/types/vue'
127
150
  </template>
128
151
  ```
129
152
 
153
+ Boolean 属性必须用 **camelCase 属性名**绑定,而不是 kebab-case attribute。Vue 会把 attribute 绑定写成字符串,
154
+ 而布尔 attribute 遵循「存在即 true」的语义——所以 `:sidebar-collapsed="false"` 会写出字符串 `"false"`,被当作 true。
155
+ 改用 camelCase 属性名(`:sidebarCollapsed="false"`,或 `.prop` 修饰符)会让 Vue 直接写 DOM property:
156
+
157
+ ```vue
158
+ <web-ui-layout
159
+ header-glow
160
+ :sidebarCollapsed="sidebarCollapsed"
161
+ :sidebarOpen="sidebarOpen"
162
+ @sidebar-collapsed-change="sidebarCollapsed = $event.detail.collapsed"
163
+ @sidebar-open-change="sidebarOpen = $event.detail.open"
164
+ />
165
+ ```
166
+
130
167
  Vue 事件类型零 cast:带值组件上的 `@input`/`@change` 解析到组件 emit,`$event.target` 即为组件实例,
131
168
  `value`/`checked` 直接读取;kebab-case 事件(如 `open-change`)的 `$event.detail` 保持 `CustomEvent` 载荷类型。
132
169
  命名 handler 用 `WebUiEvent<WebUiXxx, 'change'>` 标注;当变量或泛型表示事件名时,使用
@@ -143,45 +180,79 @@ ARIA 属性同样必须显式支持:使用组件文档化的命名属性,而
143
180
  `click`、`input`、`change` 等浏览器 composed 原生事件仍是主要交互 API。`open-change` 等 kebab-case 自定义事件
144
181
  仅描述用户操作导致的组件状态变化;程序化赋值 property 不会触发它们。
145
182
 
183
+ ### Cursor 行为
184
+
185
+ 交互控件使用原生箭头光标,而不是手型光标;disabled 控件使用 `not-allowed`。Slider、Switch 和 Segmented 在
186
+ hover 与按压反馈阶段保持箭头光标,仅在真实拖拽进行中切换为 `grabbing`。专用拖拽把手和 resize 控件保留各自
187
+ 的专用光标。Cursor 样式位于 Shadow DOM 内,应用层普通选择器无法覆盖。
188
+
189
+ ### 受控状态语义
190
+
191
+ `web-ui-*` 元素没有单一的「受控」契约;按交互性质分成三套状态模型,各组件族取其一。不要假设不同组件上的
192
+ `controlled` 含义相同。
193
+
194
+ **仅用户来源事件(所有 `open` 类组件:collapse、popover、dropdown、tooltip、dialog、drawer、back-top)。**
195
+ `*-change` 事件(`open-change` 等)只在用户来源的切换时派发;程序化赋值(`el.open = true`)或命令式调用
196
+ (`show()`、`close()`、`toggle()`)从不派发。组件**自管理**自己的 `open` 值,除非你在外部协调——你可以监听事件
197
+ 并写回自己的状态,但组件不要求、也不等待这个写回。
198
+
199
+ **请求-写回模式(仅 dialog 与 drawer 的 `controlled`)。**
200
+ `controlled=true` 时,用户关闭操作(Escape、backdrop、内置关闭、拖拽释放)只*请求* `open=false`;组件不改自己的
201
+ 状态,保持打开,直到消费者写回 `open=false`。这是模态确认语义——关对话框/抽屉通常是需要消费者批准的操作(未保存
202
+ 表单、需确认),与即时开合不同,不能由组件自行提交。只有这两个模态组件使用该模式;即时开合家族(collapse、popover、
203
+ dropdown、tooltip)不需要它。
204
+
205
+ **原生表单模型(input、textarea、input-number、select、checkbox、radio、switch、autocomplete)。**
206
+ 控件内部自管理 value/checked 状态;用户交互立即翻转,然后派发原生 `input`/`change` 事件。程序化赋值
207
+ (`el.checked = true`)覆盖内部状态。这与原生 `<input type="checkbox">` 一致——**没有 `controlled` prop 是因为
208
+ 值总是可读可写**,React/Vue 层自备受控包装。若翻转的持久化需要外部往返(例如开关应只有 API 调用成功后保持开启),
209
+ 使用**乐观更新**路径:立即翻转、监听 `change`、请求期间设 `loading`(阻断后续交互并显示 spinner),失败后回写
210
+ property(`el.checked = false`)并提示 toast。翻转先于批准的窗口被接受;不提供「批准前不翻转」的 `controlled` prop。
211
+
212
+ ### 表单关联控件
213
+
214
+ 所有表单控件均参与原生 `FormData`、约束校验、`form.reset()` 和浏览器表单状态恢复。控件会在**首次连接且声明式属性完成初始化后**捕获一次重置默认值;之后的运行时 property 更新不会改写该默认值。祖先 `fieldset` 的禁用状态会禁用交互和校验,但不会改写控件公开的 `disabled` 属性。对于 checkbox/radio group,父 group 是提交、重置和状态恢复的唯一所有者;被管理的子项不会独立提交或恢复状态。
215
+
146
216
  ## 所有组件
147
217
 
148
- | 分类 | 组件 |
149
- | --------------- | --------------------------------------------------------- |
150
- | **表单控件** | [`<web-ui-input>`](#web-ui-input) |
151
- | | [`<web-ui-textarea>`](#web-ui-textarea) |
152
- | | [`<web-ui-input-number>`](#web-ui-input-number) |
153
- | | [`<web-ui-select>`](#web-ui-select) |
154
- | | [`<web-ui-autocomplete>`](#web-ui-autocomplete) |
155
- | | [`<web-ui-slider>`](#web-ui-slider) |
156
- | | [`<web-ui-checkbox>`](#web-ui-checkbox) |
157
- | | [`<web-ui-radio>`](#web-ui-radio) |
158
- | | [`<web-ui-switch>`](#web-ui-switch) |
159
- | | [`<web-ui-segmented>`](#web-ui-segmented) |
160
- | | [`<web-ui-checkbox-group>`](#web-ui-checkbox-group) |
161
- | | [`<web-ui-radio-group>`](#web-ui-radio-group) |
162
- | **按钮** | [`<web-ui-button>`](#web-ui-button) |
163
- | | [`<web-ui-button-group>`](#web-ui-button-group) |
164
- | **浮层 / 模态** | [`<web-ui-dialog>`](#web-ui-dialog) |
165
- | | [`<web-ui-drawer>`](#web-ui-drawer) |
166
- | **浮动** | [`<web-ui-popover>`](#web-ui-popover) |
167
- | | [`<web-ui-tooltip>`](#web-ui-tooltip) |
168
- | | [`<web-ui-context-menu>`](#web-ui-context-menu) |
169
- | **菜单** | [`<web-ui-dropdown>`](#web-ui-dropdown) |
170
- | | [`<web-ui-dropdown-item>`](#web-ui-dropdown-item) |
171
- | | [`<web-ui-dropdown-divider>`](#web-ui-dropdown-divider) |
172
- | | [`<web-ui-dropdown-header>`](#web-ui-dropdown-header) |
173
- | **数据展示** | [`<web-ui-avatar>`](#web-ui-avatar) |
174
- | | [`<web-ui-badge>`](#web-ui-badge) |
175
- | | [`<web-ui-empty>`](#web-ui-empty) |
176
- | | [`<web-ui-icon>`](#web-ui-icon) |
177
- | | [`<web-ui-spinner>`](#web-ui-spinner) |
178
- | **布局与工具** | [`<web-ui-layout>`](#web-ui-layout) |
179
- | | [`<web-ui-back-top>`](#web-ui-back-top) |
180
- | | [`<web-ui-svg-draw-lines>`](#web-ui-svg-draw-lines) |
181
- | | [`<web-ui-theme>`](#web-ui-theme) |
182
- | **通知** | [`<web-ui-toast>`](#web-ui-toast) |
183
- | **子项** | [`<web-ui-option>`](#web-ui-option) |
184
- | | [`<web-ui-segmented-trigger>`](#web-ui-segmented-trigger) |
218
+ | 分类 | 组件 |
219
+ | --------------------- | --------------------------------------------------------- |
220
+ | **表单控件** | [`<web-ui-input>`](#web-ui-input) |
221
+ | | [`<web-ui-textarea>`](#web-ui-textarea) |
222
+ | | [`<web-ui-input-number>`](#web-ui-input-number) |
223
+ | | [`<web-ui-select>`](#web-ui-select) |
224
+ | | [`<web-ui-autocomplete>`](#web-ui-autocomplete) |
225
+ | | [`<web-ui-slider>`](#web-ui-slider) |
226
+ | | [`<web-ui-checkbox>`](#web-ui-checkbox) |
227
+ | | [`<web-ui-radio>`](#web-ui-radio) |
228
+ | | [`<web-ui-switch>`](#web-ui-switch) |
229
+ | | [`<web-ui-segmented>`](#web-ui-segmented) |
230
+ | | [`<web-ui-checkbox-group>`](#web-ui-checkbox-group) |
231
+ | | [`<web-ui-radio-group>`](#web-ui-radio-group) |
232
+ | **按钮** | [`<web-ui-button>`](#web-ui-button) |
233
+ | | [`<web-ui-button-group>`](#web-ui-button-group) |
234
+ | **浮层 / 模态** | [`<web-ui-dialog>`](#web-ui-dialog) |
235
+ | | [`<web-ui-drawer>`](#web-ui-drawer) |
236
+ | **文档流 Disclosure** | [`<web-ui-collapse>`](#web-ui-collapse) |
237
+ | **浮动** | [`<web-ui-popover>`](#web-ui-popover) |
238
+ | | [`<web-ui-tooltip>`](#web-ui-tooltip) |
239
+ | | [`<web-ui-context-menu>`](#web-ui-context-menu) |
240
+ | **菜单** | [`<web-ui-dropdown>`](#web-ui-dropdown) |
241
+ | | [`<web-ui-dropdown-item>`](#web-ui-dropdown-item) |
242
+ | | [`<web-ui-dropdown-divider>`](#web-ui-dropdown-divider) |
243
+ | | [`<web-ui-dropdown-header>`](#web-ui-dropdown-header) |
244
+ | **数据展示** | [`<web-ui-avatar>`](#web-ui-avatar) |
245
+ | | [`<web-ui-badge>`](#web-ui-badge) |
246
+ | | [`<web-ui-empty>`](#web-ui-empty) |
247
+ | | [`<web-ui-icon>`](#web-ui-icon) |
248
+ | | [`<web-ui-spinner>`](#web-ui-spinner) |
249
+ | **布局与工具** | [`<web-ui-layout>`](#web-ui-layout) |
250
+ | | [`<web-ui-back-top>`](#web-ui-back-top) |
251
+ | | [`<web-ui-svg-draw-lines>`](#web-ui-svg-draw-lines) |
252
+ | | [`<web-ui-theme>`](#web-ui-theme) |
253
+ | **通知** | [`<web-ui-toast>`](#web-ui-toast) |
254
+ | **子项** | [`<web-ui-option>`](#web-ui-option) |
255
+ | | [`<web-ui-segmented-trigger>`](#web-ui-segmented-trigger) |
185
256
 
186
257
  ## API 参考
187
258
 
@@ -193,46 +264,52 @@ ARIA 属性同样必须显式支持:使用组件文档化的命名属性,而
193
264
 
194
265
  文本输入框,支持清除按钮和前后缀插槽。
195
266
 
196
- | 属性 | 类型 | 默认值 | 说明 |
197
- | ------------- | --------- | -------- | --------------- |
198
- | `value` | `string` | `''` | 输入值 |
199
- | `type` | `string` | `'text'` | HTML input 类型 |
200
- | `placeholder` | `string` | `''` | 占位文本 |
201
- | `name` | `string` | `''` | 表单字段名 |
202
- | `disabled` | `boolean` | `false` | 禁用状态 |
203
- | `readonly` | `boolean` | `false` | 只读状态 |
204
- | `required` | `boolean` | `false` | 必填校验 |
205
- | `clearable` | `boolean` | `false` | 显示清除按钮 |
206
- | `full` | `boolean` | `false` | 全宽 |
207
- | `borderless` | `boolean` | `false` | 无边框 |
208
- | `aria-label` | `string` | — | 无障碍标签 |
267
+ | 属性 | 类型 | 默认值 | 说明 |
268
+ | ------------- | --------- | -------- | --------------------------------------------------------------------- |
269
+ | `value` | `string` | `''` | 输入值 |
270
+ | `type` | `string` | `'text'` | HTML input 类型 |
271
+ | `placeholder` | `string` | `''` | 占位文本 |
272
+ | `name` | `string` | `''` | 表单字段名 |
273
+ | `disabled` | `boolean` | `false` | 禁用状态 |
274
+ | `readonly` | `boolean` | `false` | 只读状态 |
275
+ | `required` | `boolean` | `false` | 必填校验 |
276
+ | `clearable` | `boolean` | `false` | 显示清除按钮 |
277
+ | `full` | `boolean` | `false` | 全宽 |
278
+ | `borderless` | `boolean` | `false` | ghost 形态:移除边框、背景与阴影;保留 padding、高度度量与 focus ring |
279
+ | `aria-label` | `string` | — | 无障碍标签 |
209
280
 
210
281
  **事件:** `input`, `change`, `focus`, `blur`
211
282
 
212
283
  **插槽:** `prefix`, `default`, `suffix`
213
284
 
285
+ **CSS 自定义属性:**
286
+
287
+ | 属性 | 默认值 | 说明 |
288
+ | ------------------------- | -------------------------------- | ------------ |
289
+ | `--wui-input-clear-color` | `var(--wui-color-text-tertiary)` | 清除按钮颜色 |
290
+
214
291
  #### `<web-ui-textarea>`
215
292
 
216
293
  多行文本输入框,支持自动调整高度。
217
294
 
218
- | 属性 | 类型 | 默认值 | 说明 |
219
- | ----------------- | --------- | ------- | ---------------------------------- |
220
- | `value` | `string` | `''` | 输入值 |
221
- | `placeholder` | `string` | `''` | 占位文本 |
222
- | `rows` | `number` | `3` | 显示行数 |
223
- | `name` | `string` | `''` | 表单字段名 |
224
- | `disabled` | `boolean` | `false` | 禁用状态 |
225
- | `readonly` | `boolean` | `false` | 只读状态 |
226
- | `required` | `boolean` | `false` | 必填校验 |
227
- | `clearable` | `boolean` | `false` | 显示清除按钮 |
228
- | `full` | `boolean` | `false` | 全宽 |
229
- | `borderless` | `boolean` | `false` | 无边框 |
230
- | `autosize` | `boolean` | `false` | 自动调整高度 |
231
- | `max-height` | `number` | `0` | 自动高度上限(px),`0` 表示不限制 |
232
- | `minlength` | `number` | — | 最小长度校验 |
233
- | `maxlength` | `number` | — | 最大长度校验 |
234
- | `aria-label` | `string` | — | 无障碍标签 |
235
- | `aria-labelledby` | `string` | — | 无障碍标签引用 |
295
+ | 属性 | 类型 | 默认值 | 说明 |
296
+ | ----------------- | --------- | ------- | --------------------------------------------------------------------- |
297
+ | `value` | `string` | `''` | 输入值 |
298
+ | `placeholder` | `string` | `''` | 占位文本 |
299
+ | `rows` | `number` | `3` | 显示行数 |
300
+ | `name` | `string` | `''` | 表单字段名 |
301
+ | `disabled` | `boolean` | `false` | 禁用状态 |
302
+ | `readonly` | `boolean` | `false` | 只读状态 |
303
+ | `required` | `boolean` | `false` | 必填校验 |
304
+ | `clearable` | `boolean` | `false` | 显示清除按钮 |
305
+ | `full` | `boolean` | `false` | 全宽 |
306
+ | `borderless` | `boolean` | `false` | ghost 形态:移除边框、背景与阴影;保留 padding、高度度量与 focus ring |
307
+ | `autosize` | `boolean` | `false` | 自动调整高度 |
308
+ | `max-height` | `number` | `0` | 自动高度上限(px),`0` 表示不限制 |
309
+ | `minlength` | `number` | — | 最小长度校验 |
310
+ | `maxlength` | `number` | — | 最大长度校验 |
311
+ | `aria-label` | `string` | — | 无障碍标签 |
312
+ | `aria-labelledby` | `string` | — | 无障碍标签引用 |
236
313
 
237
314
  **事件:** `input`, `change`, `focus`, `blur`
238
315
 
@@ -240,6 +317,13 @@ ARIA 属性同样必须显式支持:使用组件文档化的命名属性,而
240
317
 
241
318
  **插槽:** `prefix`, `suffix`
242
319
 
320
+ **CSS 自定义属性:**
321
+
322
+ | 属性 | 默认值 | 说明 |
323
+ | ---------------------------- | -------------------------------- | ------------ |
324
+ | `--wui-textarea-width` | `200px` | 文本域宽度 |
325
+ | `--wui-textarea-clear-color` | `var(--wui-color-text-tertiary)` | 清除按钮颜色 |
326
+
243
327
  #### `<web-ui-input-number>`
244
328
 
245
329
  数字输入框,支持步进按钮和键盘操作。
@@ -282,32 +366,60 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
282
366
 
283
367
  子 `<web-ui-option>` 通过 `option-register` / `option-unregister` 注册。支持 ArrowDown/ArrowUp/Enter/Escape 键盘导航。
284
368
 
369
+ **CSS 自定义属性:**
370
+
371
+ | 属性 | 默认值 | 说明 |
372
+ | ------------------------- | ---------------------------------- | --------------------- |
373
+ | `--wui-select-max-width` | `500px` | 下拉框最大宽度 |
374
+ | `--wui-select-max-height` | `200px` | 下拉滚动区域最大高度 |
375
+ | `--wui-overlay-min-width` | `200px` | 下拉框最小宽度 |
376
+ | `--wui-select-bg-hover` | `--wui-color-surface-glass-hover` | Trigger 悬停背景 |
377
+ | `--wui-select-bg-active` | `--wui-color-surface-glass-active` | Trigger 按下/打开背景 |
378
+
379
+ Portal 面板创建时会镜像 host 上解析后的这些变量;更新 host 后需重新打开 Portal 面板才会生效。
380
+
285
381
  #### `<web-ui-autocomplete>`
286
382
 
287
383
  可输入并过滤候选的单值选择器。
288
384
 
289
- | 属性 | 类型 | 默认值 | 说明 |
290
- | ------------------ | ---------------------------------- | ------------ | ------------------------------------------------------- |
291
- | `value` | `string` | `''` | 当前输入文本(表单值) |
292
- | `selected-value` | `string` | `''` | 输入文本精确匹配 label 的 option 的 value(派生,只读) |
293
- | `placeholder` | `string` | `''` | 占位文本 |
294
- | `filter` | `'none' \| 'prefix' \| 'contains'` | `'contains'` | 候选过滤模式(按 option label 匹配) |
295
- | `name` | `string` | `''` | 表单字段名 |
296
- | `disabled` | `boolean` | `false` | 禁用状态 |
297
- | `readonly` | `boolean` | `false` | 只读状态(不可输入、不可展开下拉) |
298
- | `required` | `boolean` | `false` | 必填校验 |
299
- | `portal` | `boolean` | `false` | 在主题浮层容器中渲染 |
300
- | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
301
- | `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | 显式 Portal 容器 |
302
- | `aria-label` | `string` | — | 无障碍名称 |
303
- | `aria-labelledby` | `string` | — | 无障碍名称引用 |
385
+ | 属性 | 类型 | 默认值 | 说明 |
386
+ | -------------------- | ---------------------------------- | ------------ | --------------------------------------------------------------------- |
387
+ | `value` | `string` | `''` | 当前输入文本(表单值) |
388
+ | `selected-value` | `string` | `''` | 输入文本精确匹配 label 的非禁用 option 的 value(派生,只读) |
389
+ | `placeholder` | `string` | `''` | 占位文本 |
390
+ | `borderless` | `boolean` | `false` | ghost 形态:移除边框、背景与阴影;保留 padding、高度度量与 focus ring |
391
+ | `filter` | `'none' \| 'prefix' \| 'contains'` | `'contains'` | 候选过滤模式(按 option label 匹配) |
392
+ | `name` | `string` | `''` | 表单字段名 |
393
+ | `disabled` | `boolean` | `false` | 禁用状态 |
394
+ | `readonly` | `boolean` | `false` | 只读状态(不可输入、不可展开下拉) |
395
+ | `required` | `boolean` | `false` | 必填校验 |
396
+ | `allow-custom-value` | `boolean` | `false` | 允许 Enter 提交不在候选中的 custom value |
397
+ | `portal` | `boolean` | `false` | 在主题浮层容器中渲染 |
398
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
399
+ | `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | 显式 Portal 容器 |
400
+ | `aria-label` | `string` | — | 无障碍名称 |
401
+ | `aria-labelledby` | `string` | — | 无障碍名称引用 |
304
402
 
305
403
  **事件:** `input`, `change`, `focus`, `blur`, `open-change` (`CustomEvent<{ open: boolean }>`)
306
404
 
307
- **插槽:** `default`(投影 `<web-ui-option>` 元素)
405
+ **插槽:** `default`(投影 `<web-ui-option>` 元素)、`empty`(替换无匹配空态;默认回退为“无匹配选项”)
308
406
 
309
407
  键入时按 label 过滤候选(`contains` 或 `prefix`,`none` 关闭过滤)。选择 option 时文本回填为该项 label,`selected-value` 暴露该项的 value;`change` 在选择提交时触发。支持 ArrowDown/ArrowUp/Enter/Escape 键盘导航。
310
408
 
409
+ 启用 `allow-custom-value` 后,无匹配且无活动 option 时,Enter 会把当前输入原文作为 custom value 提交并关闭面板;`change` 会触发,`selected-value` 保持为空。组件不会自动创建 option,也不会 trim 原文。命中禁用 option 的文本不会绕过禁用语义,也不会派生为已选 option。
410
+
411
+ 通过 `<div slot="empty">…</div>` 自定义静态、非交互的空态内容。Portal 渲染时该节点会迁入浮层,关闭后恢复到宿主。
412
+
413
+ **CSS 自定义属性:**
414
+
415
+ | 属性 | 默认值 | 说明 |
416
+ | ------------------------------- | ------- | -------------------- |
417
+ | `--wui-autocomplete-max-width` | `500px` | 下拉框最大宽度 |
418
+ | `--wui-autocomplete-max-height` | `200px` | 下拉滚动区域最大高度 |
419
+ | `--wui-overlay-min-width` | `200px` | 下拉框最小宽度 |
420
+
421
+ Portal 面板创建时会镜像 host 上解析后的这些变量;更新 host 后需重新打开 Portal 面板才会生效。
422
+
311
423
  #### `<web-ui-slider>`
312
424
 
313
425
  范围滑块,支持刻度标记和垂直方向。
@@ -330,6 +442,18 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
330
442
 
331
443
  支持 ArrowLeft/Right/Up/Down、Home/End、PageUp/PageDown 键盘导航。使用 pointer capture 处理鼠标、触控笔和触摸交互。
332
444
 
445
+ **CSS 自定义属性:**
446
+
447
+ | 属性 | 默认值 | 说明 |
448
+ | ------------------------------ | ----------------------------------- | ------------ |
449
+ | `--wui-slider-width` | `200px` | 滑块宽度 |
450
+ | `--wui-slider-vertical-height` | `200px` | 垂直滑块高度 |
451
+ | `--wui-slider-height` | `var(--wui-slider-track-size, 6px)` | 轨道厚度 |
452
+ | `--wui-slider-track-size` | `6px` | 轨道尺寸 |
453
+ | `--wui-slider-thumb-width` | `30px` | 滑块宽度 |
454
+ | `--wui-slider-thumb-height` | `20px` | 滑块高度 |
455
+ | `--wui-slider-marks-inset` | `0` | 刻度内缩 |
456
+
333
457
  #### `<web-ui-checkbox>`
334
458
 
335
459
  单个复选框。
@@ -442,16 +566,16 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
442
566
 
443
567
  样式化按钮,支持多种变体和加载状态。
444
568
 
445
- | 属性 | 类型 | 默认值 | 说明 |
446
- | ------------ | ------------------------------------------------------------ | ---------- | ----------------------------------- |
447
- | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | 按钮变体 |
448
- | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | 内部按钮类型;非法值回退为 `button` |
449
- | `disabled` | `boolean` | `false` | 禁用状态 |
450
- | `loading` | `boolean` | `false` | 加载旋转动画 |
451
- | `full` | `boolean` | `false` | 全宽 |
452
- | `icon` | `boolean` | `false` | 纯图标模式 |
453
- | `size` | `string` | `''` | 尺寸格式 `高度` 或 `高度x宽度` |
454
- | `aria-label` | `string` | — | 无障碍标签(委托给内部按钮) |
569
+ | 属性 | 类型 | 默认值 | 说明 |
570
+ | ------------ | ------------------------------------------------------------ | ---------- | ------------------------------------------------------------- |
571
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | 按钮变体 |
572
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | 内部按钮类型;非法值回退为 `button` |
573
+ | `disabled` | `boolean` | `false` | 禁用状态 |
574
+ | `loading` | `boolean` | `false` | 加载旋转动画;与 `icon` 组合时 spinner 替换图标内容 |
575
+ | `full` | `boolean` | `false` | 全宽 |
576
+ | `icon` | `boolean` | `false` | 纯图标模式 |
577
+ | `size` | `string` | `''` | 按钮高度(px);icon 模式下同时设为 min-width,默认保持正方形 |
578
+ | `aria-label` | `string` | — | 无障碍标签(委托给内部按钮) |
455
579
 
456
580
  **事件:** 标准 `click`
457
581
 
@@ -461,6 +585,20 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
461
585
 
462
586
  禁用和加载状态阻止 `click` 事件。
463
587
 
588
+ `icon` 与 `loading` 同时开启时,按钮只渲染 spinner,默认插槽图标不投影。默认 icon 几何保持正方形,`full` 或显式 width 除外。
589
+
590
+ **CSS 自定义属性:**
591
+
592
+ | 属性 | 默认值 | 说明 |
593
+ | ------------------------ | ------------- | ---------------------- |
594
+ | `--wui-button-width` | `max-content` | 按钮宽度 |
595
+ | `--wui-button-px` | `12px` | 水平内边距 |
596
+ | `--wui-button-gap` | `8px` | 前缀/默认/后缀插槽间距 |
597
+ | `--wui-button-color` | 随 variant | 按钮文字颜色 |
598
+ | `--wui-button-bg` | 随 variant | 按钮背景颜色 |
599
+ | `--wui-button-bg-hover` | 随 variant | 悬停背景颜色 |
600
+ | `--wui-button-bg-active` | 随 variant | 按下背景颜色 |
601
+
464
602
  #### `<web-ui-button-group>`
465
603
 
466
604
  按钮组,管理子按钮布局和方向。
@@ -471,7 +609,7 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
471
609
 
472
610
  **插槽:** `default`(投影 `<web-ui-button>` 元素)
473
611
 
474
- 向子按钮传递 `direction` 属性。
612
+ 以内部派生的视觉上下文控制按钮组方向,不改写子按钮属性。
475
613
 
476
614
  ---
477
615
 
@@ -481,41 +619,105 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
481
619
 
482
620
  模态对话框,使用原生 `<dialog>` 的 `showModal()`。
483
621
 
484
- | 属性 | 类型 | 默认值 | 说明 |
485
- | ------------------- | --------- | ------- | -------------------- |
486
- | `open` | `boolean` | `false` | 对话框可见性 |
487
- | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
488
- | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
489
- | `no-escape-close` | `boolean` | `false` | 禁止按 Escape 关闭 |
622
+ | 属性 | 类型 | 默认值 | 说明 |
623
+ | ------------------- | --------- | ------- | --------------------------------------------------------- |
624
+ | `open` | `boolean` | `false` | 对话框可见性 |
625
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
626
+ | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
627
+ | `no-escape-close` | `boolean` | `false` | 禁止按 Escape 关闭 |
628
+ | `controlled` | `boolean` | `false` | Escape 与遮罩仅请求 `open=false`,由 Consumer 回写 `open` |
490
629
 
491
- **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
630
+ **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)。启用 `controlled` 后,Escape 与遮罩点击仅请求 `open=false`,Consumer 写入 `open=false` 前对话框保持打开。程序化 API(`showModal()`/`close()`/直接赋值 `open`)不受影响,始终直通且不派发事件。原生 dialog 关闭(如表单 `method="dialog"`)会被恢复为受控打开状态并重新发出同一请求。
492
631
 
493
632
  **插槽:** `body`, `title`, `default`, `footer`
494
633
 
495
634
  **方法:** `showModal()`, `close()`
496
635
 
497
- 使用原生 `<dialog>`,`@cancel` 阻止默认关闭行为。除非存在 `no-escape-close`,否则 Escape 调用 `close()`;除非存在 `no-backdrop-close`,否则点击遮罩关闭。
636
+ 使用原生 `<dialog>`,`@cancel` 阻止默认关闭行为。除非存在 `no-escape-close`,否则 Escape 调用 `close()`;除非存在 `no-backdrop-close`,否则点击遮罩关闭。启用 `controlled` 后,两者都只派发关闭请求而不自关闭。
637
+
638
+ **CSS 自定义属性:**
639
+
640
+ | 属性 | 默认值 | 说明 |
641
+ | ------------------------- | ---------------------------------- | ------------------------------------------------ |
642
+ | `--wui-dialog-max-width` | `360px` | 对话框最大宽度 |
643
+ | `--wui-dialog-overlay-bg` | `var(--wui-color-backdrop)` | 遮罩背景色 |
644
+ | `--wui-dialog-bg` | `var(--wui-color-surface-overlay)` | 玻璃卡片背景色,回退到 `rgb(246 246 246 / 0.88)` |
498
645
 
499
646
  #### `<web-ui-drawer>`
500
647
 
501
- 侧边抽屉,使用原生 `<dialog>` 并自带关闭动画。
648
+ 侧边抽屉,使用原生 `<dialog>` 并自带关闭动画。非 headless 模式下抽屉渲染为四周留边的浮动圆角卡片(与 layout sidebar 的卡片语言一致),弹性拖拽的位移表现为边距变化而非缺口。
502
649
 
503
- | 属性 | 类型 | 默认值 | 说明 |
504
- | ------------------- | ---------------------------------------- | --------- | -------------------------------- |
505
- | `open` | `boolean` | `false` | 抽屉可见性 |
506
- | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | 滑入方向 |
507
- | `heading` | `string` | `''` | 标题文字(无 header 插槽时显示) |
508
- | `closable` | `boolean` | `false` | 显示关闭按钮 |
509
- | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
510
- | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
650
+ | 属性 | 类型 | 默认值 | 说明 |
651
+ | ------------------- | ---------------------------------------- | --------- | ---------------------------------------------------- |
652
+ | `open` | `boolean` | `false` | 抽屉可见性 |
653
+ | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | 滑入方向 |
654
+ | `heading` | `string` | `''` | 标题文字(无 header 插槽时显示) |
655
+ | `closable` | `boolean` | `false` | 显示关闭按钮 |
656
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
657
+ | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
658
+ | `controlled` | `boolean` | `false` | 用户关闭仅请求 `open=false`,由 Consumer 回写 `open` |
659
+ | `headless` | `boolean` | `false` | 仅保留 overlay 行为,默认插槽不渲染内置抽屉 UI |
660
+ | `dialog-label` | `string` | `''` | 内部原生 dialog 的可访问名称;headless 模式必须提供 |
661
+ | `draggable` | `boolean` | `false` | 打开时在抽屉内缘显示 drag bar,支持拖拽关闭手势 |
511
662
 
512
- **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
663
+ **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)。启用 `controlled` 后,Escape、遮罩、内置关闭按钮和拖拽松手仅请求 `open=false`;Consumer 写入 `open=false` 前抽屉保持打开。程序化 API(`show()`/`close()`/直接赋值 `open`)不受影响,始终直通且不派发事件。若原生 dialog 在请求等待期间关闭,组件会恢复其打开的 top layer 状态并发出同一关闭请求。嵌套 drawer 时,内层 `open-change` 会 composed 冒泡穿过外层根,按 `event.target` 区分。
513
664
 
514
- **插槽:** `header`, `default`, `footer`
665
+ **插槽:** `header`, `default`, `footer`;启用 `headless` 时仅渲染 `default` 插槽。
515
666
 
516
667
  **方法:** `show()`, `close()`
517
668
 
518
- 关闭时保留原生 dialog 的 top layer,待 `--wui-duration-drawer` 过渡完成(默认 280ms)后调用 `dialog.close()`。Escape 始终走此关闭路径;`no-backdrop-close` 仅控制遮罩点击。
669
+ `headless` 保留原生 dialog、遮罩、placement 动画、Escape/遮罩关闭行为和滚动锁定,但不渲染内置 glass 主体、header、关闭按钮或 footer;Consumer 负责完整定义默认插槽内容的样式,并且必须提供 `dialog-label`,确保原生 dialog 具有可访问名称。
670
+
671
+ 关闭时保留原生 dialog 的 top layer,待退出过渡完成后调用 `dialog.close()`。Escape 始终走此关闭路径;`no-backdrop-close` 仅控制遮罩点击。
672
+
673
+ **拖拽关闭:** 启用 `draggable` 后,打开的抽屉在内缘显示灰色胶囊 drag bar(`right` 在左缘、`left` 在右缘、`top` 在下缘、`bottom` 在上缘)。拖拽实时跟手(遮罩透明度按比例淡出);松手时位移超过抽屉尺寸约 1/3 或快速甩动即弹簧关闭,否则弹回打开位,方向随 placement 适配。启用 `controlled` 后,超过阈值松手仅派发 `open-change(false)`;抽屉在闭合位短暂等待(120ms 回写窗口),Consumer 拒绝或超时未回写时弹回打开位。不支持拖拽打开——关闭态的抽屉在原生 dialog 之外没有任何渲染物。`prefers-reduced-motion` 下松手即时到位,不播放弹簧动画。
674
+
675
+ **CSS 自定义属性:**
676
+
677
+ | 属性 | 默认值 | 说明 |
678
+ | ------------------------- | ---------------------------------- | -------------------------------------------------- |
679
+ | `--wui-drawer-width` | `320px` | 抽屉宽度 |
680
+ | `--wui-drawer-height` | `300px` | 抽屉高度(上/下) |
681
+ | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | 抽屉背景色 |
682
+ | `--wui-drawer-radius` | `28px` | 浮动卡片圆角(非 headless) |
683
+ | `--wui-drawer-inset` | `8px` | 浮动卡片视口留边(非 headless);置 `0` 为贴边几何 |
684
+ | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | 遮罩背景色 |
685
+
686
+ ---
687
+
688
+ ### 文档流展开收起
689
+
690
+ #### `<web-ui-collapse>`
691
+
692
+ 文档流内的展开收起容器,带高度(或宽度)过渡动画。单元素双插槽;无 portal、无滚动锁定、无焦点管理。
693
+
694
+ | 属性 | 类型 | 默认值 | 说明 |
695
+ | -------------- | --------- | ------- | ----------------------------------------------------------------------------------- |
696
+ | `open` | `boolean` | `false` | 展开状态;交互时自管理,`open-change` 仅用户来源时派发 |
697
+ | `disabled` | `boolean` | `false` | 忽略 trigger 点击并在 trigger 元素上设 `aria-disabled`;已展开内容保持现状 |
698
+ | `horizontal` | `boolean` | `false` | 沿宽度而非高度动画 |
699
+ | `keep-mounted` | `boolean` | `false` | 关闭稳态以 `inert` 保留在 0fr 轨道内(滚动位置与布局可测量),而非内部容器 `hidden` |
700
+
701
+ **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)。仅用户来源的切换(trigger 点击)派发;程序化写入(`open`、`show()`、`close()`、`toggle()`)不派发。嵌套时内层 `open-change` 会冒泡穿过外层根(composed 事件),按 `event.target` 区分。
702
+
703
+ **插槽:** `default`(trigger)+ `content`(折叠内容)
704
+
705
+ **方法:** `show()`、`close()`、`toggle()`
706
+
707
+ ```html
708
+ <web-ui-collapse>
709
+ <button type="button">点击切换</button>
710
+ <div slot="content">折叠内容</div>
711
+ </web-ui-collapse>
712
+ ```
713
+
714
+ 初始即带 `open` attribute 时直接落稳态,不播动画。支持嵌套 collapse。
715
+
716
+ **trigger 语义:** 交互语义完全来自 default slot 放入的元素——原生 `<button>`、`<web-ui-button>` 或其他可交互元素原生提供 Enter/Space 激活与焦点。collapse 把 `aria-expanded` / `aria-controls`(指向内容轨道)与 `aria-disabled` 回写到 trigger slot 的首个 assigned element。trigger 请使用可交互元素:纯 `<span>` 可点击但没有键盘/焦点语义。
717
+
718
+ **关闭稳态语义:** 消费者的 light DOM 永不移动或卸载。默认关闭稳态在内部内容容器上设 `hidden`;`keep-mounted` 时内部容器标记 `inert`,保留在收起轨道内可测量。
719
+
720
+ **已知限制:** `horizontal` 动画期间内容随宽度变化 reflow。
519
721
 
520
722
  ---
521
723
 
@@ -543,6 +745,8 @@ ArrowUp/ArrowDown 键增减数值。空输入或 `-` 在提交时被忽略,值
543
745
 
544
746
  Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式点击切换。Manual 模式仅响应命令式调用。
545
747
 
748
+ **trigger ARIA:** 开合状态回写到 trigger 元素:`aria-expanded` 与 `aria-controls`(指向面板)设在 `trigger` slot 的首个 assigned element 上(包装结构上的同名属性保留兼容)。trigger slot 请放入可交互元素(原生 button、`web-ui-button`)。
749
+
546
750
  #### `<web-ui-tooltip>`
547
751
 
548
752
  工具提示,支持指针和焦点触发。
@@ -563,7 +767,14 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
563
767
 
564
768
  **插槽:** `default`(触发器)、`content`(提示面板)
565
769
 
566
- `open` 是受控可见性属性。指针/焦点触发会更新它,直接设置也会同步本地或 Portal 面板。第一个 Tooltip 显示后,相邻 Tooltip 会立即切换;其余 pointer/focus 触发使用延迟计时器。
770
+ `open` 是自管理的可见性属性。指针/焦点触发会更新它,直接赋值 property 也会同步本地或 Portal 面板;`open-change` 仅用户来源的开关时派发。第一个 Tooltip 显示后,相邻 Tooltip 会立即切换;其余 pointer/focus 触发使用延迟计时器。
771
+
772
+ **CSS 自定义属性:**
773
+
774
+ | 属性 | 默认值 | 说明 |
775
+ | ------------------------- | ------- | ------------ |
776
+ | `--wui-tooltip-max-width` | `240px` | 提示最大宽度 |
777
+ | `--wui-tooltip-font-size` | `13px` | 提示字号 |
567
778
 
568
779
  #### `<web-ui-context-menu>`
569
780
 
@@ -582,6 +793,8 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
582
793
 
583
794
  通过 `contextmenu` 事件打开。菜单项:`web-ui-dropdown-item`、`web-ui-dropdown-divider`、`web-ui-dropdown-header`。支持键盘导航和子菜单 hover。
584
795
 
796
+ 菜单打开期间,消费者可以安全地使用条件渲染(如 Vue `v-if`)切换、移动或删除菜单项,无需重新插入到宿主元素;portal 内的变更会自动 reconcile,关闭时框架锚点随元素迁回宿主,保证后续框架更新正常。
797
+
585
798
  ---
586
799
 
587
800
  ### 菜单
@@ -607,6 +820,8 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
607
820
 
608
821
  菜单项:`web-ui-dropdown-item`、`web-ui-dropdown-divider`、`web-ui-dropdown-header`。子菜单在 `web-ui-dropdown-item` 上通过 `submenu` 属性启用。完整键盘导航支持。
609
822
 
823
+ **trigger ARIA:** `aria-haspopup="menu"`、`aria-expanded` 与 `aria-controls`(指向根菜单面板)回写到 `trigger` slot 的首个 assigned element。trigger slot 请放入可交互元素。
824
+
610
825
  #### `<web-ui-dropdown-item>`
611
826
 
612
827
  菜单项。
@@ -677,6 +892,17 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
677
892
 
678
893
  **插槽:** `default`(标题,覆盖 `title` 属性)、`icon`、`description`、`action`
679
894
 
895
+ **CSS 自定义属性:**
896
+
897
+ | 属性 | 默认值 | 说明 |
898
+ | ----------------------------------- | ----------- | ------------------ |
899
+ | `--wui-empty-min-height` | `240px` | 最小高度(medium) |
900
+ | `--wui-empty-padding` | `32px 24px` | 内边距(medium) |
901
+ | `--wui-empty-icon-size` | `56px` | 图标容器尺寸 |
902
+ | `--wui-empty-content-width` | `480px` | 标题/描述最大宽度 |
903
+ | `--wui-empty-title-font-size` | `16px` | 标题字号(medium) |
904
+ | `--wui-empty-description-font-size` | `14px` | 描述字号(medium) |
905
+
680
906
  #### `<web-ui-icon>`
681
907
 
682
908
  图标渲染组件。接受 Iconify 数据对象。
@@ -695,6 +921,12 @@ import { lucideLoaderCircle } from '@greypan/web-ui/icons'
695
921
  html`<web-ui-icon .icon=${lucideLoaderCircle} spin />`
696
922
  ```
697
923
 
924
+ **CSS 自定义属性:**
925
+
926
+ | 属性 | 默认值 | 说明 |
927
+ | ------------------ | --------- | -------- |
928
+ | `--wui-icon-color` | `inherit` | 图标颜色 |
929
+
698
930
  #### `<web-ui-spinner>`
699
931
 
700
932
  加载旋转器。
@@ -727,14 +959,43 @@ WebUiSpinner.hide() // 隐藏
727
959
 
728
960
  #### `<web-ui-layout>`
729
961
 
730
- 页面布局网格。
962
+ 响应式页面布局:支持可选全宽 Banner、桌面端可折叠侧边栏,以及移动端 headless drawer。页面本身滚动;Banner 滚出后,桌面端 sidebar 和 header 固定在视口内。
963
+
964
+ | 属性 | 类型 | 默认值 | 说明 |
965
+ | ------------------- | --------- | --------- | -------------------------------------------------------------- |
966
+ | `sidebar-collapsed` | `boolean` | `false` | 桌面端侧边栏受控折叠状态 |
967
+ | `sidebar-open` | `boolean` | `false` | 移动端侧边栏 Drawer 受控打开状态 |
968
+ | `header-glow` | `boolean` | `false` | 在 header 插槽内容背后显示装饰性晕染 |
969
+ | `sidebar-width` | `string` | `'240px'` | 桌面端和移动端展开时的侧边栏宽度 |
970
+ | `collapsed-width` | `string` | `'72px'` | 桌面端折叠时的侧边栏宽度 |
971
+ | `sidebar-resizable` | `boolean` | `false` | 启用桌面端侧边栏右边缘拖拽调整宽度 |
972
+ | `sidebar-min-width` | `string` | — | 拖拽调整的下限(px);默认回退到 `collapsed-width` |
973
+ | `sidebar-max-width` | `string` | — | 拖拽调整的上限(px);钳制在视口一半以内,内置上限优先于配置值 |
974
+
975
+ **事件:** `sidebar-collapsed-change`(`CustomEvent<{ collapsed: boolean }>`)用于请求更新桌面端折叠状态;`sidebar-open-change`(`CustomEvent<{ open: boolean }>`)用于请求更新移动端 Drawer 打开状态;`sidebar-width-change`(`CustomEvent<{ width: string }>`)用于请求在拖拽调整结束后更新侧边栏宽度。Consumer 必须将请求值回写到对应的受控属性。
976
+
977
+ **侧边栏调整宽度:** 启用 `sidebar-resizable` 后,桌面端侧边栏右边缘会出现调整手柄(折叠状态下隐藏)。悬停或拖拽时显示 3px 宽的强调色垂直线和 `col-resize` 光标。拖拽时实时更新宽度(禁止过渡动画,限制在 `[min, max]` 和视口范围内);释放时触发 `sidebar-width-change` 事件并携带最终像素宽度,控制权交还给 `sidebar-width` 属性等待 Consumer 回写。`pointercancel` 会恢复属性控制的宽度且不触发事件。手柄同时支持键盘(WAI-ARIA splitter 模式):聚焦后用 ←/→ 以 16px 步进调整(Shift 加速到 64px),Home/End 跳到 min/max,Enter 以同一 `sidebar-width-change` 请求提交,Escape 撤回未提交的调整。移动端 Drawer 始终通过其内置 `draggable` 抽屉支持拖拽关闭。
978
+
979
+ | 插槽 | 说明 |
980
+ | --------- | ------------------------------------------------------------ |
981
+ | `banner` | 位于布局主体上方的可选全宽 Banner |
982
+ | `header` | 内容区的 sticky header |
983
+ | `sidebar` | 侧边栏卡片内容;内部固定区域与滚动容器均由 Consumer 自行定义 |
984
+ | `default` | 主内容区 |
985
+ | `tabbar` | 底部 tabbar |
986
+
987
+ `web-ui-layout` 只约束侧边栏卡片的可用空间并管理桌面端 Toggle,不创建侧边栏 scrollport。若仅让侧边栏的一部分滚动,请将 `sidebar` 插槽根节点设为 `height: 100%; min-height: 0` 的 flex column,再将 `overflow-y: auto` 设置到目标子元素。这样 Consumer 可自行固定头部和底部,无需额外的公共 slot。
988
+
989
+ 在 `640px` 及以下,侧边栏会切换为 headless 模式的 `web-ui-drawer`。Consumer 内容仍渲染在相同的圆角侧边栏卡片中,移动端 Toggle 以 glass 变体位于 header 行内。其左缩进默认 `8px`,可通过 `--wui-layout-mobile-toggle-inset` 与 Consumer 自身的 header 内边距对齐。
731
990
 
732
- | 插槽 | 说明 |
733
- | --------- | ---------- |
734
- | `header` | 顶部横幅 |
735
- | `default` | 主内容区 |
736
- | `sidebar` | 侧边栏 |
737
- | `tabbar` | 底部标签栏 |
991
+ `header-glow` 会在 header 插槽内容和移动端 Toggle 的背后添加 `pointer-events: none` 的装饰性晕染。它属于 Header 背景而非前景层,因此插槽内容始终位于其上方;可通过 `--wui-layout-header-glow-color` 覆盖颜色,默认值为 `--wui-color-page`。晕染浓度和范围由内部变量 `--wui-layout-header-glow-height`(默认 `150%`)控制;增大可加强覆盖,减小则更柔和。布局层级顺序为 Header(`10`)< Auxiliary(`20`)< Banner(`30`)< Tabbar(`40`)< Sidebar(`50`)。
992
+
993
+ **CSS 自定义属性:**
994
+
995
+ | 属性 | 默认值 | 说明 |
996
+ | ---------------------------------- | ------ | ------------------------------------ |
997
+ | `--wui-layout-sidebar-radius` | `24px` | 侧边栏卡片圆角(桌面端和移动端共用) |
998
+ | `--wui-layout-mobile-toggle-inset` | `8px` | 移动端 header Toggle 的左缩进 |
738
999
 
739
1000
  #### `<web-ui-back-top>`
740
1001
 
@@ -751,10 +1012,21 @@ WebUiSpinner.hide() // 隐藏
751
1012
 
752
1013
  **方法:** `toTop()`
753
1014
 
754
- **定位:** `scrollTarget` 为 `window` 时按钮固定在视口角落;为 `HTMLElement` 时需将元素放置在容器内部,按钮通过 `position: sticky` 悬浮于容器底部角落。偏移量沿用 `--web-ui-back-top-top/right/bottom/left` CSS 变量。
1015
+ **定位:** `scrollTarget` 为 `window` 时按钮固定在视口角落;为 `HTMLElement` 时需将元素放置在容器内部,按钮通过 `position: sticky` 悬浮于容器底部角落。偏移量沿用 `--wui-back-top-top/right/bottom/left` CSS 变量。
755
1016
 
756
1017
  角色:`button`,键盘 Enter 触发回到顶部。
757
1018
 
1019
+ **CSS 自定义属性:**
1020
+
1021
+ | 属性 | 默认值 | 说明 |
1022
+ | ------------------------- | -------------------------------- | -------- |
1023
+ | `--wui-back-top-position` | `fixed` | CSS 定位 |
1024
+ | `--wui-back-top-z-index` | `var(--wui-layer-auxiliary, 20)` | 层级 |
1025
+ | `--wui-back-top-top` | `auto` | 上偏移 |
1026
+ | `--wui-back-top-right` | `20px` | 右偏移 |
1027
+ | `--wui-back-top-bottom` | `20px` | 下偏移 |
1028
+ | `--wui-back-top-left` | `auto` | 左偏移 |
1029
+
758
1030
  #### `<web-ui-svg-draw-lines>`
759
1031
 
760
1032
  SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动画 —— 不克隆、不操作 DOM。
@@ -783,7 +1055,84 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
783
1055
 
784
1056
  **方法:** `getOverlayRoot()` — 返回 Portal 浮层容器
785
1057
 
786
- 定义 `--wui-color-*`、`--wui-shadow-*`、`--wui-layer-*` 与 motion token。motion token 是稳定的主题契约,可在主题范围覆盖:`--wui-duration-press`、`--wui-duration-feedback`、`--wui-duration-trigger`、`--wui-duration-focus`、`--wui-duration-menu-enter`、`--wui-duration-menu-exit`、`--wui-duration-overlay-enter`、`--wui-duration-overlay-exit`、`--wui-duration-drawer-enter`、`--wui-duration-drawer-exit`、`--wui-ease-enter`、`--wui-ease-slide`、`--wui-scale-enter`。`motion="system"` 跟随 `prefers-reduced-motion`;使用 `motion="reduced"` 降低当前作用域动效,或在嵌套主题中使用 `motion="full"` 恢复默认 token。System 配色模式跟随 `prefers-color-scheme`。
1058
+ 在其子树中定义基础、颜色、层级、阴影和动效 token。`motion="system"` 跟随 `prefers-reduced-motion`;使用 `motion="reduced"` 降低当前作用域动效,或在嵌套主题中使用 `motion="full"` 恢复默认 token。System 配色模式跟随 `prefers-color-scheme`。
1059
+
1060
+ **基础 token:**
1061
+
1062
+ | 属性 | 默认值 | 说明 |
1063
+ | ------------------------- | ------- | ------------------------ |
1064
+ | `--wui-font-size` | `14px` | 控件基础字号 |
1065
+ | `--wui-input-width` | `200px` | 紧凑表单控件默认宽度 |
1066
+ | `--wui-control-size` | `36px` | 控件默认高度和方形最小宽 |
1067
+ | `--wui-overlay-min-width` | `200px` | 锚定浮层最小宽度 |
1068
+ | `--wui-focus-ring-width` | `3px` | Focus 指示器宽度 |
1069
+
1070
+ **层级 token:**
1071
+
1072
+ | 属性 | 默认值 | 说明 |
1073
+ | ---------------------------- | ------ | -------------- |
1074
+ | `--wui-layer-base` | `0` | 基础内容 |
1075
+ | `--wui-layer-inline-overlay` | `1` | 组件内部浮层 |
1076
+ | `--wui-layer-header` | `10` | 页面 Header |
1077
+ | `--wui-layer-auxiliary` | `20` | 悬浮工具控件 |
1078
+ | `--wui-layer-banner` | `30` | Banner |
1079
+ | `--wui-layer-tabbar` | `40` | Tab Bar |
1080
+ | `--wui-layer-sidebar` | `50` | 侧边栏 |
1081
+ | `--wui-layer-menu` | `100` | 菜单/浮动面板 |
1082
+ | `--wui-layer-menu-nested` | `110` | 嵌套菜单 |
1083
+ | `--wui-layer-toast` | `200` | Toast |
1084
+ | `--wui-layer-loading` | `300` | 阻塞式 Loading |
1085
+
1086
+ **动效 token:** duration 默认值为 `--wui-duration-press: 80ms`、`--wui-duration-feedback: 100ms`、`--wui-duration-trigger: 160ms`、`--wui-duration-focus: 200ms`、`--wui-duration-menu-enter: 140ms`、`--wui-duration-menu-exit: 100ms`、`--wui-duration-overlay-enter: 180ms`、`--wui-duration-overlay-exit: 140ms`、`--wui-duration-drawer-enter: 280ms`、`--wui-duration-drawer-exit: 240ms`、`--wui-duration-drawer-nested: 450ms`、`--wui-duration-collapse-enter: 200ms`、`--wui-duration-collapse-exit: 160ms`、`--wui-duration-layout: 200ms`。Easing token 是 `--wui-ease-enter` 和 `--wui-ease-slide`;进入缩放是 `--wui-scale-enter: 0.97`。hover/active 背景反馈即时切换、无过渡动画;选中态、按压、focus 与 overlay 进出场过渡不受影响。
1087
+
1088
+ **颜色 token:**
1089
+
1090
+ | 属性 | 浅色默认值 | 深色默认值 | 说明 |
1091
+ | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------- |
1092
+ | `--wui-color-page` | `#fff` | `#242628` | 页面背景 |
1093
+ | `--wui-color-surface` | `#fff` | `#2c2c2e` | 普通 表面 |
1094
+ | `--wui-color-surface-raised` | `#f2f2f7` | `#2c2c2e` | 抬升表面 |
1095
+ | `--wui-color-surface-control` | `#dfdfdf` | `#3a3a3c` | 中性可交互控件表面 |
1096
+ | `--wui-color-surface-track` | `#e5e5ea` | `#444446` | Slider/Switch 轨道表面 |
1097
+ | `--wui-color-surface-menu` | `rgb(246 246 246 / 0.82)` | `rgb(30 30 32 / 0.92)` | Menu 和浮动面板表面 |
1098
+ | `--wui-color-surface-glass` | `rgb(250 250 250 / 0.34)` | `rgb(44 44 46 / 0.42)` | 液态玻璃表面 |
1099
+ | `--wui-color-surface-glass-hover` | `color-mix(... text 6%, surface-glass)` | `color-mix(... text 6%, surface-glass)` | Glass 完整悬停背景 |
1100
+ | `--wui-color-surface-glass-active` | `color-mix(... text 15%, surface-glass)` | `color-mix(... text 15%, surface-glass)` | Glass 完整按下背景 |
1101
+ | `--wui-color-surface-overlay` | `rgb(246 246 246 / 0.82)` | `rgb(32 34 34 / 0.9)` | 半透明浮层表面 |
1102
+ | `--wui-color-surface-segmented` | `#e5e5ea` | `#3a3a3c` | Segmented 轨道表面 |
1103
+ | `--wui-color-surface-selected` | `#fff` | `#5c5c5e` | Segmented 选中滑块表面 |
1104
+ | `--wui-color-text` | `#1b1b1b` | `#e9eaea` | 主要文本 |
1105
+ | `--wui-color-text-secondary` | `#6a6a6a` | `#a1a1a6` | 次要文本 |
1106
+ | `--wui-color-text-tertiary` | `color-mix(in srgb, var(--wui-color-text) 35%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 42%, transparent)` | 三级文本和弱意图图标 |
1107
+ | `--wui-color-text-disabled` | `color-mix(in srgb, var(--wui-color-text) 32%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 38%, transparent)` | 禁用态前景文本 |
1108
+ | `--wui-color-state-layer-hover` | `color-mix(in srgb, var(--wui-color-text) 6%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 6%, transparent)` | 透明悬停层 |
1109
+ | `--wui-color-state-layer-active` | `color-mix(in srgb, var(--wui-color-text) 15%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 15%, transparent)` | 透明按下层 |
1110
+ | `--wui-color-border` | `rgb(0 0 0 / 0.1)` | `rgb(255 255 255 / 0.14)` | 常规边框和分隔线 |
1111
+ | `--wui-color-glass-border` | `transparent` | `rgb(255 255 255 / 0.05)` | Glass 边框色调 |
1112
+ | `--wui-color-glass-highlight` | `rgb(255 255 255 / 0.9)` | `rgb(255 255 255 / 0.1)` | Glass 高光边缘 |
1113
+ | `--wui-color-glass-corner` | `rgb(255 255 255 / 0.08)` | `rgb(255 255 255 / 0.2)` | Glass 边框角落光泽 |
1114
+ | `--wui-color-glass-shade` | `rgb(0 0 0 / 0.06)` | `rgb(0 0 0 / 0.5)` | Glass 边框背光角压暗 |
1115
+ | `--wui-color-accent` | `#08f` | `#0a84ff` | Accent 和输入焦点边框 |
1116
+ | `--wui-color-on-accent` | `#fff` | `#fff` | Accent 上的前景色 |
1117
+ | `--wui-color-on-control` | `#fff` | `#f2f2f7` | 控件内芯前景色 |
1118
+ | `--wui-color-success` | `#16a34a` | `#30d158` | 成功 |
1119
+ | `--wui-color-warning` | `#d97706` | `#ff9f0a` | 警告 |
1120
+ | `--wui-color-danger` | `#dc2626` | `#ff453a` | 危险 |
1121
+ | `--wui-color-info` | `#2563eb` | `#64d2ff` | 信息 |
1122
+ | `--wui-color-backdrop` | `rgb(0 0 0 / 0.12)` | `rgb(0 0 0 / 0.48)` | Modal 遮罩 |
1123
+ | `--wui-color-focus-ring` | `rgb(0 136 255 / 0.4)` | `rgb(10 132 255 / 0.62)` | Focus 指示器颜色 |
1124
+
1125
+ **阴影 token:**
1126
+
1127
+ | 属性 | 浅色默认值 | 深色默认值 | 说明 |
1128
+ | ---------------------- | -------------------------------- | ------------------------------- | ----------------- |
1129
+ | `--wui-shadow-overlay` | `2px 16px 40px rgb(0 0 0 / 0.4)` | `0 18px 48px rgb(0 0 0 / 0.48)` | Modal/Drawer 阴影 |
1130
+ | `--wui-shadow-panel` | `0 3px 9px rgb(0 0 0 / 0.27)` | `0 4px 16px rgb(0 0 0 / 0.32)` | 小型浮动面板阴影 |
1131
+ | `--wui-shadow-glass` | 四层扩散阴影 | `0 8px 24px rgb(0 0 0 / 0.08)` | 液态玻璃基础阴影 |
1132
+
1133
+ **玻璃效果 token:** `--wui-glass-brightness` 浅色模式为 `1.06`,深色模式为 `1.02`。`--wui-glass-corner-radius` 默认值为 `32px`;玻璃组件会以自身的圆角半径覆盖它,使对角描边光影与形状对齐。
1134
+
1135
+ **内部 token:** 以 `--wui-internal-*` 为前缀的变量是 Shadow DOM 内部接线变量,不属于公共 token API,消费方不应覆盖。
787
1136
 
788
1137
  ---
789
1138
 
@@ -837,6 +1186,13 @@ toast.updateMessage(id, { message: '上传已完成 60%', heading: '正在上传
837
1186
 
838
1187
  悬停暂停自动关闭计时器(使用 `pointerenter`/`pointerleave`)。同一微任务中批量挂载 Toast。
839
1188
 
1189
+ **CSS 自定义属性:**
1190
+
1191
+ | 属性 | 默认值 | 说明 |
1192
+ | ------------------------------- | ------ | -------------------------- |
1193
+ | `--wui-toast-viewport-gap` | `16px` | Toast 到视口边缘的可见距离 |
1194
+ | `--wui-toast-container-padding` | `40px` | 容器预留的扩散阴影绘制空间 |
1195
+
840
1196
  ---
841
1197
 
842
1198
  ### 子项
@@ -856,6 +1212,12 @@ toast.updateMessage(id, { message: '上传已完成 60%', heading: '正在上传
856
1212
 
857
1213
  非表单关联组件(父级 select 统一提交)。
858
1214
 
1215
+ **CSS 自定义属性:**
1216
+
1217
+ | 属性 | 默认值 | 说明 |
1218
+ | ---------------------------- | ------- | ------------------------- |
1219
+ | `--wui-option-check-display` | `block` | 选中勾选图标的 display 值 |
1220
+
859
1221
  #### `<web-ui-segmented-trigger>`
860
1222
 
861
1223
  `<web-ui-segmented>` 的分段按钮。
@@ -869,3 +1231,11 @@ toast.updateMessage(id, { message: '上传已完成 60%', heading: '正在上传
869
1231
  **事件:** `change`
870
1232
 
871
1233
  非表单关联组件(父级 segmented 统一提交)。
1234
+
1235
+ **CSS 自定义属性:**
1236
+
1237
+ | 属性 | 默认值 | 说明 |
1238
+ | ----------------------------------- | -------------------------------- | ---------------- |
1239
+ | `--wui-segmented-trigger-px` | `12px` | 水平内边距 |
1240
+ | `--wui-segmented-trigger-bg-hover` | `--wui-color-state-layer-hover` | Trigger 悬停背景 |
1241
+ | `--wui-segmented-trigger-bg-active` | `--wui-color-state-layer-active` | Trigger 按下背景 |