@greypan/web-ui 2.1.5 → 2.1.8

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 (111) hide show
  1. package/README.CN.md +52 -36
  2. package/README.md +55 -36
  3. package/dist/assets/glass.js.map +1 -1
  4. package/dist/components/avatar/index.js +1 -1
  5. package/dist/components/avatar/index.js.map +1 -1
  6. package/dist/components/back-top/index.js +1 -1
  7. package/dist/components/back-top/index.js.map +1 -1
  8. package/dist/components/button/index.d.ts +6 -1
  9. package/dist/components/button/index.js +35 -14
  10. package/dist/components/button/index.js.map +1 -1
  11. package/dist/components/button/style.js +1 -1
  12. package/dist/components/button/style.js.map +1 -1
  13. package/dist/components/checkbox/index.d.ts +0 -3
  14. package/dist/components/checkbox/index.js.map +1 -1
  15. package/dist/components/checkbox/style.js +1 -1
  16. package/dist/components/checkbox/style.js.map +1 -1
  17. package/dist/components/context-menu/index.d.ts +4 -3
  18. package/dist/components/context-menu/index.js +47 -50
  19. package/dist/components/context-menu/index.js.map +1 -1
  20. package/dist/components/dialog/index.d.ts +1 -1
  21. package/dist/components/dialog/index.js +20 -19
  22. package/dist/components/dialog/index.js.map +1 -1
  23. package/dist/components/dialog/style.js +1 -1
  24. package/dist/components/dialog/style.js.map +1 -1
  25. package/dist/components/drawer/index.d.ts +2 -3
  26. package/dist/components/drawer/index.js +41 -31
  27. package/dist/components/drawer/index.js.map +1 -1
  28. package/dist/components/drawer/style.js +1 -1
  29. package/dist/components/drawer/style.js.map +1 -1
  30. package/dist/components/dropdown/index.d.ts +2 -9
  31. package/dist/components/dropdown/index.js +55 -51
  32. package/dist/components/dropdown/index.js.map +1 -1
  33. package/dist/components/dropdown-item/index.d.ts +0 -1
  34. package/dist/components/dropdown-item/index.js.map +1 -1
  35. package/dist/components/dropdown-item/style.js +1 -1
  36. package/dist/components/dropdown-item/style.js.map +1 -1
  37. package/dist/components/empty/index.js.map +1 -1
  38. package/dist/components/input/index.d.ts +1 -0
  39. package/dist/components/input/index.js +27 -14
  40. package/dist/components/input/index.js.map +1 -1
  41. package/dist/components/input/style.js +1 -1
  42. package/dist/components/input/style.js.map +1 -1
  43. package/dist/components/input-number/index.d.ts +3 -0
  44. package/dist/components/input-number/index.js +11 -3
  45. package/dist/components/input-number/index.js.map +1 -1
  46. package/dist/components/input-number/style.js +1 -1
  47. package/dist/components/input-number/style.js.map +1 -1
  48. package/dist/components/layout/style.js +1 -1
  49. package/dist/components/layout/style.js.map +1 -1
  50. package/dist/components/option/index.js +1 -1
  51. package/dist/components/option/index.js.map +1 -1
  52. package/dist/components/option/style.js +1 -1
  53. package/dist/components/option/style.js.map +1 -1
  54. package/dist/components/popover/index.d.ts +1 -5
  55. package/dist/components/popover/index.js +41 -36
  56. package/dist/components/popover/index.js.map +1 -1
  57. package/dist/components/radio/index.d.ts +0 -3
  58. package/dist/components/radio/index.js.map +1 -1
  59. package/dist/components/radio/style.js +1 -1
  60. package/dist/components/radio/style.js.map +1 -1
  61. package/dist/components/segmented/index.js +6 -2
  62. package/dist/components/segmented/index.js.map +1 -1
  63. package/dist/components/segmented/style.js +1 -1
  64. package/dist/components/segmented/style.js.map +1 -1
  65. package/dist/components/segmented-trigger/index.js +1 -1
  66. package/dist/components/segmented-trigger/index.js.map +1 -1
  67. package/dist/components/segmented-trigger/style.js +1 -1
  68. package/dist/components/segmented-trigger/style.js.map +1 -1
  69. package/dist/components/select/index.d.ts +1 -0
  70. package/dist/components/select/index.js +11 -6
  71. package/dist/components/select/index.js.map +1 -1
  72. package/dist/components/slider/index.d.ts +0 -2
  73. package/dist/components/slider/index.js +1 -1
  74. package/dist/components/slider/index.js.map +1 -1
  75. package/dist/components/spinner/index.d.ts +0 -2
  76. package/dist/components/spinner/index.js.map +1 -1
  77. package/dist/components/svg-draw-lines/index.d.ts +0 -2
  78. package/dist/components/svg-draw-lines/index.js.map +1 -1
  79. package/dist/components/switch/index.d.ts +0 -1
  80. package/dist/components/switch/index.js.map +1 -1
  81. package/dist/components/switch/style.js +1 -1
  82. package/dist/components/switch/style.js.map +1 -1
  83. package/dist/components/textarea/index.d.ts +1 -0
  84. package/dist/components/textarea/index.js +47 -33
  85. package/dist/components/textarea/index.js.map +1 -1
  86. package/dist/components/textarea/style.js +1 -1
  87. package/dist/components/textarea/style.js.map +1 -1
  88. package/dist/components/theme/index.d.ts +0 -2
  89. package/dist/components/theme/index.js.map +1 -1
  90. package/dist/components/theme/style.js +1 -1
  91. package/dist/components/theme/style.js.map +1 -1
  92. package/dist/components/toast/manager.js.map +1 -1
  93. package/dist/components/toast/style.js +1 -1
  94. package/dist/components/toast/style.js.map +1 -1
  95. package/dist/components/toast/toast.d.ts +0 -4
  96. package/dist/components/toast/toast.js +14 -6
  97. package/dist/components/toast/toast.js.map +1 -1
  98. package/dist/components/toast/types.d.ts +0 -3
  99. package/dist/components/tooltip/index.d.ts +1 -0
  100. package/dist/components/tooltip/index.js +31 -30
  101. package/dist/components/tooltip/index.js.map +1 -1
  102. package/dist/shared/events/user-change.js +17 -0
  103. package/dist/shared/events/user-change.js.map +1 -0
  104. package/dist/shared/normalize/index.js.map +1 -1
  105. package/dist/shared/overlay/native-dialog-presence.js +8 -3
  106. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  107. package/dist/shared/overlay/overlay.js.map +1 -1
  108. package/dist/shared/overlay/portal.js +3 -1
  109. package/dist/shared/overlay/portal.js.map +1 -1
  110. package/dist/shared/overlay/presence.js.map +1 -1
  111. package/package.json +9 -4
package/README.CN.md CHANGED
@@ -123,6 +123,16 @@ import '@greypan/web-ui/types/vue'
123
123
  </template>
124
124
  ```
125
125
 
126
+ ### 属性与事件边界
127
+
128
+ `web-ui-*` 元素是公开 DOM 边界。`id`、`class`、`style`、全局 HTML 属性和 `data-*` 保留在 Custom Element 宿主上,
129
+ 不会复制到 Shadow DOM。只有组件文档明确声明语义映射时,原生元素属性才会传递。例如 `web-ui-button` 会把 `type`
130
+ 映射到内部按钮,且仅接受 `button`、`submit`、`reset`;非法值会回退为 `button`。
131
+
132
+ ARIA 属性同样必须显式支持:使用组件文档化的命名属性,而不是通配 `aria-*` 透传。组件拥有自己的 role 和交互状态。
133
+ `click`、`input`、`change` 等浏览器 composed 原生事件仍是主要交互 API。`open-change` 等 kebab-case 自定义事件
134
+ 仅描述用户操作导致的组件状态变化;程序化赋值 property 不会触发它们。
135
+
126
136
  ## 所有组件
127
137
 
128
138
  | 分类 | 组件 |
@@ -183,6 +193,7 @@ import '@greypan/web-ui/types/vue'
183
193
  | `clearable` | `boolean` | `false` | 显示清除按钮 |
184
194
  | `full` | `boolean` | `false` | 全宽 |
185
195
  | `borderless` | `boolean` | `false` | 无边框 |
196
+ | `aria-label` | `string` | — | 无障碍标签 |
186
197
 
187
198
  **事件:** `input`, `change`, `focus`, `blur`
188
199
 
@@ -192,23 +203,24 @@ import '@greypan/web-ui/types/vue'
192
203
 
193
204
  多行文本输入框,支持自动调整高度。
194
205
 
195
- | 属性 | 类型 | 默认值 | 说明 |
196
- | ----------------- | --------- | ------- | -------------- |
197
- | `value` | `string` | `''` | 输入值 |
198
- | `placeholder` | `string` | `''` | 占位文本 |
199
- | `rows` | `number` | `3` | 显示行数 |
200
- | `name` | `string` | `''` | 表单字段名 |
201
- | `disabled` | `boolean` | `false` | 禁用状态 |
202
- | `readonly` | `boolean` | `false` | 只读状态 |
203
- | `required` | `boolean` | `false` | 必填校验 |
204
- | `clearable` | `boolean` | `false` | 显示清除按钮 |
205
- | `full` | `boolean` | `false` | 全宽 |
206
- | `borderless` | `boolean` | `false` | 无边框 |
207
- | `autosize` | `boolean` | `false` | 自动调整高度 |
208
- | `minlength` | `number` | — | 最小长度校验 |
209
- | `maxlength` | `number` | — | 最大长度校验 |
210
- | `aria-label` | `string` | — | 无障碍标签 |
211
- | `aria-labelledby` | `string` | — | 无障碍标签引用 |
206
+ | 属性 | 类型 | 默认值 | 说明 |
207
+ | ----------------- | --------- | ------- | ---------------------------------- |
208
+ | `value` | `string` | `''` | 输入值 |
209
+ | `placeholder` | `string` | `''` | 占位文本 |
210
+ | `rows` | `number` | `3` | 显示行数 |
211
+ | `name` | `string` | `''` | 表单字段名 |
212
+ | `disabled` | `boolean` | `false` | 禁用状态 |
213
+ | `readonly` | `boolean` | `false` | 只读状态 |
214
+ | `required` | `boolean` | `false` | 必填校验 |
215
+ | `clearable` | `boolean` | `false` | 显示清除按钮 |
216
+ | `full` | `boolean` | `false` | 全宽 |
217
+ | `borderless` | `boolean` | `false` | 无边框 |
218
+ | `autosize` | `boolean` | `false` | 自动调整高度 |
219
+ | `max-height` | `number` | `0` | 自动高度上限(px),`0` 表示不限制 |
220
+ | `minlength` | `number` | — | 最小长度校验 |
221
+ | `maxlength` | `number` | — | 最大长度校验 |
222
+ | `aria-label` | `string` | — | 无障碍标签 |
223
+ | `aria-labelledby` | `string` | — | 无障碍标签引用 |
212
224
 
213
225
  **事件:** `input`, `change`, `focus`, `blur`
214
226
 
@@ -391,19 +403,23 @@ ArrowUp/ArrowDown 键增减数值。
391
403
 
392
404
  样式化按钮,支持多种变体和加载状态。
393
405
 
394
- | 属性 | 类型 | 默认值 | 说明 |
395
- | ---------- | ------------------------------------------------------------ | --------- | ------------------------------ |
396
- | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | 按钮变体 |
397
- | `disabled` | `boolean` | `false` | 禁用状态 |
398
- | `loading` | `boolean` | `false` | 加载旋转动画 |
399
- | `full` | `boolean` | `false` | 全宽 |
400
- | `icon` | `boolean` | `false` | 纯图标模式 |
401
- | `size` | `string` | `''` | 尺寸格式 `高度` 或 `高度x宽度` |
406
+ | 属性 | 类型 | 默认值 | 说明 |
407
+ | ------------ | ------------------------------------------------------------ | ---------- | ----------------------------------- |
408
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | 按钮变体 |
409
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | 内部按钮类型;非法值回退为 `button` |
410
+ | `disabled` | `boolean` | `false` | 禁用状态 |
411
+ | `loading` | `boolean` | `false` | 加载旋转动画 |
412
+ | `full` | `boolean` | `false` | 全宽 |
413
+ | `icon` | `boolean` | `false` | 纯图标模式 |
414
+ | `size` | `string` | `''` | 尺寸格式 `高度` 或 `高度x宽度` |
415
+ | `aria-label` | `string` | — | 无障碍标签(委托给内部按钮) |
402
416
 
403
417
  **事件:** 标准 `click`
404
418
 
405
419
  **插槽:** `prefix`, `default`, `suffix`
406
420
 
421
+ `submit` 和 `reset` 不会提交或重置组件 Shadow DOM 外祖先 `<form>`。如需外部表单行为,请使用 form-associated 控件。
422
+
407
423
  禁用和加载状态阻止 `click` 事件。
408
424
 
409
425
  #### `<web-ui-button-group>`
@@ -598,16 +614,16 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
598
614
 
599
615
  徽标 / 通知计数。
600
616
 
601
- | 属性 | 类型 | 默认值 | 说明 |
602
- | ----------- | -------------------------------------------------------------- | ------------- | ---------------------- |
603
- | `count` | `number` | `0` | 显示数字 |
604
- | `max` | `number` | `99` | 最大值(超过显示 99+) |
605
- | `dot` | `boolean` | `false` | 点模式(不显示数字) |
606
- | `show-zero` | `boolean` | `false` | count 为 0 时也显示 |
607
- | `hidden` | `boolean` | `false` | 完全隐藏 |
608
- | `offset-x` | `number` | `0` | 水平偏移 |
609
- | `offset-y` | `number` | `0` | 垂直偏移 |
610
- | `placement` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` | 徽标位置 |
617
+ | 属性 | 类型 | 默认值 | 说明 |
618
+ | -------------- | -------------------------------------------------------------- | ------------- | ---------------------- |
619
+ | `count` | `number` | `0` | 显示数字 |
620
+ | `max` | `number` | `99` | 最大值(超过显示 99+) |
621
+ | `dot` | `boolean` | `false` | 点模式(不显示数字) |
622
+ | `show-zero` | `boolean` | `false` | count 为 0 时也显示 |
623
+ | `badge-hidden` | `boolean` | `false` | 完全隐藏 |
624
+ | `offset-x` | `number` | `0` | 水平偏移 |
625
+ | `offset-y` | `number` | `0` | 垂直偏移 |
626
+ | `placement` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` | 徽标位置 |
611
627
 
612
628
  #### `<web-ui-empty>`
613
629
 
@@ -727,7 +743,7 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
727
743
 
728
744
  **方法:** `getOverlayRoot()` — 返回 Portal 浮层容器
729
745
 
730
- 定义 `--wui-color-*`、`--wui-shadow-*`、`--wui-layer-*` 与 motion token。motion token 是稳定的主题契约,可在主题范围覆盖:`--wui-duration-press`、`--wui-duration-feedback`、`--wui-duration-fast`、`--wui-duration-menu-enter`、`--wui-duration-menu-exit`、`--wui-duration-overlay-enter`、`--wui-duration-overlay-exit`、`--wui-duration-drawer`、`--wui-ease-out`、`--wui-ease-standard`、`--wui-scale-press`、`--wui-scale-enter`。`motion="system"` 跟随 `prefers-reduced-motion`;使用 `motion="reduced"` 降低当前作用域动效,或在嵌套主题中使用 `motion="full"` 恢复默认 token。System 配色模式跟随 `prefers-color-scheme`。
746
+ 定义 `--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`。
731
747
 
732
748
  ---
733
749
 
package/README.md CHANGED
@@ -125,6 +125,18 @@ import '@greypan/web-ui/types/vue'
125
125
  </template>
126
126
  ```
127
127
 
128
+ ### Attribute and event boundaries
129
+
130
+ `web-ui-*` elements are the public DOM boundary. `id`, `class`, `style`, global HTML attributes, and `data-*` stay on
131
+ the custom-element host; they are not copied into its Shadow DOM. Components expose native-element attributes only when
132
+ they document an explicit semantic mapping. For example, `web-ui-button` maps `type` to its inner button and accepts
133
+ only `button`, `submit`, or `reset` (invalid values become `button`).
134
+
135
+ ARIA attributes are explicit: use the component's documented naming attributes, not a blanket `aria-*` pass-through.
136
+ Components own their role and interaction state. Browser-native composed events such as `click`, `input`, and `change`
137
+ remain the primary interaction API. Kebab-case custom events such as `open-change` describe user-originated component
138
+ state changes; assigning a property programmatically does not emit them.
139
+
128
140
  ## All Components
129
141
 
130
142
  | Category | Component |
@@ -185,6 +197,7 @@ Text input with clearable, prefix/suffix slots.
185
197
  | `clearable` | `boolean` | `false` | Show clear button |
186
198
  | `full` | `boolean` | `false` | Full width |
187
199
  | `borderless` | `boolean` | `false` | No border |
200
+ | `aria-label` | `string` | — | Accessible label |
188
201
 
189
202
  **Events:** `input`, `change`, `focus`, `blur`
190
203
 
@@ -194,23 +207,24 @@ Text input with clearable, prefix/suffix slots.
194
207
 
195
208
  Multi-line text input with auto-resize.
196
209
 
197
- | Attribute | Type | Default | Description |
198
- | ----------------- | --------- | ------- | -------------------------- |
199
- | `value` | `string` | `''` | Textarea value |
200
- | `placeholder` | `string` | `''` | Placeholder text |
201
- | `rows` | `number` | `3` | Visible rows |
202
- | `name` | `string` | `''` | Form field name |
203
- | `disabled` | `boolean` | `false` | Disabled state |
204
- | `readonly` | `boolean` | `false` | Read-only state |
205
- | `required` | `boolean` | `false` | Required validation |
206
- | `clearable` | `boolean` | `false` | Show clear button |
207
- | `full` | `boolean` | `false` | Full width |
208
- | `borderless` | `boolean` | `false` | No border |
209
- | `autosize` | `boolean` | `false` | Auto-resize height |
210
- | `minlength` | `number` | — | Minimum length validation |
211
- | `maxlength` | `number` | — | Maximum length validation |
212
- | `aria-label` | `string` | — | Accessible label |
213
- | `aria-labelledby` | `string` | — | Accessible label reference |
210
+ | Attribute | Type | Default | Description |
211
+ | ----------------- | --------- | ------- | ----------------------------------------- |
212
+ | `value` | `string` | `''` | Textarea value |
213
+ | `placeholder` | `string` | `''` | Placeholder text |
214
+ | `rows` | `number` | `3` | Visible rows |
215
+ | `name` | `string` | `''` | Form field name |
216
+ | `disabled` | `boolean` | `false` | Disabled state |
217
+ | `readonly` | `boolean` | `false` | Read-only state |
218
+ | `required` | `boolean` | `false` | Required validation |
219
+ | `clearable` | `boolean` | `false` | Show clear button |
220
+ | `full` | `boolean` | `false` | Full width |
221
+ | `borderless` | `boolean` | `false` | No border |
222
+ | `autosize` | `boolean` | `false` | Auto-resize height |
223
+ | `max-height` | `number` | `0` | Autosize max height (px); `0` = unlimited |
224
+ | `minlength` | `number` | — | Minimum length validation |
225
+ | `maxlength` | `number` | — | Maximum length validation |
226
+ | `aria-label` | `string` | — | Accessible label |
227
+ | `aria-labelledby` | `string` | — | Accessible label reference |
214
228
 
215
229
  **Events:** `input`, `change`, `focus`, `blur`
216
230
 
@@ -397,19 +411,24 @@ Radio group managing single selection.
397
411
 
398
412
  Styled button with variants and loading state.
399
413
 
400
- | Attribute | Type | Default | Description |
401
- | ---------- | ------------------------------------------------------------ | --------- | -------------------------------------- |
402
- | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | Button variant |
403
- | `disabled` | `boolean` | `false` | Disabled state |
404
- | `loading` | `boolean` | `false` | Loading spinner |
405
- | `full` | `boolean` | `false` | Full width |
406
- | `icon` | `boolean` | `false` | Icon-only mode |
407
- | `size` | `string` | `''` | Size format `height` or `heightxwidth` |
414
+ | Attribute | Type | Default | Description |
415
+ | ------------ | ------------------------------------------------------------ | ---------- | ------------------------------------------------- |
416
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | Button variant |
417
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Inner-button type; invalid values become `button` |
418
+ | `disabled` | `boolean` | `false` | Disabled state |
419
+ | `loading` | `boolean` | `false` | Loading spinner |
420
+ | `full` | `boolean` | `false` | Full width |
421
+ | `icon` | `boolean` | `false` | Icon-only mode |
422
+ | `size` | `string` | `''` | Size format `height` or `heightxwidth` |
423
+ | `aria-label` | `string` | — | Accessible label (delegated to inner button) |
408
424
 
409
425
  **Events:** standard `click`
410
426
 
411
427
  **Slots:** `prefix`, `default`, `suffix`
412
428
 
429
+ `submit` and `reset` do not submit or reset an ancestor form outside the component's Shadow DOM. Use a
430
+ form-associated control when external form submission behavior is required.
431
+
413
432
  Disabled and loading states prevent `click` events.
414
433
 
415
434
  #### `<web-ui-button-group>`
@@ -604,16 +623,16 @@ Avatar display with image fallback.
604
623
 
605
624
  Badge / notification count.
606
625
 
607
- | Attribute | Type | Default | Description |
608
- | ----------- | -------------------------------------------------------------- | ------------- | ------------------------- |
609
- | `count` | `number` | `0` | Display count |
610
- | `max` | `number` | `99` | Maximum count (shows 99+) |
611
- | `dot` | `boolean` | `false` | Dot mode (no count) |
612
- | `show-zero` | `boolean` | `false` | Show when count is 0 |
613
- | `hidden` | `boolean` | `false` | Hide completely |
614
- | `offset-x` | `number` | `0` | Horizontal offset |
615
- | `offset-y` | `number` | `0` | Vertical offset |
616
- | `placement` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` | Badge position |
626
+ | Attribute | Type | Default | Description |
627
+ | -------------- | -------------------------------------------------------------- | ------------- | ------------------------- |
628
+ | `count` | `number` | `0` | Display count |
629
+ | `max` | `number` | `99` | Maximum count (shows 99+) |
630
+ | `dot` | `boolean` | `false` | Dot mode (no count) |
631
+ | `show-zero` | `boolean` | `false` | Show when count is 0 |
632
+ | `badge-hidden` | `boolean` | `false` | Hide completely |
633
+ | `offset-x` | `number` | `0` | Horizontal offset |
634
+ | `offset-y` | `number` | `0` | Vertical offset |
635
+ | `placement` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` | Badge position |
617
636
 
618
637
  #### `<web-ui-empty>`
619
638
 
@@ -733,7 +752,7 @@ Theme provider defining CSS custom property tokens.
733
752
 
734
753
  **Methods:** `getOverlayRoot()` — returns the portal overlay container
735
754
 
736
- Defines `--wui-color-*`, `--wui-shadow-*`, `--wui-layer-*`, and motion tokens. Motion tokens are stable and may be overridden per theme scope: `--wui-duration-press`, `--wui-duration-feedback`, `--wui-duration-fast`, `--wui-duration-menu-enter`, `--wui-duration-menu-exit`, `--wui-duration-overlay-enter`, `--wui-duration-overlay-exit`, `--wui-duration-drawer`, `--wui-ease-out`, `--wui-ease-standard`, `--wui-scale-press`, and `--wui-scale-enter`. `motion="system"` follows `prefers-reduced-motion`; use `motion="reduced"` to reduce animation in a scope or `motion="full"` in a nested theme to restore the normal token values. System appearance follows `prefers-color-scheme`.
755
+ Defines `--wui-color-*`, `--wui-shadow-*`, `--wui-layer-*`, and motion tokens. Motion tokens are stable and may be overridden per theme scope: `--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`, and `--wui-scale-enter`. `motion="system"` follows `prefers-reduced-motion`; use `motion="reduced"` to reduce animation in a scope or `motion="full"` in a nested theme to restore the normal token values. System appearance follows `prefers-color-scheme`.
737
756
 
738
757
  ---
739
758
 
@@ -1 +1 @@
1
- {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n position: relative;\n border: 0.5px double var(--wui-color-glass-border, rgb(51 51 51 / 0.08));\n backdrop-filter: blur(2px);\n box-shadow:\n inset -1px -1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset 1px 1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset -3px -3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 3px 3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 0 0 1px rgb(0 0 0 / 0.8),\n var(--wui-glass-shadow, var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)));\n}\n"],"mappings":""}
1
+ {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n position: relative;\n\n border: 0.5px double var(--wui-color-glass-border, rgb(51 51 51 / 0.08));\n\n /* Safari 16.4 只支持带 -webkit- 前缀的 backdrop-filter(无前缀 18 才支持),\n lightningcss 对 ?inline 导入不做自动前缀,需手动写前缀版本 */\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(2px);\n backdrop-filter: blur(2px);\n box-shadow:\n inset -1px -1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset 1px 1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset -3px -3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 3px 3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 0 0 1px rgb(0 0 0 / 0.8),\n var(--wui-glass-shadow, var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)));\n}\n"],"mappings":""}
@@ -84,7 +84,7 @@ var p = ["circle", "square"], m = class extends a {
84
84
  <slot @slotchange=${this._checkSlot}></slot>
85
85
  ${this._showFallback && this._initials ? o`<span class="avatar-fallback avatar-initials">${this._initials}</span>` : ""}
86
86
  ${this._showFallback && !this._initials ? o`<span class="avatar-fallback"
87
- ><web-ui-icon .icon=${n} size=${this._iconSize}></web-ui-icon
87
+ ><web-ui-icon .icon=${n} .size=${this._iconSize}></web-ui-icon
88
88
  ></span>` : ""}
89
89
  </div>
90
90
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\n// 注册 web-ui-icon(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideUser } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_SHAPES = ['circle', 'square'] as const\n\n@customElement('web-ui-avatar')\nexport class WebUiAvatar extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n set src(value: string) {\n const old = this._src\n this._src = value\n if (old !== value) {\n this._imgError = false\n this.requestUpdate('src', old)\n }\n }\n\n get src(): string {\n return this._src\n }\n\n private _src = ''\n\n @property({ type: String, reflect: true }) alt = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Number, reflect: true }) size = 40\n\n @property({ type: String, reflect: true })\n set shape(value: string) {\n const normalized = normalizeLiteral(value, ALLOWED_SHAPES, 'circle')\n if (this._shape !== normalized) {\n const old = this._shape\n this._shape = normalized\n this.requestUpdate('shape', old)\n }\n // 外部 setAttribute 非法值后,宿主 attribute 与规范化后的值不同步,立即修正\n if (this.getAttribute('shape') !== normalized) {\n this.setAttribute('shape', normalized)\n }\n }\n\n get shape(): 'circle' | 'square' {\n return this._shape\n }\n\n private _shape: 'circle' | 'square' = 'circle'\n\n @state() private _imgError = false\n @state() private _hasDefaultSlot = false\n\n override connectedCallback() {\n super.connectedCallback()\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector('slot:not([name])')?.addEventListener('slotchange', () => this._checkSlot())\n })\n }\n\n private _checkSlot() {\n const slot = this.shadowRoot?.querySelector('slot:not([name])')\n const has = slot instanceof HTMLSlotElement && slot.assignedElements().length > 0\n if (this._hasDefaultSlot !== has) {\n this._hasDefaultSlot = has\n }\n }\n\n private get _initials(): string {\n const words = this.name.trim().split(/\\s+/)\n return words\n .slice(0, 2)\n .map(w => Array.from(w)[0])\n .join('')\n .toUpperCase()\n }\n\n private get _iconSize(): number {\n return Math.round(this.size * 0.4)\n }\n\n private get _showImage(): boolean {\n return !!this.src && !this._imgError\n }\n\n private get _showFallback(): boolean {\n return !this._showImage && !this._hasDefaultSlot\n }\n\n private _onImgError() {\n this._imgError = true\n }\n\n private get _ariaLabel(): string | undefined {\n if (this.alt) return this.alt\n if (this.name) return this.name\n return undefined\n }\n\n override render() {\n const isDecorative = !this._ariaLabel\n\n return html`\n <div\n class=${classMap({ 'avatar-inner': true, 'wui-glass': this._showFallback })}\n role=${isDecorative ? 'presentation' : 'img'}\n aria-label=${ifDefined(this._ariaLabel)}\n aria-hidden=${isDecorative ? 'true' : undefined}\n style=\"width:${this.size}px;height:${this.size}px;--wui-avatar-size:${this.size}px\"\n >\n ${this._showImage\n ? html`<img\n class=\"avatar-img\"\n src=${this.src}\n alt=${ifDefined(this.alt || undefined)}\n @error=${this._onImgError}\n />`\n : ''}\n <slot @slotchange=${this._checkSlot}></slot>\n ${this._showFallback && this._initials\n ? html`<span class=\"avatar-fallback avatar-initials\">${this._initials}</span>`\n : ''}\n ${this._showFallback && !this._initials\n ? html`<span class=\"avatar-fallback\"\n ><web-ui-icon .icon=${lucideUser} size=${this._iconSize}></web-ui-icon\n ></span>`\n : ''}\n </div>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-avatar': WebUiAvatar\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\n// 注册 web-ui-icon(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideUser } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_SHAPES = ['circle', 'square'] as const\n\n@customElement('web-ui-avatar')\nexport class WebUiAvatar extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n set src(value: string) {\n const old = this._src\n this._src = value\n if (old !== value) {\n this._imgError = false\n this.requestUpdate('src', old)\n }\n }\n\n get src(): string {\n return this._src\n }\n\n private _src = ''\n\n @property({ type: String, reflect: true }) alt = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Number, reflect: true }) size = 40\n\n @property({ type: String, reflect: true })\n set shape(value: string) {\n const normalized = normalizeLiteral(value, ALLOWED_SHAPES, 'circle')\n if (this._shape !== normalized) {\n const old = this._shape\n this._shape = normalized\n this.requestUpdate('shape', old)\n }\n // 外部 setAttribute 非法值后,宿主 attribute 与规范化后的值不同步,立即修正\n if (this.getAttribute('shape') !== normalized) {\n this.setAttribute('shape', normalized)\n }\n }\n\n get shape(): 'circle' | 'square' {\n return this._shape\n }\n\n private _shape: 'circle' | 'square' = 'circle'\n\n @state() private _imgError = false\n @state() private _hasDefaultSlot = false\n\n override connectedCallback() {\n super.connectedCallback()\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector('slot:not([name])')?.addEventListener('slotchange', () => this._checkSlot())\n })\n }\n\n private _checkSlot() {\n const slot = this.shadowRoot?.querySelector('slot:not([name])')\n const has = slot instanceof HTMLSlotElement && slot.assignedElements().length > 0\n if (this._hasDefaultSlot !== has) {\n this._hasDefaultSlot = has\n }\n }\n\n private get _initials(): string {\n const words = this.name.trim().split(/\\s+/)\n return words\n .slice(0, 2)\n .map(w => Array.from(w)[0])\n .join('')\n .toUpperCase()\n }\n\n private get _iconSize(): number {\n return Math.round(this.size * 0.4)\n }\n\n private get _showImage(): boolean {\n return !!this.src && !this._imgError\n }\n\n private get _showFallback(): boolean {\n return !this._showImage && !this._hasDefaultSlot\n }\n\n private _onImgError() {\n this._imgError = true\n }\n\n private get _ariaLabel(): string | undefined {\n if (this.alt) return this.alt\n if (this.name) return this.name\n return undefined\n }\n\n override render() {\n const isDecorative = !this._ariaLabel\n\n return html`\n <div\n class=${classMap({ 'avatar-inner': true, 'wui-glass': this._showFallback })}\n role=${isDecorative ? 'presentation' : 'img'}\n aria-label=${ifDefined(this._ariaLabel)}\n aria-hidden=${isDecorative ? 'true' : undefined}\n style=\"width:${this.size}px;height:${this.size}px;--wui-avatar-size:${this.size}px\"\n >\n ${this._showImage\n ? html`<img\n class=\"avatar-img\"\n src=${this.src}\n alt=${ifDefined(this.alt || undefined)}\n @error=${this._onImgError}\n />`\n : ''}\n <slot @slotchange=${this._checkSlot}></slot>\n ${this._showFallback && this._initials\n ? html`<span class=\"avatar-fallback avatar-initials\">${this._initials}</span>`\n : ''}\n ${this._showFallback && !this._initials\n ? html`<span class=\"avatar-fallback\"\n ><web-ui-icon .icon=${lucideUser} .size=${this._iconSize}></web-ui-icon\n ></span>`\n : ''}\n </div>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-avatar': WebUiAvatar\n }\n}\n"],"mappings":"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"}
@@ -62,7 +62,7 @@ var f = class extends a {
62
62
  });
63
63
  }
64
64
  onEnter(e) {
65
- e.key === "Enter" && (e.preventDefault(), this.toTop());
65
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), this.toTop());
66
66
  }
67
67
  render() {
68
68
  return o`
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/back-top/index.ts"],"sourcesContent":["import { getRootScrollTop } from '@greypan/browser-kit'\nimport { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport { lucideArrowUpToLine } from '@/icons'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-back-top')\nexport class WebUiBackTop extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ reflect: true, attribute: 'scroll-behavior', useDefault: true })\n get scrollBehavior(): 'smooth' | 'auto' {\n return this._scrollBehavior\n }\n set scrollBehavior(value: string) {\n const old = this._scrollBehavior\n this._scrollBehavior = normalizeLiteral(value, ['smooth', 'auto'] as const, 'smooth')\n this.requestUpdate('scrollBehavior', old)\n }\n private _scrollBehavior: 'smooth' | 'auto' = 'smooth'\n @property({ type: Boolean, reflect: true }) visible = false\n @property({ attribute: false }) scrollTarget: HTMLElement | Window = window\n\n @property({ type: Number, reflect: true })\n get threshold(): number {\n return this._threshold\n }\n set threshold(v: number) {\n const old = this._threshold\n this._threshold = normalizeNumber(v, 0, 10000, 200)\n this.requestUpdate('threshold', old)\n }\n private _threshold = 200\n\n @state() private eventController?: AbortController\n\n override connectedCallback() {\n super.connectedCallback()\n this.computeVisible()\n this.onScrollTarget()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.eventController?.abort()\n }\n\n protected override willUpdate(props: PropertyValues) {\n super.willUpdate(props)\n\n if (props.has('threshold') || props.has('scrollTarget')) {\n this.computeVisible()\n }\n // 不设 hasUpdated 门控:scrollTarget 可能在首次更新完成前赋值(如框架 onMounted 中),\n // 此时 connectedCallback 已按 window 绑定,必须重绑到新容器;onScrollTarget 幂等,重复调用安全\n if (props.has('scrollTarget')) {\n // 容器模式:scrollTarget 为元素时按钮通过 sticky 悬浮于容器底部,而非固定视口角落\n this.toggleAttribute('container-mode', this.target !== window)\n this.onScrollTarget()\n }\n }\n\n private get target() {\n if (!this.scrollTarget) return window\n const isRoot =\n this.scrollTarget === window ||\n this.scrollTarget === document.documentElement ||\n this.scrollTarget === document.body\n return isRoot ? window : this.scrollTarget\n }\n\n private onScrollTarget() {\n this.eventController?.abort()\n this.eventController = new AbortController()\n\n this.target.addEventListener(\n 'scroll',\n () => {\n this.computeVisible()\n },\n { signal: this.eventController.signal, passive: true }\n )\n }\n\n private computeVisible() {\n const target = this.target\n if (target === window) {\n this.visible = getRootScrollTop() >= this.threshold\n } else if (target instanceof HTMLElement) {\n this.visible = target.scrollTop >= this.threshold\n } else {\n throw new Error('Prop scrollTarget must be HTMLElement or Window.')\n }\n }\n\n toTop() {\n this.target.scrollTo({\n top: 0,\n behavior: this.scrollBehavior\n })\n }\n\n private onEnter(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n e.preventDefault()\n this.toTop()\n }\n }\n\n override render() {\n return html`\n <div class=\"back-top-inner\" role=\"button\" tabindex=\"0\" @click=${this.toTop} @keydown=${this.onEnter}>\n <slot>\n <web-ui-button tabindex=\"-1\" icon>\n <web-ui-icon .icon=${lucideArrowUpToLine}></web-ui-icon>\n </web-ui-button>\n </slot>\n </div>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-back-top': WebUiBackTop\n }\n}\n"],"mappings":";;;;;;;;;;AAYO,IAAM,IAAN,cAA2B,EAAW;;EAyBtB,aAbwB,KAAA,kBAAA,UACS,KAAA,UAAA,IACe,KAAA,eAAA,QAWhD,KAAA,aAAA;;;EAxBI,KAAA,SAAA,EAAU,CAAK;;CAExC,IACI,iBAAoC;EACtC,OAAO,KAAK;CACd;CACA,IAAI,eAAe,GAAe;EAChC,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,kBAAkB,EAAiB,GAAO,CAAC,UAAU,MAAM,GAAY,QAAQ,GACpF,KAAK,cAAc,kBAAkB,CAAG;CAC1C;CAKA,IACI,YAAoB;EACtB,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAgB,GAAG,GAAG,KAAO,GAAG,GAClD,KAAK,cAAc,aAAa,CAAG;CACrC;CAKA,oBAA6B;EAG3B,AAFA,MAAM,kBAAkB,GACxB,KAAK,eAAe,GACpB,KAAK,eAAe;CACtB;CAEA,uBAAgC;EAE9B,AADA,MAAM,qBAAqB,GAC3B,KAAK,iBAAiB,MAAM;CAC9B;CAEA,WAA8B,GAAuB;EAQnD,AAPA,MAAM,WAAW,CAAK,IAElB,EAAM,IAAI,WAAW,KAAK,EAAM,IAAI,cAAc,MACpD,KAAK,eAAe,GAIlB,EAAM,IAAI,cAAc,MAE1B,KAAK,gBAAgB,kBAAkB,KAAK,WAAW,MAAM,GAC7D,KAAK,eAAe;CAExB;CAEA,IAAY,SAAS;EAMnB,OALK,KAAK,eAER,KAAK,iBAAiB,UACtB,KAAK,iBAAiB,SAAS,mBAC/B,KAAK,iBAAiB,SAAS,OACjB,SAAS,KAAK,eALC;CAMjC;CAEA,iBAAyB;EAIvB,AAHA,KAAK,iBAAiB,MAAM,GAC5B,KAAK,kBAAkB,IAAI,gBAAgB,GAE3C,KAAK,OAAO,iBACV,gBACM;GACJ,KAAK,eAAe;EACtB,GACA;GAAE,QAAQ,KAAK,gBAAgB;GAAQ,SAAS;EAAK,CACvD;CACF;CAEA,iBAAyB;EACvB,IAAM,IAAS,KAAK;EACpB,IAAI,MAAW,QACb,KAAK,UAAU,EAAiB,KAAK,KAAK;OACrC,IAAI,aAAkB,aAC3B,KAAK,UAAU,EAAO,aAAa,KAAK;OAExC,MAAU,MAAM,kDAAkD;CAEtE;CAEA,QAAQ;EACN,KAAK,OAAO,SAAS;GACnB,KAAK;GACL,UAAU,KAAK;EACjB,CAAC;CACH;CAEA,QAAgB,GAAkB;EAChC,AAAI,EAAE,QAAQ,YACZ,EAAE,eAAe,GACjB,KAAK,MAAM;CAEf;CAEA,SAAkB;EAChB,OAAO,CAAI;sEACuD,KAAK,MAAM,YAAY,KAAK,QAAQ;;;iCAGzE,EAAoB;;;;;CAKnD;AAGF;AAhHG,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,WAAW;CAAmB,YAAY;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,kBAAA,IAAA,GAU1E,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,EAAE,WAAW,GAAM,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GAE7B,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAWxC,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GA5BR,IAAA,EAAA,CAAA,EAAc,iBAAiB,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/back-top/index.ts"],"sourcesContent":["import { getRootScrollTop } from '@greypan/browser-kit'\nimport { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport { lucideArrowUpToLine } from '@/icons'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-back-top')\nexport class WebUiBackTop extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ reflect: true, attribute: 'scroll-behavior', useDefault: true })\n get scrollBehavior(): 'smooth' | 'auto' {\n return this._scrollBehavior\n }\n set scrollBehavior(value: string) {\n const old = this._scrollBehavior\n this._scrollBehavior = normalizeLiteral(value, ['smooth', 'auto'] as const, 'smooth')\n this.requestUpdate('scrollBehavior', old)\n }\n private _scrollBehavior: 'smooth' | 'auto' = 'smooth'\n @property({ type: Boolean, reflect: true }) visible = false\n @property({ attribute: false }) scrollTarget: HTMLElement | Window = window\n\n @property({ type: Number, reflect: true })\n get threshold(): number {\n return this._threshold\n }\n set threshold(v: number) {\n const old = this._threshold\n this._threshold = normalizeNumber(v, 0, 10000, 200)\n this.requestUpdate('threshold', old)\n }\n private _threshold = 200\n\n @state() private eventController?: AbortController\n\n override connectedCallback() {\n super.connectedCallback()\n this.computeVisible()\n this.onScrollTarget()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.eventController?.abort()\n }\n\n protected override willUpdate(props: PropertyValues) {\n super.willUpdate(props)\n\n if (props.has('threshold') || props.has('scrollTarget')) {\n this.computeVisible()\n }\n // 不设 hasUpdated 门控:scrollTarget 可能在首次更新完成前赋值(如框架 onMounted 中),\n // 此时 connectedCallback 已按 window 绑定,必须重绑到新容器;onScrollTarget 幂等,重复调用安全\n if (props.has('scrollTarget')) {\n // 容器模式:scrollTarget 为元素时按钮通过 sticky 悬浮于容器底部,而非固定视口角落\n this.toggleAttribute('container-mode', this.target !== window)\n this.onScrollTarget()\n }\n }\n\n private get target() {\n if (!this.scrollTarget) return window\n const isRoot =\n this.scrollTarget === window ||\n this.scrollTarget === document.documentElement ||\n this.scrollTarget === document.body\n return isRoot ? window : this.scrollTarget\n }\n\n private onScrollTarget() {\n this.eventController?.abort()\n this.eventController = new AbortController()\n\n this.target.addEventListener(\n 'scroll',\n () => {\n this.computeVisible()\n },\n { signal: this.eventController.signal, passive: true }\n )\n }\n\n private computeVisible() {\n const target = this.target\n if (target === window) {\n this.visible = getRootScrollTop() >= this.threshold\n } else if (target instanceof HTMLElement) {\n this.visible = target.scrollTop >= this.threshold\n } else {\n throw new Error('Prop scrollTarget must be HTMLElement or Window.')\n }\n }\n\n toTop() {\n this.target.scrollTo({\n top: 0,\n behavior: this.scrollBehavior\n })\n }\n\n // ARIA button 契约要求 Enter 与 Space 均能激活\n private onEnter(e: KeyboardEvent) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.toTop()\n }\n }\n\n override render() {\n return html`\n <div class=\"back-top-inner\" role=\"button\" tabindex=\"0\" @click=${this.toTop} @keydown=${this.onEnter}>\n <slot>\n <web-ui-button tabindex=\"-1\" icon>\n <web-ui-icon .icon=${lucideArrowUpToLine}></web-ui-icon>\n </web-ui-button>\n </slot>\n </div>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-back-top': WebUiBackTop\n }\n}\n"],"mappings":";;;;;;;;;;AAYO,IAAM,IAAN,cAA2B,EAAW;;EAyBtB,aAbwB,KAAA,kBAAA,UACS,KAAA,UAAA,IACe,KAAA,eAAA,QAWhD,KAAA,aAAA;;;EAxBI,KAAA,SAAA,EAAU,CAAK;;CAExC,IACI,iBAAoC;EACtC,OAAO,KAAK;CACd;CACA,IAAI,eAAe,GAAe;EAChC,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,kBAAkB,EAAiB,GAAO,CAAC,UAAU,MAAM,GAAY,QAAQ,GACpF,KAAK,cAAc,kBAAkB,CAAG;CAC1C;CAKA,IACI,YAAoB;EACtB,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAgB,GAAG,GAAG,KAAO,GAAG,GAClD,KAAK,cAAc,aAAa,CAAG;CACrC;CAKA,oBAA6B;EAG3B,AAFA,MAAM,kBAAkB,GACxB,KAAK,eAAe,GACpB,KAAK,eAAe;CACtB;CAEA,uBAAgC;EAE9B,AADA,MAAM,qBAAqB,GAC3B,KAAK,iBAAiB,MAAM;CAC9B;CAEA,WAA8B,GAAuB;EAQnD,AAPA,MAAM,WAAW,CAAK,IAElB,EAAM,IAAI,WAAW,KAAK,EAAM,IAAI,cAAc,MACpD,KAAK,eAAe,GAIlB,EAAM,IAAI,cAAc,MAE1B,KAAK,gBAAgB,kBAAkB,KAAK,WAAW,MAAM,GAC7D,KAAK,eAAe;CAExB;CAEA,IAAY,SAAS;EAMnB,OALK,KAAK,eAER,KAAK,iBAAiB,UACtB,KAAK,iBAAiB,SAAS,mBAC/B,KAAK,iBAAiB,SAAS,OACjB,SAAS,KAAK,eALC;CAMjC;CAEA,iBAAyB;EAIvB,AAHA,KAAK,iBAAiB,MAAM,GAC5B,KAAK,kBAAkB,IAAI,gBAAgB,GAE3C,KAAK,OAAO,iBACV,gBACM;GACJ,KAAK,eAAe;EACtB,GACA;GAAE,QAAQ,KAAK,gBAAgB;GAAQ,SAAS;EAAK,CACvD;CACF;CAEA,iBAAyB;EACvB,IAAM,IAAS,KAAK;EACpB,IAAI,MAAW,QACb,KAAK,UAAU,EAAiB,KAAK,KAAK;OACrC,IAAI,aAAkB,aAC3B,KAAK,UAAU,EAAO,aAAa,KAAK;OAExC,MAAU,MAAM,kDAAkD;CAEtE;CAEA,QAAQ;EACN,KAAK,OAAO,SAAS;GACnB,KAAK;GACL,UAAU,KAAK;EACjB,CAAC;CACH;CAGA,QAAgB,GAAkB;EAChC,CAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,eAAe,GACjB,KAAK,MAAM;CAEf;CAEA,SAAkB;EAChB,OAAO,CAAI;sEACuD,KAAK,MAAM,YAAY,KAAK,QAAQ;;;iCAGzE,EAAoB;;;;;CAKnD;AAGF;AAjHG,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,WAAW;CAAmB,YAAY;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,kBAAA,IAAA,GAU1E,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,EAAE,WAAW,GAAM,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GAE7B,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAWxC,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GA5BR,IAAA,EAAA,CAAA,EAAc,iBAAiB,CAAA,GAAA,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
+ declare const ALLOWED_TYPES: readonly ["button", "submit", "reset"];
2
3
  export declare class WebUiButton extends LitElement {
3
4
  static styles: import('lit').CSSResult[];
4
5
  get variant(): 'primary' | 'secondary' | 'ghost' | 'danger' | 'glass';
@@ -9,7 +10,10 @@ export declare class WebUiButton extends LitElement {
9
10
  full: boolean;
10
11
  icon: boolean;
11
12
  size: string;
12
- /** size="32" → 32x32,size="32x80" → 32x80 */
13
+ get type(): (typeof ALLOWED_TYPES)[number];
14
+ set type(value: unknown);
15
+ private _type;
16
+ ariaLabel: string | null;
13
17
  private get _sizeStyle();
14
18
  private handleClick;
15
19
  render(): import('lit').TemplateResult<1>;
@@ -20,3 +24,4 @@ declare global {
20
24
  'web-ui-button': WebUiButton;
21
25
  }
22
26
  }
27
+ export {};
@@ -7,17 +7,22 @@ import i from "./style.js";
7
7
  import { LitElement as a, html as o, nothing as s, unsafeCSS as c } from "lit";
8
8
  import { customElement as l, property as u } from "lit/decorators.js";
9
9
  import { classMap as d } from "lit/directives/class-map.js";
10
- import { styleMap as f } from "lit/directives/style-map.js";
10
+ import { ifDefined as f } from "lit/directives/if-defined.js";
11
+ import { styleMap as p } from "lit/directives/style-map.js";
11
12
  //#region src/components/button/index.ts
12
- var p = [
13
+ var m = [
13
14
  "primary",
14
15
  "secondary",
15
16
  "ghost",
16
17
  "danger",
17
18
  "glass"
18
- ], m = class extends a {
19
+ ], h = [
20
+ "button",
21
+ "submit",
22
+ "reset"
23
+ ], g = class extends a {
19
24
  constructor(...e) {
20
- super(...e), this._variant = "glass", this.disabled = !1, this.loading = !1, this.full = !1, this.icon = !1, this.size = "";
25
+ super(...e), this._variant = "glass", this.disabled = !1, this.loading = !1, this.full = !1, this.icon = !1, this.size = "", this._type = "button", this.ariaLabel = null;
21
26
  }
22
27
  static {
23
28
  this.styles = [c(t), c(i)];
@@ -27,7 +32,14 @@ var p = [
27
32
  }
28
33
  set variant(e) {
29
34
  let t = this._variant;
30
- this._variant = r(e, p, "glass"), this.requestUpdate("variant", t);
35
+ this._variant = r(e, m, "glass"), this.requestUpdate("variant", t);
36
+ }
37
+ get type() {
38
+ return this._type;
39
+ }
40
+ set type(e) {
41
+ let t = this._type;
42
+ this._type = r(e, h, "button"), this.requestUpdate("type", t);
31
43
  }
32
44
  get _sizeStyle() {
33
45
  if (!this.size) return {};
@@ -38,10 +50,13 @@ var p = [
38
50
  (this.disabled || this.loading) && (e.preventDefault(), e.stopPropagation());
39
51
  }
40
52
  render() {
53
+ let e = { "wui-glass": this.variant === "glass" && !this.hasAttribute("group") };
41
54
  return o`
42
55
  <button
43
- class=${d({ "wui-glass": this.variant === "glass" && !this.hasAttribute("group") })}
44
- style=${this.size ? f(this._sizeStyle) : s}
56
+ type=${this.type}
57
+ aria-label=${f(this.ariaLabel)}
58
+ class=${d(e)}
59
+ style=${this.size ? p(this._sizeStyle) : s}
45
60
  ?disabled=${this.disabled || this.loading}
46
61
  @click=${this.handleClick}
47
62
  >
@@ -58,23 +73,29 @@ var p = [
58
73
  e([u({
59
74
  type: String,
60
75
  reflect: !0
61
- })], m.prototype, "variant", null), e([u({
76
+ })], g.prototype, "variant", null), e([u({
62
77
  type: Boolean,
63
78
  reflect: !0
64
- })], m.prototype, "disabled", void 0), e([u({
79
+ })], g.prototype, "disabled", void 0), e([u({
65
80
  type: Boolean,
66
81
  reflect: !0
67
- })], m.prototype, "loading", void 0), e([u({
82
+ })], g.prototype, "loading", void 0), e([u({
68
83
  type: Boolean,
69
84
  reflect: !0
70
- })], m.prototype, "full", void 0), e([u({
85
+ })], g.prototype, "full", void 0), e([u({
71
86
  type: Boolean,
72
87
  reflect: !0
73
- })], m.prototype, "icon", void 0), e([u({
88
+ })], g.prototype, "icon", void 0), e([u({
74
89
  type: String,
75
90
  reflect: !0
76
- })], m.prototype, "size", void 0), m = e([l("web-ui-button")], m);
91
+ })], g.prototype, "size", void 0), e([u({
92
+ type: String,
93
+ reflect: !0
94
+ })], g.prototype, "type", null), e([u({
95
+ type: String,
96
+ attribute: "aria-label"
97
+ })], g.prototype, "ariaLabel", void 0), g = e([l("web-ui-button")], g);
77
98
  //#endregion
78
- export { m as WebUiButton };
99
+ export { g as WebUiButton };
79
100
 
80
101
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\n// web-ui-icon 必须注册(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideLoaderCircle } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_VARIANTS = ['primary', 'secondary', 'ghost', 'danger', 'glass'] as const\n\n@customElement('web-ui-button')\nexport class WebUiButton extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get variant(): 'primary' | 'secondary' | 'ghost' | 'danger' | 'glass' {\n return this._variant\n }\n set variant(v: string) {\n const old = this._variant\n this._variant = normalizeLiteral(v, ALLOWED_VARIANTS, 'glass')\n this.requestUpdate('variant', old)\n }\n private _variant: 'primary' | 'secondary' | 'ghost' | 'danger' | 'glass' = 'glass'\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) loading = false\n @property({ type: Boolean, reflect: true }) full = false\n @property({ type: Boolean, reflect: true }) icon = false\n @property({ type: String, reflect: true }) size = ''\n\n /** size=\"32\" → 32x32,size=\"32x80\" → 32x80 */\n private get _sizeStyle(): Record<string, string> {\n if (!this.size) return {}\n const [h, w] = this.size.split('x')\n const style: Record<string, string> = { '--wui-button-size': `${h}px` }\n if (w) style['--wui-button-width'] = `${w}px`\n return style\n }\n\n private handleClick(e: Event) {\n if (this.disabled || this.loading) {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n\n override render() {\n const btnClass = { 'wui-glass': this.variant === 'glass' && !this.hasAttribute('group') }\n return html`\n <button\n class=${classMap(btnClass)}\n style=${this.size ? styleMap(this._sizeStyle) : nothing}\n ?disabled=${this.disabled || this.loading}\n @click=${this.handleClick}\n >\n ${this.loading ? html`<web-ui-icon .icon=${lucideLoaderCircle} spin></web-ui-icon>` : ''}\n ${this.icon\n ? html`<slot></slot>`\n : html`\n <slot name=\"prefix\"></slot>\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `}\n </button>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-button': WebUiButton\n }\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,IAAmB;CAAC;CAAW;CAAa;CAAS;CAAU;AAAO,GAG/D,IAAN,cAA0B,EAAW;;EAkBQ,aANyB,KAAA,WAAA,SAEpB,KAAA,WAAA,IACD,KAAA,UAAA,IACH,KAAA,OAAA,IACA,KAAA,OAAA,IACD,KAAA,OAAA;;;EAjBzB,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAE5D,IACI,UAAkE;EACpE,OAAO,KAAK;CACd;CACA,IAAI,QAAQ,GAAW;EACrB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,WAAW,EAAiB,GAAG,GAAkB,OAAO,GAC7D,KAAK,cAAc,WAAW,CAAG;CACnC;CAUA,IAAY,aAAqC;EAC/C,IAAI,CAAC,KAAK,MAAM,OAAO,CAAC;EACxB,IAAM,CAAC,GAAG,KAAK,KAAK,KAAK,MAAM,GAAG,GAC5B,IAAgC,EAAE,qBAAqB,GAAG,EAAE,IAAI;EAEtE,OADI,MAAG,EAAM,wBAAwB,GAAG,EAAE,MACnC;CACT;CAEA,YAAoB,GAAU;EAC5B,CAAI,KAAK,YAAY,KAAK,aACxB,EAAE,eAAe,GACjB,EAAE,gBAAgB;CAEtB;CAEA,SAAkB;EAEhB,OAAO,CAAI;;gBAEC,EAAS,EAHF,aAAa,KAAK,YAAY,WAAW,CAAC,KAAK,aAAa,OAAO,EAGjE,CAAQ,EAAE;gBACnB,KAAK,OAAO,EAAS,KAAK,UAAU,IAAI,EAAQ;oBAC5C,KAAK,YAAY,KAAK,QAAQ;iBACjC,KAAK,YAAY;;UAExB,KAAK,UAAU,CAAI,sBAAsB,EAAmB,wBAAwB,GAAG;UACvF,KAAK,OACH,CAAI,kBACJ,CAAI;;;;cAIF;;;CAGZ;AAGF;AAvDG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,IAAA,GAWxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAnB1C,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideLoaderCircle } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_VARIANTS = ['primary', 'secondary', 'ghost', 'danger', 'glass'] as const\nconst ALLOWED_TYPES = ['button', 'submit', 'reset'] as const\n\n@customElement('web-ui-button')\nexport class WebUiButton extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get variant(): 'primary' | 'secondary' | 'ghost' | 'danger' | 'glass' {\n return this._variant\n }\n set variant(v: string) {\n const old = this._variant\n this._variant = normalizeLiteral(v, ALLOWED_VARIANTS, 'glass')\n this.requestUpdate('variant', old)\n }\n private _variant: 'primary' | 'secondary' | 'ghost' | 'danger' | 'glass' = 'glass'\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) loading = false\n @property({ type: Boolean, reflect: true }) full = false\n @property({ type: Boolean, reflect: true }) icon = false\n @property({ type: String, reflect: true }) size = ''\n\n @property({ type: String, reflect: true })\n get type(): (typeof ALLOWED_TYPES)[number] {\n return this._type\n }\n set type(value: unknown) {\n const old = this._type\n this._type = normalizeLiteral(value, ALLOWED_TYPES, 'button')\n this.requestUpdate('type', old)\n }\n private _type: (typeof ALLOWED_TYPES)[number] = 'button'\n\n // Explicitly delegated accessible naming attributes.\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n\n // size=\"32\" → 32x32,size=\"32x80\" → 32x80\n private get _sizeStyle(): Record<string, string> {\n if (!this.size) return {}\n const [h, w] = this.size.split('x')\n const style: Record<string, string> = { '--wui-button-size': `${h}px` }\n if (w) style['--wui-button-width'] = `${w}px`\n return style\n }\n\n private handleClick(e: Event) {\n if (this.disabled || this.loading) {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n\n override render() {\n const btnClass = { 'wui-glass': this.variant === 'glass' && !this.hasAttribute('group') }\n return html`\n <button\n type=${this.type}\n aria-label=${ifDefined(this.ariaLabel)}\n class=${classMap(btnClass)}\n style=${this.size ? styleMap(this._sizeStyle) : nothing}\n ?disabled=${this.disabled || this.loading}\n @click=${this.handleClick}\n >\n ${this.loading ? html`<web-ui-icon .icon=${lucideLoaderCircle} spin></web-ui-icon>` : ''}\n ${this.icon\n ? html`<slot></slot>`\n : html`\n <slot name=\"prefix\"></slot>\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `}\n </button>\n `\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-button': WebUiButton\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,IAAM,IAAmB;CAAC;CAAW;CAAa;CAAS;CAAU;AAAO,GACtE,IAAgB;CAAC;CAAU;CAAU;AAAO,GAGrC,IAAN,cAA0B,EAAW;;EAgC+C,aApBd,KAAA,WAAA,SAEpB,KAAA,WAAA,IACD,KAAA,UAAA,IACH,KAAA,OAAA,IACA,KAAA,OAAA,IACD,KAAA,OAAA,IAWF,KAAA,QAAA,UAGyC,KAAA,YAAA;;;EA/BhE,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAE5D,IACI,UAAkE;EACpE,OAAO,KAAK;CACd;CACA,IAAI,QAAQ,GAAW;EACrB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,WAAW,EAAiB,GAAG,GAAkB,OAAO,GAC7D,KAAK,cAAc,WAAW,CAAG;CACnC;CASA,IACI,OAAuC;EACzC,OAAO,KAAK;CACd;CACA,IAAI,KAAK,GAAgB;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,QAAQ,EAAiB,GAAO,GAAe,QAAQ,GAC5D,KAAK,cAAc,QAAQ,CAAG;CAChC;CAOA,IAAY,aAAqC;EAC/C,IAAI,CAAC,KAAK,MAAM,OAAO,CAAC;EACxB,IAAM,CAAC,GAAG,KAAK,KAAK,KAAK,MAAM,GAAG,GAC5B,IAAgC,EAAE,qBAAqB,GAAG,EAAE,IAAI;EAEtE,OADI,MAAG,EAAM,wBAAwB,GAAG,EAAE,MACnC;CACT;CAEA,YAAoB,GAAU;EAC5B,CAAI,KAAK,YAAY,KAAK,aACxB,EAAE,eAAe,GACjB,EAAE,gBAAgB;CAEtB;CAEA,SAAkB;EAChB,IAAM,IAAW,EAAE,aAAa,KAAK,YAAY,WAAW,CAAC,KAAK,aAAa,OAAO,EAAE;EACxF,OAAO,CAAI;;eAEA,KAAK,KAAK;qBACJ,EAAU,KAAK,SAAS,EAAE;gBAC/B,EAAS,CAAQ,EAAE;gBACnB,KAAK,OAAO,EAAS,KAAK,UAAU,IAAI,EAAQ;oBAC5C,KAAK,YAAY,KAAK,QAAQ;iBACjC,KAAK,YAAY;;UAExB,KAAK,UAAU,CAAI,sBAAsB,EAAmB,wBAAwB,GAAG;UACvF,KAAK,OACH,CAAI,kBACJ,CAAI;;;;cAIF;;;CAGZ;AAGF;AAvEG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,IAAA,GAWxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAExC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,IAAA,GAYxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAjCpD,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/button/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([full]){width:100%;display:block}:host([disabled]){cursor:not-allowed}button{cursor:pointer;-webkit-user-select:none;user-select:none;gap:var(--wui-button-gap,8px);box-sizing:border-box;width:var(--wui-button-width,max-content);min-width:var(--wui-button-size,auto);height:var(--wui-button-size,40px);padding:0 var(--wui-button-px,16px);font-size:var(--wui-font-size,14px);color:var(--wui-button-color);white-space:nowrap;background-color:var(--wui-button-bg);transition:transform var(--wui-duration-press,.12s) var(--wui-ease-out,cubic-bezier(.23, 1, .32, 1)), background-color var(--wui-duration-fast,.16s) ease;border:1px solid #0000;border-radius:2147483647px;justify-content:center;align-items:center;line-height:1;display:inline-flex;position:relative;overflow:clip}button:disabled{cursor:not-allowed;opacity:.4}button:focus-visible{outline:3px solid var(--wui-focus-ring,#08f6);outline-offset:2px}button:active:not(:disabled){transform:scale(var(--wui-scale-press,.97));background-color:var(--wui-button-bg-active)}@media (hover:hover) and (pointer:fine){button:hover:not(:disabled){background-color:var(--wui-button-bg-hover)}}@media (prefers-reduced-motion:reduce){button{transition:background-color var(--wui-duration-fast,.16s) ease}button:active:not(:disabled){transform:none}}:host([full]) button{width:100%;display:flex}:host([icon]) button{aspect-ratio:1;padding:0}:host([variant=primary]){--wui-button-color:var(--wui-color-on-accent,#fff);--wui-button-bg:var(--wui-color-accent,#08f);--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-accent,#08f) 88%, var(--wui-color-text,#1b1b1b));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-accent,#08f) 76%, var(--wui-color-text,#1b1b1b))}:host([variant=secondary]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:var(--wui-color-surface-raised-mid,#dfdfdf);--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-surface-raised-mid,#dfdfdf) 90%, var(--wui-color-text,#1b1b1b));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-surface-raised-mid,#dfdfdf) 80%, var(--wui-color-text,#1b1b1b))}:host([variant=ghost]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 10%, transparent)}:host([variant=danger]){--wui-button-color:var(--wui-color-danger,#dc2626);--wui-button-bg:color-mix(in srgb, var(--wui-color-danger,#dc2626) 18%, var(--wui-color-surface,#fff));--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-danger,#dc2626) 26%, var(--wui-color-surface,#fff));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-danger,#dc2626) 34%, var(--wui-color-surface,#fff))}:host([variant=glass]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 10%, transparent)}:host([group]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 10%, transparent);position:relative}:host([group]:not([last])):after{content:\"\";width:var(--wui-button-divider-width,0);background-color:var(--wui-color-border,#0000001a);height:24px;position:absolute;top:50%;right:-2px;transform:translateY(-50%)}:host([group][direction=vertical]:not([last])):after{width:24px;height:var(--wui-button-divider-width,0);inset:auto auto -2px 50%;transform:translate(-50%)}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{justify-content:center;align-items:center;display:inline-flex}:host([full]){width:100%;display:block}:host([disabled]){cursor:not-allowed}button{cursor:pointer;-webkit-user-select:none;user-select:none;gap:var(--wui-button-gap,8px);box-sizing:border-box;width:var(--wui-button-width,max-content);min-width:var(--wui-button-size,auto);height:var(--wui-button-size,40px);padding:0 var(--wui-button-px,16px);font-size:var(--wui-font-size,14px);color:var(--wui-button-color);white-space:nowrap;background-color:var(--wui-button-bg);transition:background-color var(--wui-duration-trigger,.16s) ease;border:1px solid #0000;border-radius:2147483647px;justify-content:center;align-items:center;line-height:1;display:inline-flex;position:relative;overflow:clip}button:disabled{cursor:not-allowed;opacity:.4}button:focus-visible{outline:3px solid var(--wui-focus-ring,#08f6);outline-offset:2px}@media (hover:hover) and (pointer:fine){button:hover:not(:disabled){background-color:var(--wui-button-bg-hover)}}button:active:not(:disabled){background-color:var(--wui-button-bg-active)}@media (prefers-reduced-motion:reduce){button{transition:background-color var(--wui-duration-trigger,.16s) ease}}:host([full]) button{width:100%;display:flex}:host([icon]) button{aspect-ratio:1;padding:0}:host([variant=primary]){--wui-button-color:var(--wui-color-on-accent,#fff);--wui-button-bg:var(--wui-color-accent,#08f);--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-accent,#08f) 88%, var(--wui-color-text,#1b1b1b));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-accent,#08f) 65%, var(--wui-color-text,#1b1b1b))}:host([variant=secondary]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:var(--wui-color-surface-raised-mid,#dfdfdf);--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-surface-raised-mid,#dfdfdf) 90%, var(--wui-color-text,#1b1b1b));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-surface-raised-mid,#dfdfdf) 70%, var(--wui-color-text,#1b1b1b))}:host([variant=ghost]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent)}:host([variant=danger]){--wui-button-color:var(--wui-color-danger,#dc2626);--wui-button-bg:color-mix(in srgb, var(--wui-color-danger,#dc2626) 18%, var(--wui-color-surface,#fff));--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-danger,#dc2626) 26%, var(--wui-color-surface,#fff));--wui-button-bg-active:color-mix(in srgb, var(--wui-color-danger,#dc2626) 45%, var(--wui-color-surface,#fff))}:host([variant=glass]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent)}:host([group]){--wui-button-color:var(--wui-color-text,#1b1b1b);--wui-button-bg:transparent;--wui-button-bg-hover:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent);--wui-button-bg-active:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent);position:relative}:host([group]:not([last])):after{content:\"\";width:var(--wui-button-divider-width,0);background-color:var(--wui-color-border,#0000001a);height:24px;position:absolute;top:50%;right:-2px;transform:translateY(-50%)}:host([group][direction=vertical]:not([last])):after{width:24px;height:var(--wui-button-divider-width,0);inset:auto auto -2px 50%;transform:translate(-50%)}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/button/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-block;\n}\n\n:host([full]) {\n display: block;\n width: 100%;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\nbutton {\n cursor: pointer;\n user-select: none;\n\n position: relative;\n\n overflow: clip;\n display: inline-flex;\n gap: var(--wui-button-gap, 8px);\n align-items: center;\n justify-content: center;\n\n box-sizing: border-box;\n width: var(--wui-button-width, max-content);\n min-width: var(--wui-button-size, auto);\n height: var(--wui-button-size, 40px);\n padding: 0 var(--wui-button-px, 16px);\n border: 1px solid transparent;\n border-radius: calc(infinity * 1px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1;\n color: var(--wui-button-color);\n white-space: nowrap;\n\n background-color: var(--wui-button-bg);\n\n transition:\n transform var(--wui-duration-press, 120ms) var(--wui-ease-out, cubic-bezier(0.23, 1, 0.32, 1)),\n background-color var(--wui-duration-fast, 160ms) ease;\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n &:focus-visible {\n outline: 3px solid var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n\n &:active:not(:disabled) {\n transform: scale(var(--wui-scale-press, 0.97));\n background-color: var(--wui-button-bg-active);\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n button:hover:not(:disabled) {\n background-color: var(--wui-button-bg-hover);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n button {\n transition: background-color var(--wui-duration-fast, 160ms) ease;\n }\n\n button:active:not(:disabled) {\n transform: none;\n }\n}\n\n/* ===== Full width ===== */\n\n:host([full]) button {\n display: flex;\n width: 100%;\n}\n\n/* ===== Icon mode ===== */\n\n:host([icon]) button {\n aspect-ratio: 1;\n padding: 0;\n}\n\n/* ===== Variant: primary (默认) ===== */\n\n:host([variant='primary']) {\n --wui-button-color: var(--wui-color-on-accent, #fff);\n --wui-button-bg: var(--wui-color-accent, #08f);\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-accent, #08f) 88%, var(--wui-color-text, #1b1b1b));\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-accent, #08f) 76%, var(--wui-color-text, #1b1b1b));\n}\n\n/* ===== Variant: secondary ===== */\n\n:host([variant='secondary']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: var(--wui-color-surface-raised-mid, #dfdfdf);\n --wui-button-bg-hover: color-mix(\n in srgb,\n var(--wui-color-surface-raised-mid, #dfdfdf) 90%,\n var(--wui-color-text, #1b1b1b)\n );\n --wui-button-bg-active: color-mix(\n in srgb,\n var(--wui-color-surface-raised-mid, #dfdfdf) 80%,\n var(--wui-color-text, #1b1b1b)\n );\n}\n\n/* ===== Variant: ghost ===== */\n\n:host([variant='ghost']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 10%, transparent);\n}\n\n/* ===== Variant: danger ===== */\n\n:host([variant='danger']) {\n --wui-button-color: var(--wui-color-danger, #dc2626);\n --wui-button-bg: color-mix(in srgb, var(--wui-color-danger, #dc2626) 18%, var(--wui-color-surface, #fff));\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-danger, #dc2626) 26%, var(--wui-color-surface, #fff));\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-danger, #dc2626) 34%, var(--wui-color-surface, #fff));\n}\n\n/* ===== Variant: glass (玻璃) ===== */\n\n/* .wui-glass 样式由 @/assets/glass.css 提供 */\n:host([variant='glass']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 10%, transparent);\n}\n\n/* ===== Group context ===== */\n\n:host([group]) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 10%, transparent);\n position: relative;\n}\n\n:host([group]:not([last]))::after {\n content: '';\n\n position: absolute;\n top: 50%;\n right: -2px;\n transform: translateY(-50%);\n\n width: var(--wui-button-divider-width, 0);\n height: 24px;\n\n background-color: var(--wui-color-border, rgb(0 0 0 / 0.1));\n}\n\n:host([group][direction='vertical']:not([last]))::after {\n top: auto;\n right: auto;\n bottom: -2px;\n left: 50%;\n transform: translateX(-50%);\n\n width: 24px;\n height: var(--wui-button-divider-width, 0);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/button/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n /* inline-flex 让内层按钮在宿主内完全居中,避免继承的行高撑高宿主、导致图标偏移 */\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n:host([full]) {\n display: block;\n width: 100%;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\nbutton {\n cursor: pointer;\n user-select: none;\n\n position: relative;\n\n overflow: clip;\n display: inline-flex;\n gap: var(--wui-button-gap, 8px);\n align-items: center;\n justify-content: center;\n\n box-sizing: border-box;\n width: var(--wui-button-width, max-content);\n min-width: var(--wui-button-size, auto);\n height: var(--wui-button-size, 40px);\n padding: 0 var(--wui-button-px, 16px);\n border: 1px solid transparent;\n border-radius: calc(infinity * 1px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1;\n color: var(--wui-button-color);\n white-space: nowrap;\n\n background-color: var(--wui-button-bg);\n\n transition: background-color var(--wui-duration-trigger, 160ms) ease;\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n &:focus-visible {\n outline: 3px solid var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n button:hover:not(:disabled) {\n background-color: var(--wui-button-bg-hover);\n }\n}\n\nbutton:active:not(:disabled) {\n background-color: var(--wui-button-bg-active);\n}\n\n@media (prefers-reduced-motion: reduce) {\n button {\n transition: background-color var(--wui-duration-trigger, 160ms) ease;\n }\n}\n\n/* ===== Full width ===== */\n\n:host([full]) button {\n display: flex;\n width: 100%;\n}\n\n/* ===== Icon mode ===== */\n\n:host([icon]) button {\n aspect-ratio: 1;\n padding: 0;\n}\n\n/* ===== Variant: primary (默认) ===== */\n\n:host([variant='primary']) {\n --wui-button-color: var(--wui-color-on-accent, #fff);\n --wui-button-bg: var(--wui-color-accent, #08f);\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-accent, #08f) 88%, var(--wui-color-text, #1b1b1b));\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-accent, #08f) 65%, var(--wui-color-text, #1b1b1b));\n}\n\n/* ===== Variant: secondary ===== */\n\n:host([variant='secondary']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: var(--wui-color-surface-raised-mid, #dfdfdf);\n --wui-button-bg-hover: color-mix(\n in srgb,\n var(--wui-color-surface-raised-mid, #dfdfdf) 90%,\n var(--wui-color-text, #1b1b1b)\n );\n --wui-button-bg-active: color-mix(\n in srgb,\n var(--wui-color-surface-raised-mid, #dfdfdf) 70%,\n var(--wui-color-text, #1b1b1b)\n );\n}\n\n/* ===== Variant: ghost ===== */\n\n:host([variant='ghost']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent);\n}\n\n/* ===== Variant: danger ===== */\n\n:host([variant='danger']) {\n --wui-button-color: var(--wui-color-danger, #dc2626);\n --wui-button-bg: color-mix(in srgb, var(--wui-color-danger, #dc2626) 18%, var(--wui-color-surface, #fff));\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-danger, #dc2626) 26%, var(--wui-color-surface, #fff));\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-danger, #dc2626) 45%, var(--wui-color-surface, #fff));\n}\n\n/* ===== Variant: glass (玻璃) ===== */\n\n/* .wui-glass 样式由 @/assets/glass.css 提供 */\n:host([variant='glass']) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent);\n}\n\n/* ===== Group context ===== */\n\n:host([group]) {\n --wui-button-color: var(--wui-color-text, #1b1b1b);\n --wui-button-bg: transparent;\n --wui-button-bg-hover: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent);\n --wui-button-bg-active: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent);\n position: relative;\n}\n\n:host([group]:not([last]))::after {\n content: '';\n\n position: absolute;\n top: 50%;\n right: -2px;\n transform: translateY(-50%);\n\n width: var(--wui-button-divider-width, 0);\n height: 24px;\n\n background-color: var(--wui-color-border, rgb(0 0 0 / 0.1));\n}\n\n:host([group][direction='vertical']:not([last]))::after {\n top: auto;\n right: auto;\n bottom: -2px;\n left: 50%;\n transform: translateX(-50%);\n\n width: 24px;\n height: var(--wui-button-divider-width, 0);\n}\n"],"mappings":""}
@@ -2,11 +2,9 @@ import { LitElement } from 'lit';
2
2
  export declare class WebUiCheckbox extends LitElement {
3
3
  static styles: import('lit').CSSResult;
4
4
  static formAssociated: boolean;
5
- /** 内部表单关联实例(connectedCallback 中初始化) */
6
5
  private _internals?;
7
6
  private _formDisabled;
8
7
  private _groupDisabled;
9
- /** 内部 checked 状态,通过 getter/setter 暴露为公共 API */
10
8
  private _checked;
11
9
  get checked(): boolean;
12
10
  set checked(v: boolean);
@@ -23,7 +21,6 @@ export declare class WebUiCheckbox extends LitElement {
23
21
  updated(): void;
24
22
  private _syncFormValue;
25
23
  private _syncValidity;
26
- /** 用户点击切换 */
27
24
  private handleClick;
28
25
  private handleKeyDown;
29
26
  render(): import('lit').TemplateResult<1>;