@greypan/web-ui 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.CN.md +43 -38
  2. package/README.md +53 -47
  3. package/dist/assets/menu-portal.js +1 -1
  4. package/dist/assets/menu-portal.js.map +1 -1
  5. package/dist/assets/toast-containers.js +1 -1
  6. package/dist/assets/toast-containers.js.map +1 -1
  7. package/dist/components/back-top/index.d.ts +3 -1
  8. package/dist/components/back-top/index.js +16 -12
  9. package/dist/components/back-top/index.js.map +1 -1
  10. package/dist/components/back-top/style.js +1 -1
  11. package/dist/components/back-top/style.js.map +1 -1
  12. package/dist/components/context-menu/index.d.ts +3 -4
  13. package/dist/components/context-menu/index.js +55 -69
  14. package/dist/components/context-menu/index.js.map +1 -1
  15. package/dist/components/context-menu/style.js +1 -1
  16. package/dist/components/context-menu/style.js.map +1 -1
  17. package/dist/components/dialog/index.d.ts +4 -11
  18. package/dist/components/dialog/index.js +29 -53
  19. package/dist/components/dialog/index.js.map +1 -1
  20. package/dist/components/drawer/index.d.ts +4 -11
  21. package/dist/components/drawer/index.js +42 -63
  22. package/dist/components/drawer/index.js.map +1 -1
  23. package/dist/components/dropdown/index.d.ts +3 -3
  24. package/dist/components/dropdown/index.js +70 -78
  25. package/dist/components/dropdown/index.js.map +1 -1
  26. package/dist/components/dropdown/style.js +1 -1
  27. package/dist/components/dropdown/style.js.map +1 -1
  28. package/dist/components/dropdown-item/style.js +1 -1
  29. package/dist/components/dropdown-item/style.js.map +1 -1
  30. package/dist/components/option/style.js +1 -1
  31. package/dist/components/option/style.js.map +1 -1
  32. package/dist/components/popover/index.d.ts +2 -5
  33. package/dist/components/popover/index.js +47 -70
  34. package/dist/components/popover/index.js.map +1 -1
  35. package/dist/components/select/index.d.ts +4 -7
  36. package/dist/components/select/index.js +64 -74
  37. package/dist/components/select/index.js.map +1 -1
  38. package/dist/components/select/style.js +1 -1
  39. package/dist/components/select/style.js.map +1 -1
  40. package/dist/components/switch/style.js +1 -1
  41. package/dist/components/switch/style.js.map +1 -1
  42. package/dist/components/theme/style.js +1 -1
  43. package/dist/components/theme/style.js.map +1 -1
  44. package/dist/components/toast/manager.js +1 -1
  45. package/dist/components/toast/manager.js.map +1 -1
  46. package/dist/components/toast/toast.d.ts +1 -1
  47. package/dist/components/toast/toast.js +26 -26
  48. package/dist/components/toast/toast.js.map +1 -1
  49. package/dist/components/tooltip/index.d.ts +3 -5
  50. package/dist/components/tooltip/index.js +61 -70
  51. package/dist/components/tooltip/index.js.map +1 -1
  52. package/dist/icons/generated/ooui-close.d.ts +6 -0
  53. package/dist/icons/generated/ooui-close.js +10 -0
  54. package/dist/icons/generated/ooui-close.js.map +1 -0
  55. package/dist/icons/index.d.ts +1 -0
  56. package/dist/icons/index.js +2 -1
  57. package/dist/shared/menu-portal/menu-portal.js +8 -1
  58. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  59. package/dist/shared/menu-portal/menu-tree.js +29 -0
  60. package/dist/shared/menu-portal/menu-tree.js.map +1 -0
  61. package/dist/shared/overlay/anchored-panel.js +49 -0
  62. package/dist/shared/overlay/anchored-panel.js.map +1 -0
  63. package/dist/shared/overlay/native-dialog-presence.js +45 -0
  64. package/dist/shared/overlay/native-dialog-presence.js.map +1 -0
  65. package/dist/shared/overlay/overlay.js +5 -2
  66. package/dist/shared/overlay/overlay.js.map +1 -1
  67. package/dist/shared/overlay/portal.js +3 -3
  68. package/dist/shared/overlay/portal.js.map +1 -1
  69. package/dist/shared/overlay/presence.js +1 -1
  70. package/dist/shared/overlay/presence.js.map +1 -1
  71. package/dist/shared/scroll-lock/scroll-lock.js +15 -1
  72. package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
  73. package/dist/types/vue.d.ts +2 -1
  74. package/package.json +1 -1
  75. package/dist/shared/property-converters/boolean-with-false-string.js +0 -9
  76. package/dist/shared/property-converters/boolean-with-false-string.js.map +0 -1
package/README.CN.md CHANGED
@@ -6,7 +6,9 @@
6
6
 
7
7
  ## 演示
8
8
 
9
- [查看演示](https://pan-z2l0ahvi.github.io/mono/)
9
+ [查看组件在 vue 中使用](https://pan-z2l0ahvi.github.io/mono/vue-web-ui-demo/)
10
+
11
+ [查看组件在 react 中使用](https://pan-z2l0ahvi.github.io/mono/react-web-ui-demo/)
10
12
 
11
13
  ## 安装
12
14
 
@@ -64,13 +66,12 @@ function App() {
64
66
 
65
67
  React 19 按 JSX 键名中的 `on` 后缀原样注册 Custom Element 事件。事件名大小写敏感:`open-change`
66
68
  必须绑定为 `onopen-change`,不能写成 `onOpenChange`。标准 `input` 和 `change` 事件仍使用 React
67
- 惯用的 `onInput` 和 `onChange`。默认值为 `true` 的属性应使用驼峰 JavaScript 属性传入,这样 `false`
68
- 才会传递给组件。
69
+ 惯用的 `onInput` 和 `onChange`。布尔属性遵循原生 HTML 语义:属性缺失为 `false`,属性存在为 `true`。
69
70
 
70
71
  ```tsx
71
72
  <web-ui-dialog
72
73
  open={open}
73
- lockScroll={false}
74
+ noScrollLock
74
75
  onopen-change={event => setOpen(event.detail.open)}
75
76
  />
76
77
  <web-ui-select value={value} onChange={event => setValue(event.currentTarget.value)} />
@@ -247,7 +248,7 @@ ArrowUp/ArrowDown 键增减数值。
247
248
  | `disabled` | `boolean` | `false` | 禁用状态 |
248
249
  | `required` | `boolean` | `false` | 必填校验 |
249
250
  | `portal` | `boolean` | `false` | 在主题浮层容器中渲染 |
250
- | `lock-scroll` | `boolean` | `true` | 打开时锁定页面滚动 |
251
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
251
252
  | `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | 显式 Portal 容器 |
252
253
 
253
254
  **事件:** `input`, `change`, `open-change` (`CustomEvent<{ open: boolean }>`)
@@ -425,11 +426,11 @@ ArrowUp/ArrowDown 键增减数值。
425
426
 
426
427
  模态对话框,使用原生 `<dialog>` 的 `showModal()`。
427
428
 
428
- | 属性 | 类型 | 默认值 | 说明 |
429
- | ------------------ | --------- | ------- | ------------------ |
430
- | `open` | `boolean` | `false` | 对话框可见性 |
431
- | `lock-scroll` | `boolean` | `true` | 打开时锁定页面滚动 |
432
- | `overlay-closable` | `boolean` | `true` | 点击遮罩关闭对话框 |
429
+ | 属性 | 类型 | 默认值 | 说明 |
430
+ | ------------------- | --------- | ------- | -------------------- |
431
+ | `open` | `boolean` | `false` | 对话框可见性 |
432
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
433
+ | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
433
434
 
434
435
  **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
435
436
 
@@ -443,14 +444,14 @@ ArrowUp/ArrowDown 键增减数值。
443
444
 
444
445
  侧边抽屉,使用原生 `<dialog>` 并自带关闭动画。
445
446
 
446
- | 属性 | 类型 | 默认值 | 说明 |
447
- | ------------------ | ---------------------------------------- | --------- | -------------------------------- |
448
- | `open` | `boolean` | `false` | 抽屉可见性 |
449
- | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | 滑入方向 |
450
- | `heading` | `string` | `''` | 标题文字(无 header 插槽时显示) |
451
- | `closable` | `boolean` | `false` | 显示关闭按钮 |
452
- | `lock-scroll` | `boolean` | `true` | 打开时锁定页面滚动 |
453
- | `overlay-closable` | `boolean` | `true` | 点击遮罩关闭抽屉 |
447
+ | 属性 | 类型 | 默认值 | 说明 |
448
+ | ------------------- | ---------------------------------------- | --------- | -------------------------------- |
449
+ | `open` | `boolean` | `false` | 抽屉可见性 |
450
+ | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | 滑入方向 |
451
+ | `heading` | `string` | `''` | 标题文字(无 header 插槽时显示) |
452
+ | `closable` | `boolean` | `false` | 显示关闭按钮 |
453
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
454
+ | `no-backdrop-close` | `boolean` | `false` | 禁止点击遮罩关闭 |
454
455
 
455
456
  **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
456
457
 
@@ -458,7 +459,7 @@ ArrowUp/ArrowDown 键增减数值。
458
459
 
459
460
  **方法:** `show()`, `close()`
460
461
 
461
- 关闭时保留原生 dialog 的 top layer,待 `--wui-duration-drawer` 过渡完成(默认 280ms)后调用 `dialog.close()`。Escape 始终走此关闭路径;`overlay-closable` 仅控制遮罩点击。
462
+ 关闭时保留原生 dialog 的 top layer,待 `--wui-duration-drawer` 过渡完成(默认 280ms)后调用 `dialog.close()`。Escape 始终走此关闭路径;`no-backdrop-close` 仅控制遮罩点击。
462
463
 
463
464
  ---
464
465
 
@@ -512,10 +513,10 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
512
513
 
513
514
  右键上下文菜单。
514
515
 
515
- | 属性 | 类型 | 默认值 | 说明 |
516
- | ------------- | --------- | ------- | ------------ |
517
- | `disabled` | `boolean` | `false` | 禁用状态 |
518
- | `lock-scroll` | `boolean` | `true` | 阻止背景滚动 |
516
+ | 属性 | 类型 | 默认值 | 说明 |
517
+ | ---------------- | --------- | ------- | ------------ |
518
+ | `disabled` | `boolean` | `false` | 禁用状态 |
519
+ | `no-scroll-lock` | `boolean` | `false` | 允许背景滚动 |
519
520
 
520
521
  **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
521
522
 
@@ -533,14 +534,14 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
533
534
 
534
535
  下拉菜单,支持多级子菜单。
535
536
 
536
- | 属性 | 类型 | 默认值 | 说明 |
537
- | ------------- | ----------- | ---------------- | ---------------- |
538
- | `open` | `boolean` | `false` | 菜单可见性 |
539
- | `disabled` | `boolean` | `false` | 禁用状态 |
540
- | `placement` | `Placement` | `'bottom-start'` | Floating UI 位置 |
541
- | `offset` | `number` | `4` | 与触发器距离 |
542
- | `match-width` | `boolean` | `false` | 匹配触发器宽度 |
543
- | `lock-scroll` | `boolean` | `true` | 锁定页面滚动 |
537
+ | 属性 | 类型 | 默认值 | 说明 |
538
+ | ---------------- | ----------- | ---------------- | -------------------- |
539
+ | `open` | `boolean` | `false` | 菜单可见性 |
540
+ | `disabled` | `boolean` | `false` | 禁用状态 |
541
+ | `placement` | `Placement` | `'bottom-start'` | Floating UI 位置 |
542
+ | `offset` | `number` | `4` | 与触发器距离 |
543
+ | `match-width` | `boolean` | `false` | 匹配触发器宽度 |
544
+ | `no-scroll-lock` | `boolean` | `false` | 打开时不锁定页面滚动 |
544
545
 
545
546
  **事件:** `open-change` (`CustomEvent<{ open: boolean }>`)
546
547
 
@@ -683,17 +684,19 @@ WebUiSpinner.hide() // 隐藏
683
684
 
684
685
  回到顶部按钮。
685
686
 
686
- | 属性 | 类型 | 默认值 | 说明 |
687
- | -------------- | ----------------------- | -------- | ------------------ |
688
- | `smooth` | `boolean` | `true` | 平滑滚动 |
689
- | `threshold` | `number` | `200` | 显示按钮的滚动阈值 |
690
- | `visible` | `boolean` | `false` | 当前可见状态 |
691
- | `scrollTarget` | `HTMLElement \| Window` | `window` | 滚动容器 |
687
+ | 属性 | 类型 | 默认值 | 说明 |
688
+ | ----------------- | ----------------------- | ---------- | ------------------ |
689
+ | `scroll-behavior` | `'smooth' \| 'auto'` | `'smooth'` | 滚动行为 |
690
+ | `threshold` | `number` | `200` | 显示按钮的滚动阈值 |
691
+ | `visible` | `boolean` | `false` | 当前可见状态 |
692
+ | `scrollTarget` | `HTMLElement \| Window` | `window` | 滚动容器 |
692
693
 
693
694
  **插槽:** `default`(自定义按钮内容)
694
695
 
695
696
  **方法:** `toTop()`
696
697
 
698
+ **定位:** `scrollTarget` 为 `window` 时按钮固定在视口角落;为 `HTMLElement` 时需将元素放置在容器内部,按钮通过 `position: sticky` 悬浮于容器底部角落。偏移量沿用 `--web-ui-back-top-top/right/bottom/left` CSS 变量。
699
+
697
700
  角色:`button`,键盘 Enter 触发回到顶部。
698
701
 
699
702
  #### `<web-ui-svg-draw-lines>`
@@ -724,7 +727,7 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
724
727
 
725
728
  **方法:** `getOverlayRoot()` — 返回 Portal 浮层容器
726
729
 
727
- 定义 `--wui-color-*`、`--wui-shadow-*`、`--wui-layer-*` 与 motion token。motion token 是稳定的主题契约,可在主题范围覆盖:`--wui-duration-press`、`--wui-duration-fast`、`--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`。
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`。
728
731
 
729
732
  ---
730
733
 
@@ -734,6 +737,8 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
734
737
 
735
738
  单个 Toast 通知。通过命令式 API 使用。
736
739
 
740
+ 直接使用元素时,`no-close-button` 是标准布尔属性,用于隐藏关闭按钮。
741
+
737
742
  **命令式 API:**
738
743
 
739
744
  ```ts
package/README.md CHANGED
@@ -6,7 +6,9 @@ English | [简体中文](./README.CN.md)
6
6
 
7
7
  ## Demo
8
8
 
9
- [View demo](https://pan-z2l0ahvi.github.io/mono/)
9
+ [View components used by vue](https://pan-z2l0ahvi.github.io/mono/vue-web-ui-demo/)
10
+
11
+ [View components used by react](https://pan-z2l0ahvi.github.io/mono/react-web-ui-demo/)
10
12
 
11
13
  ## Install
12
14
 
@@ -64,13 +66,13 @@ function App() {
64
66
 
65
67
  React 19 registers Custom Element events using the suffix of the JSX `on` key unchanged. Event names are
66
68
  case-sensitive: bind `open-change` as `onopen-change`, not `onOpenChange`. Standard `input` and `change`
67
- events continue to use React's conventional `onInput` and `onChange`. For a default-`true` property, pass the
68
- camel-cased JavaScript property so `false` reaches the element.
69
+ events continue to use React's conventional `onInput` and `onChange`. Boolean properties follow native HTML
70
+ semantics: absence is `false` and presence is `true`.
69
71
 
70
72
  ```tsx
71
73
  <web-ui-dialog
72
74
  open={open}
73
- lockScroll={false}
75
+ noScrollLock
74
76
  onopen-change={event => setOpen(event.detail.open)}
75
77
  />
76
78
  <web-ui-select value={value} onChange={event => setValue(event.currentTarget.value)} />
@@ -240,16 +242,16 @@ ArrowUp/ArrowDown keyboard increments and decrements the value.
240
242
 
241
243
  Select dropdown with option items, keyboard navigation, and portal support.
242
244
 
243
- | Attribute | Type | Default | Description |
244
- | ------------------ | ---------------------------------- | ------- | -------------------------------- |
245
- | `value` | `string` | `''` | Selected value |
246
- | `placeholder` | `string` | `''` | Placeholder text |
247
- | `name` | `string` | `''` | Form field name |
248
- | `disabled` | `boolean` | `false` | Disabled state |
249
- | `required` | `boolean` | `false` | Required validation |
250
- | `portal` | `boolean` | `false` | Render dropdown in theme overlay |
251
- | `lock-scroll` | `boolean` | `true` | Lock body scroll when open |
252
- | `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
245
+ | Attribute | Type | Default | Description |
246
+ | ------------------ | ---------------------------------- | ------- | --------------------------------- |
247
+ | `value` | `string` | `''` | Selected value |
248
+ | `placeholder` | `string` | `''` | Placeholder text |
249
+ | `name` | `string` | `''` | Form field name |
250
+ | `disabled` | `boolean` | `false` | Disabled state |
251
+ | `required` | `boolean` | `false` | Required validation |
252
+ | `portal` | `boolean` | `false` | Render dropdown in theme overlay |
253
+ | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
254
+ | `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
253
255
 
254
256
  **Events:** `input`, `change`, `open-change` (`CustomEvent<{ open: boolean }>`)
255
257
 
@@ -430,11 +432,11 @@ Propagates `direction` attribute to child buttons.
430
432
 
431
433
  Modal dialog using native `<dialog>` with `showModal()`.
432
434
 
433
- | Attribute | Type | Default | Description |
434
- | ------------------ | --------- | ------- | -------------------------- |
435
- | `open` | `boolean` | `false` | Dialog visibility |
436
- | `lock-scroll` | `boolean` | `true` | Lock body scroll when open |
437
- | `overlay-closable` | `boolean` | `true` | Close on backdrop click |
435
+ | Attribute | Type | Default | Description |
436
+ | ------------------- | --------- | ------- | --------------------------------- |
437
+ | `open` | `boolean` | `false` | Dialog visibility |
438
+ | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
439
+ | `no-backdrop-close` | `boolean` | `false` | Do not close on backdrop click |
438
440
 
439
441
  **Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
440
442
 
@@ -448,14 +450,14 @@ Uses native `<dialog>` with `@cancel` prevention (Escape calls `close()`). Click
448
450
 
449
451
  Side drawer using native `<dialog>` with closing animation.
450
452
 
451
- | Attribute | Type | Default | Description |
452
- | ------------------ | ---------------------------------------- | --------- | ----------------------------------------- |
453
- | `open` | `boolean` | `false` | Drawer visibility |
454
- | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | Slide-in direction |
455
- | `heading` | `string` | `''` | Title text (fallback when no header slot) |
456
- | `closable` | `boolean` | `false` | Show close button |
457
- | `lock-scroll` | `boolean` | `true` | Lock body scroll when open |
458
- | `overlay-closable` | `boolean` | `true` | Close on backdrop click |
453
+ | Attribute | Type | Default | Description |
454
+ | ------------------- | ---------------------------------------- | --------- | ----------------------------------------- |
455
+ | `open` | `boolean` | `false` | Drawer visibility |
456
+ | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | Slide-in direction |
457
+ | `heading` | `string` | `''` | Title text (fallback when no header slot) |
458
+ | `closable` | `boolean` | `false` | Show close button |
459
+ | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
460
+ | `no-backdrop-close` | `boolean` | `false` | Do not close on backdrop click |
459
461
 
460
462
  **Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
461
463
 
@@ -463,7 +465,7 @@ Side drawer using native `<dialog>` with closing animation.
463
465
 
464
466
  **Methods:** `show()`, `close()`
465
467
 
466
- Closing keeps the native dialog in the top layer until the `--wui-duration-drawer` transition completes (280ms by default), then calls `dialog.close()`. Escape always follows this close path; `overlay-closable` controls backdrop clicks only.
468
+ Closing keeps the native dialog in the top layer until the `--wui-duration-drawer` transition completes (280ms by default), then calls `dialog.close()`. Escape always follows this close path; `no-backdrop-close` controls backdrop clicks only.
467
469
 
468
470
  ---
469
471
 
@@ -517,10 +519,10 @@ Tooltip overlay using pointer/focus triggers.
517
519
 
518
520
  Right-click context menu.
519
521
 
520
- | Attribute | Type | Default | Description |
521
- | ------------- | --------- | ------- | ------------------------- |
522
- | `disabled` | `boolean` | `false` | Disabled state |
523
- | `lock-scroll` | `boolean` | `true` | Prevent background scroll |
522
+ | Attribute | Type | Default | Description |
523
+ | ---------------- | --------- | ------- | -------------------------- |
524
+ | `disabled` | `boolean` | `false` | Disabled state |
525
+ | `no-scroll-lock` | `boolean` | `false` | Allow background scrolling |
524
526
 
525
527
  **Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
526
528
 
@@ -538,14 +540,14 @@ Opens on `contextmenu` event. Menu items: `<web-ui-dropdown-item>`, `<web-ui-dro
538
540
 
539
541
  Dropdown menu with multi-level submenu support.
540
542
 
541
- | Attribute | Type | Default | Description |
542
- | ------------- | ----------- | ---------------- | -------------------------- |
543
- | `open` | `boolean` | `false` | Menu visibility |
544
- | `disabled` | `boolean` | `false` | Disabled state |
545
- | `placement` | `Placement` | `'bottom-start'` | Floating UI placement |
546
- | `offset` | `number` | `4` | Offset from trigger |
547
- | `match-width` | `boolean` | `false` | Match trigger width |
548
- | `lock-scroll` | `boolean` | `true` | Lock body scroll when open |
543
+ | Attribute | Type | Default | Description |
544
+ | ---------------- | ----------- | ---------------- | --------------------------------- |
545
+ | `open` | `boolean` | `false` | Menu visibility |
546
+ | `disabled` | `boolean` | `false` | Disabled state |
547
+ | `placement` | `Placement` | `'bottom-start'` | Floating UI placement |
548
+ | `offset` | `number` | `4` | Offset from trigger |
549
+ | `match-width` | `boolean` | `false` | Match trigger width |
550
+ | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
549
551
 
550
552
  **Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
551
553
 
@@ -688,17 +690,19 @@ Page layout grid.
688
690
 
689
691
  Scroll-to-top button.
690
692
 
691
- | Attribute | Type | Default | Description |
692
- | -------------- | ----------------------- | -------- | ------------------------ |
693
- | `smooth` | `boolean` | `true` | Smooth scroll |
694
- | `threshold` | `number` | `200` | Scroll threshold to show |
695
- | `visible` | `boolean` | `false` | Current visibility state |
696
- | `scrollTarget` | `HTMLElement \| Window` | `window` | Scroll container |
693
+ | Attribute | Type | Default | Description |
694
+ | ----------------- | ----------------------- | ---------- | ------------------------ |
695
+ | `scroll-behavior` | `'smooth' \| 'auto'` | `'smooth'` | Scroll behavior |
696
+ | `threshold` | `number` | `200` | Scroll threshold to show |
697
+ | `visible` | `boolean` | `false` | Current visibility state |
698
+ | `scrollTarget` | `HTMLElement \| Window` | `window` | Scroll container |
697
699
 
698
700
  **Slots:** `default` (custom button content)
699
701
 
700
702
  **Methods:** `toTop()`
701
703
 
704
+ **Positioning:** With `scrollTarget` as `window`, the button is fixed to the viewport corner. With `scrollTarget` as an `HTMLElement`, place the element inside that container and the button floats at the container's bottom corner via `position: sticky`. Offsets follow the `--web-ui-back-top-top/right/bottom/left` CSS variables.
705
+
702
706
  Role: `button`, keyboard Enter scrolls to top.
703
707
 
704
708
  #### `<web-ui-svg-draw-lines>`
@@ -729,7 +733,7 @@ Theme provider defining CSS custom property tokens.
729
733
 
730
734
  **Methods:** `getOverlayRoot()` — returns the portal overlay container
731
735
 
732
- 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-fast`, `--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`.
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`.
733
737
 
734
738
  ---
735
739
 
@@ -739,6 +743,8 @@ Defines `--wui-color-*`, `--wui-shadow-*`, `--wui-layer-*`, and motion tokens. M
739
743
 
740
744
  Individual toast notification element. Managed by imperative API.
741
745
 
746
+ When using the element directly, `no-close-button` is a standard boolean attribute that hides its close button.
747
+
742
748
  **Imperative API:**
743
749
 
744
750
  ```ts
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/menu-portal.css?inline
2
- var e = ".wui-menu-portal-overlay{--wui-glass-shadow:var(--wui-shadow-pop,0 3px 9px #00000045);z-index:var(--wui-layer-menu,100);box-sizing:border-box;min-width:200px;max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:20px;padding:4px;position:fixed;overflow-y:auto}.wui-menu-portal-overlay.dropdown-overlay .dropdown-scroll{min-width:200px;max-height:320px;overflow-y:auto}.wui-menu-portal-overlay.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.context-submenu{z-index:var(--wui-layer-menu-submenu,110)}";
2
+ var e = ".wui-menu-portal-overlay{--wui-glass-shadow:var(--wui-shadow-pop,0 3px 9px #00000045);--wui-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-duration-overlay-exit:var(--wui-duration-menu-exit,.1s);-webkit-user-select:none;user-select:none;z-index:var(--wui-layer-menu,100);box-sizing:border-box;min-width:200px;max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:20px;position:fixed;overflow:hidden}.wui-menu-portal-overlay .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay .wui-menu-content{padding:4px}.wui-menu-portal-overlay.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.context-submenu{z-index:var(--wui-layer-menu-submenu,110)}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":[".wui-menu-portal-overlay {\n --wui-glass-shadow: var(--wui-shadow-pop, 0 3px 9px rgb(0 0 0 / 0.27));\n\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n\n overflow-y: auto;\n\n box-sizing: border-box;\n min-width: 200px;\n max-width: 90vw;\n max-height: 80vh;\n padding: 4px;\n border-radius: 20px;\n\n color: var(--wui-color-text, #1b1b1b);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88));\n}\n\n.wui-menu-portal-overlay.dropdown-overlay .dropdown-scroll {\n overflow-y: auto;\n min-width: 200px;\n max-height: 320px;\n}\n\n.wui-menu-portal-overlay.dropdown-overlay[data-level]:not([data-level='0']),\n.wui-menu-portal-overlay.context-submenu {\n z-index: var(--wui-layer-menu-submenu, 110);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":[".wui-menu-portal-overlay {\n --wui-glass-shadow: var(--wui-shadow-pop, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-duration-overlay-exit: var(--wui-duration-menu-exit, 100ms);\n user-select: none;\n\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n\n overflow: hidden;\n\n box-sizing: border-box;\n min-width: 200px;\n max-width: 90vw;\n max-height: 80vh;\n border-radius: 20px;\n\n color: var(--wui-color-text, #1b1b1b);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88));\n\n & .wui-menu-scroll {\n overflow-y: auto;\n max-height: 80vh;\n }\n\n & .wui-menu-content {\n padding: 4px;\n }\n\n &.dropdown-overlay {\n & .wui-menu-scroll {\n max-height: 320px;\n }\n\n &[data-level]:not([data-level='0']) {\n z-index: var(--wui-layer-menu-submenu, 110);\n }\n }\n\n &.context-submenu {\n z-index: var(--wui-layer-menu-submenu, 110);\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/toast-containers.css?inline
2
- var e = ".wui-toast-container{pointer-events:none;z-index:var(--wui-layer-toast,200);overscroll-behavior:contain;flex-direction:column;gap:8px;max-height:100vh;padding:20px;display:flex;position:fixed;overflow-y:auto}.wui-toast-container>*{pointer-events:auto}.wui-toast-top-left{align-items:flex-start;top:0;left:0}.wui-toast-top-center{align-items:center;top:0;left:50%;transform:translate(-50%)}.wui-toast-top-right{align-items:flex-end;top:0;right:0}.wui-toast-bottom-left{flex-direction:column-reverse;align-items:flex-start;bottom:0;left:0}.wui-toast-bottom-center{flex-direction:column-reverse;align-items:center;bottom:0;left:50%;transform:translate(-50%)}.wui-toast-bottom-right{flex-direction:column-reverse;align-items:flex-end;bottom:0;right:0}";
2
+ var e = ".wui-toast-container{pointer-events:none;z-index:var(--wui-layer-toast,200);overscroll-behavior:contain;flex-direction:column;gap:8px;max-height:100vh;padding:24px;display:flex;position:fixed;overflow-y:auto}.wui-toast-container>*{pointer-events:auto}.wui-toast-top-left{align-items:flex-start;top:0;left:0}.wui-toast-top-center{align-items:center;top:0;left:50%;transform:translate(-50%)}.wui-toast-top-right{align-items:flex-end;top:0;right:0}.wui-toast-bottom-left{flex-direction:column-reverse;align-items:flex-start;bottom:0;left:0}.wui-toast-bottom-center{flex-direction:column-reverse;align-items:center;bottom:0;left:50%;transform:translate(-50%)}.wui-toast-bottom-right{flex-direction:column-reverse;align-items:flex-end;bottom:0;right:0}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"toast-containers.js","names":[],"sources":["../../src/assets/toast-containers.css?inline"],"sourcesContent":["/* Toast 容器定位 — 由 toast 命令式 API 动态注入到 body */\n\n.wui-toast-container {\n pointer-events: none;\n\n position: fixed;\n z-index: var(--wui-layer-toast, 200);\n\n overflow-y: auto;\n overscroll-behavior: contain;\n display: flex;\n flex-direction: column;\n gap: 8px;\n\n max-height: 100vh;\n\n /* padding 需要 >= 阴影模糊半径,否则 overflow 会裁剪子元素 box-shadow */\n padding: 20px;\n}\n\n.wui-toast-container > * {\n pointer-events: auto;\n}\n\n/* ===== 顶部位置 ===== */\n\n.wui-toast-top-left {\n top: 0;\n left: 0;\n align-items: flex-start;\n}\n\n.wui-toast-top-center {\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n}\n\n.wui-toast-top-right {\n top: 0;\n right: 0;\n align-items: flex-end;\n}\n\n/* ===== 底部位置 ===== */\n\n.wui-toast-bottom-left {\n bottom: 0;\n left: 0;\n flex-direction: column-reverse;\n align-items: flex-start;\n}\n\n.wui-toast-bottom-center {\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n\n flex-direction: column-reverse;\n align-items: center;\n}\n\n.wui-toast-bottom-right {\n right: 0;\n bottom: 0;\n flex-direction: column-reverse;\n align-items: flex-end;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"toast-containers.js","names":[],"sources":["../../src/assets/toast-containers.css?inline"],"sourcesContent":["/* Toast 容器定位 — 由 toast 命令式 API 动态注入到 body */\n\n.wui-toast-container {\n pointer-events: none;\n\n position: fixed;\n z-index: var(--wui-layer-toast, 200);\n\n overflow-y: auto;\n overscroll-behavior: contain;\n display: flex;\n flex-direction: column;\n gap: 8px;\n\n max-height: 100vh;\n\n /* padding 需要 >= 阴影模糊半径,否则 overflow 会裁剪子元素 box-shadow */\n padding: 24px;\n}\n\n.wui-toast-container > * {\n pointer-events: auto;\n}\n\n/* ===== 顶部位置 ===== */\n\n.wui-toast-top-left {\n top: 0;\n left: 0;\n align-items: flex-start;\n}\n\n.wui-toast-top-center {\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n}\n\n.wui-toast-top-right {\n top: 0;\n right: 0;\n align-items: flex-end;\n}\n\n/* ===== 底部位置 ===== */\n\n.wui-toast-bottom-left {\n bottom: 0;\n left: 0;\n flex-direction: column-reverse;\n align-items: flex-start;\n}\n\n.wui-toast-bottom-center {\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n\n flex-direction: column-reverse;\n align-items: center;\n}\n\n.wui-toast-bottom-right {\n right: 0;\n bottom: 0;\n flex-direction: column-reverse;\n align-items: flex-end;\n}\n"],"mappings":""}
@@ -1,7 +1,9 @@
1
1
  import { LitElement, PropertyValues } from 'lit';
2
2
  export declare class WebUiBackTop extends LitElement {
3
3
  static styles: import('lit').CSSResult;
4
- smooth: boolean;
4
+ get scrollBehavior(): 'smooth' | 'auto';
5
+ set scrollBehavior(value: string);
6
+ private _scrollBehavior;
5
7
  visible: boolean;
6
8
  scrollTarget: HTMLElement | Window;
7
9
  get threshold(): number;
@@ -1,9 +1,8 @@
1
1
  import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../icons/generated/lucide-arrow-up-to-line.js";
4
- import { normalizeNumber as n } from "../../shared/normalize/index.js";
4
+ import { normalizeLiteral as n, normalizeNumber as r } from "../../shared/normalize/index.js";
5
5
  import "../button/index.js";
6
- import { booleanWithFalseString as r } from "../../shared/property-converters/boolean-with-false-string.js";
7
6
  import i from "./style.js";
8
7
  import { LitElement as a, html as o, unsafeCSS as s } from "lit";
9
8
  import { customElement as c, property as l, state as u } from "lit/decorators.js";
@@ -11,17 +10,24 @@ import { getRootScrollTop as d } from "@greypan/browser-kit";
11
10
  //#region src/components/back-top/index.ts
12
11
  var f = class extends a {
13
12
  constructor(...e) {
14
- super(...e), this.smooth = !0, this.visible = !1, this.scrollTarget = window, this._threshold = 200;
13
+ super(...e), this._scrollBehavior = "smooth", this.visible = !1, this.scrollTarget = window, this._threshold = 200;
15
14
  }
16
15
  static {
17
16
  this.styles = s(i);
18
17
  }
18
+ get scrollBehavior() {
19
+ return this._scrollBehavior;
20
+ }
21
+ set scrollBehavior(e) {
22
+ let t = this._scrollBehavior;
23
+ this._scrollBehavior = n(e, ["smooth", "auto"], "smooth"), this.requestUpdate("scrollBehavior", t);
24
+ }
19
25
  get threshold() {
20
26
  return this._threshold;
21
27
  }
22
28
  set threshold(e) {
23
29
  let t = this._threshold;
24
- this._threshold = n(e, 0, 1e4, 200), this.requestUpdate("threshold", t);
30
+ this._threshold = r(e, 0, 1e4, 200), this.requestUpdate("threshold", t);
25
31
  }
26
32
  connectedCallback() {
27
33
  super.connectedCallback(), this.computeVisible(), this.onScrollTarget();
@@ -30,7 +36,7 @@ var f = class extends a {
30
36
  super.disconnectedCallback(), this.eventController?.abort();
31
37
  }
32
38
  willUpdate(e) {
33
- super.willUpdate(e), (e.has("threshold") || e.has("scrollTarget")) && this.computeVisible(), e.has("scrollTarget") && this.hasUpdated && this.onScrollTarget();
39
+ super.willUpdate(e), (e.has("threshold") || e.has("scrollTarget")) && this.computeVisible(), e.has("scrollTarget") && (this.toggleAttribute("container-mode", this.target !== window), this.onScrollTarget());
34
40
  }
35
41
  get target() {
36
42
  return this.scrollTarget ? this.scrollTarget === window || this.scrollTarget === document.documentElement || this.scrollTarget === document.body ? window : this.scrollTarget : window;
@@ -52,7 +58,7 @@ var f = class extends a {
52
58
  toTop() {
53
59
  this.target.scrollTo({
54
60
  top: 0,
55
- behavior: this.smooth ? "smooth" : "auto"
61
+ behavior: this.scrollBehavior
56
62
  });
57
63
  }
58
64
  onEnter(e) {
@@ -72,14 +78,12 @@ var f = class extends a {
72
78
  };
73
79
  e([l({
74
80
  reflect: !0,
75
- converter: r
76
- })], f.prototype, "smooth", void 0), e([l({
81
+ attribute: "scroll-behavior",
82
+ useDefault: !0
83
+ })], f.prototype, "scrollBehavior", null), e([l({
77
84
  type: Boolean,
78
85
  reflect: !0
79
- })], f.prototype, "visible", void 0), e([l({
80
- type: Object,
81
- attribute: !1
82
- })], f.prototype, "scrollTarget", void 0), e([l({
86
+ })], f.prototype, "visible", void 0), e([l({ attribute: !1 })], f.prototype, "scrollTarget", void 0), e([l({
83
87
  type: Number,
84
88
  reflect: !0
85
89
  })], f.prototype, "threshold", null), e([u()], f.prototype, "eventController", void 0), f = e([c("web-ui-back-top")], f);
@@ -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 { normalizeNumber } from '@/shared/normalize'\nimport { booleanWithFalseString } from '@/shared/property-converters/boolean-with-false-string'\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, converter: booleanWithFalseString }) smooth = true\n @property({ type: Boolean, reflect: true }) visible = false\n @property({ type: Object, 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 if (props.has('scrollTarget') && this.hasUpdated) {\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.smooth ? 'smooth' : 'auto'\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":";;;;;;;;;;;AAaO,IAAM,IAAN,cAA2B,EAAW;;EAgBtB,aAboD,KAAA,SAAA,IACnB,KAAA,UAAA,IAC6B,KAAA,eAAA,QAW9D,KAAA,aAAA;;;EAfI,KAAA,SAAA,EAAU,CAAK;;CAMxC,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;EAMnD,AALA,MAAM,WAAW,CAAK,IAElB,EAAM,IAAI,WAAW,KAAK,EAAM,IAAI,cAAc,MACpD,KAAK,eAAe,GAElB,EAAM,IAAI,cAAc,KAAK,KAAK,cACpC,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,SAAS,WAAW;EACrC,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;AAnGG,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,WAAW;AAAuB,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GAC7D,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAM,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GAE3C,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,GAnBR,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 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,5 +1,5 @@
1
1
  //#region src/components/back-top/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{--wui-shadow-glass:var(--wui-shadow-pop);display:block}.back-top-inner{pointer-events:none;z-index:var(--web-ui-back-top-z-index,var(--wui-layer-auxiliary,20));top:var(--web-ui-back-top-top,auto);right:var(--web-ui-back-top-right,20px);bottom:var(--web-ui-back-top-bottom,20px);left:var(--web-ui-back-top-left,auto);visibility:hidden;opacity:0;position:fixed}.back-top-inner .back-top-inner:focus-visible{outline:3px solid var(--wui-focus-ring,#08f6);outline-offset:2px;border-radius:2147483647px}:host([visible]) .back-top-inner{pointer-events:auto;visibility:visible;opacity:1}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{--wui-shadow-glass:var(--wui-shadow-pop);display:block}:host([container-mode]){bottom:var(--web-ui-back-top-bottom,20px);position:sticky}.back-top-inner{pointer-events:none;z-index:var(--web-ui-back-top-z-index,var(--wui-layer-auxiliary,20));top:var(--web-ui-back-top-top,auto);right:var(--web-ui-back-top-right,20px);bottom:var(--web-ui-back-top-bottom,20px);left:var(--web-ui-back-top-left,auto);visibility:hidden;opacity:0;position:fixed}.back-top-inner .back-top-inner:focus-visible{outline:3px solid var(--wui-focus-ring,#08f6);outline-offset:2px;border-radius:2147483647px}:host([container-mode]) .back-top-inner{margin-right:var(--web-ui-back-top-right,20px);margin-left:var(--web-ui-back-top-left,auto);position:static}:host([visible]) .back-top-inner{pointer-events:auto;visibility:visible;opacity:1}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/back-top/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-shadow-glass: var(--wui-shadow-pop);\n display: block;\n}\n\n.back-top-inner {\n pointer-events: none;\n\n position: fixed;\n z-index: var(--web-ui-back-top-z-index, var(--wui-layer-auxiliary, 20));\n top: var(--web-ui-back-top-top, auto);\n right: var(--web-ui-back-top-right, 20px);\n bottom: var(--web-ui-back-top-bottom, 20px);\n left: var(--web-ui-back-top-left, auto);\n\n visibility: hidden;\n opacity: 0;\n\n .back-top-inner:focus-visible {\n border-radius: calc(infinity * 1px);\n outline: 3px solid var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n:host([visible]) .back-top-inner {\n pointer-events: auto;\n visibility: visible;\n opacity: 1;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/back-top/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-shadow-glass: var(--wui-shadow-pop);\n display: block;\n}\n\n/* 容器模式:scrollTarget 为元素时按钮悬浮于容器底部(元素需置于容器内部),\n 横向偏移沿用 --web-ui-back-top-left/right,纵向沿用 --web-ui-back-top-bottom */\n:host([container-mode]) {\n position: sticky;\n bottom: var(--web-ui-back-top-bottom, 20px);\n}\n\n.back-top-inner {\n pointer-events: none;\n\n position: fixed;\n z-index: var(--web-ui-back-top-z-index, var(--wui-layer-auxiliary, 20));\n top: var(--web-ui-back-top-top, auto);\n right: var(--web-ui-back-top-right, 20px);\n bottom: var(--web-ui-back-top-bottom, 20px);\n left: var(--web-ui-back-top-left, auto);\n\n visibility: hidden;\n opacity: 0;\n\n .back-top-inner:focus-visible {\n border-radius: calc(infinity * 1px);\n outline: 3px solid var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n/* 容器模式下按钮脱离 fixed,改为流内布局并按偏移变量左/右对齐 */\n:host([container-mode]) .back-top-inner {\n position: static;\n margin-right: var(--web-ui-back-top-right, 20px);\n margin-left: var(--web-ui-back-top-left, auto);\n}\n\n:host([visible]) .back-top-inner {\n pointer-events: auto;\n visibility: visible;\n opacity: 1;\n}\n"],"mappings":""}
@@ -1,8 +1,8 @@
1
1
  import { LitElement } from 'lit';
2
2
  export declare class WebUiContextMenu extends LitElement {
3
- static styles: import('lit').CSSResult[];
3
+ static styles: import('lit').CSSResult;
4
4
  disabled: boolean;
5
- lockScroll: boolean;
5
+ noScrollLock: boolean;
6
6
  private _isOpen;
7
7
  private _x;
8
8
  private _y;
@@ -14,7 +14,7 @@ export declare class WebUiContextMenu extends LitElement {
14
14
  private _ignoreOutsideClickTimer?;
15
15
  private _hoverCleanupFns;
16
16
  private _menu?;
17
- private _hasScrollLock;
17
+ private readonly _scrollLock;
18
18
  private _restoreFocusTarget?;
19
19
  private _shouldOpenInstantly;
20
20
  /** 当前菜单是否打开 */
@@ -55,7 +55,6 @@ export declare class WebUiContextMenu extends LitElement {
55
55
  private _onKeydown;
56
56
  private _onClickOutside;
57
57
  private _onMenuClick;
58
- private _getDropdownItemFromEvent;
59
58
  private _getLevelItems;
60
59
  private _bindLevelHovers;
61
60
  private _ignoreCurrentOutsideClick;