@greypan/web-ui 5.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.CN.md +97 -23
  2. package/README.md +112 -21
  3. package/dist/assets/glass.js +1 -1
  4. package/dist/assets/glass.js.map +1 -1
  5. package/dist/assets/menu-portal.js +1 -1
  6. package/dist/assets/menu-portal.js.map +1 -1
  7. package/dist/components/autocomplete/index.d.ts +367 -4
  8. package/dist/components/autocomplete/index.js +83 -77
  9. package/dist/components/autocomplete/index.js.map +1 -1
  10. package/dist/components/autocomplete/style.js +1 -1
  11. package/dist/components/autocomplete/style.js.map +1 -1
  12. package/dist/components/avatar/style.js +1 -1
  13. package/dist/components/avatar/style.js.map +1 -1
  14. package/dist/components/back-top/style.js +1 -1
  15. package/dist/components/back-top/style.js.map +1 -1
  16. package/dist/components/badge/style.js +1 -1
  17. package/dist/components/badge/style.js.map +1 -1
  18. package/dist/components/button/style.js +1 -1
  19. package/dist/components/button/style.js.map +1 -1
  20. package/dist/components/button-group/style.js +1 -1
  21. package/dist/components/button-group/style.js.map +1 -1
  22. package/dist/components/checkbox/index.d.ts +366 -5
  23. package/dist/components/checkbox/index.js +19 -31
  24. package/dist/components/checkbox/index.js.map +1 -1
  25. package/dist/components/checkbox/style.js +1 -1
  26. package/dist/components/checkbox/style.js.map +1 -1
  27. package/dist/components/checkbox-group/index.d.ts +366 -4
  28. package/dist/components/checkbox-group/index.js +16 -25
  29. package/dist/components/checkbox-group/index.js.map +1 -1
  30. package/dist/components/collapse/index.js +24 -27
  31. package/dist/components/collapse/index.js.map +1 -1
  32. package/dist/components/context-menu/index.d.ts +6 -34
  33. package/dist/components/context-menu/index.js +88 -201
  34. package/dist/components/context-menu/index.js.map +1 -1
  35. package/dist/components/dialog/index.js +20 -23
  36. package/dist/components/dialog/index.js.map +1 -1
  37. package/dist/components/dialog/style.js +1 -1
  38. package/dist/components/dialog/style.js.map +1 -1
  39. package/dist/components/drawer/index.js +54 -57
  40. package/dist/components/drawer/index.js.map +1 -1
  41. package/dist/components/drawer/style.js +1 -1
  42. package/dist/components/drawer/style.js.map +1 -1
  43. package/dist/components/dropdown/index.d.ts +11 -14
  44. package/dist/components/dropdown/index.js +128 -155
  45. package/dist/components/dropdown/index.js.map +1 -1
  46. package/dist/components/dropdown-header/style.js +1 -1
  47. package/dist/components/dropdown-header/style.js.map +1 -1
  48. package/dist/components/dropdown-item/style.js +1 -1
  49. package/dist/components/dropdown-item/style.js.map +1 -1
  50. package/dist/components/empty/style.js +1 -1
  51. package/dist/components/empty/style.js.map +1 -1
  52. package/dist/components/input/index.d.ts +366 -5
  53. package/dist/components/input/index.js +35 -47
  54. package/dist/components/input/index.js.map +1 -1
  55. package/dist/components/input/style.js +1 -1
  56. package/dist/components/input/style.js.map +1 -1
  57. package/dist/components/input-number/index.d.ts +366 -5
  58. package/dist/components/input-number/index.js +31 -44
  59. package/dist/components/input-number/index.js.map +1 -1
  60. package/dist/components/input-number/style.js +1 -1
  61. package/dist/components/input-number/style.js.map +1 -1
  62. package/dist/components/layout/style.js +1 -1
  63. package/dist/components/layout/style.js.map +1 -1
  64. package/dist/components/option/style.js +1 -1
  65. package/dist/components/option/style.js.map +1 -1
  66. package/dist/components/popover/index.d.ts +2 -0
  67. package/dist/components/popover/index.js +33 -44
  68. package/dist/components/popover/index.js.map +1 -1
  69. package/dist/components/popover/style.js +1 -1
  70. package/dist/components/popover/style.js.map +1 -1
  71. package/dist/components/radio/index.d.ts +366 -5
  72. package/dist/components/radio/index.js +19 -31
  73. package/dist/components/radio/index.js.map +1 -1
  74. package/dist/components/radio/style.js +1 -1
  75. package/dist/components/radio/style.js.map +1 -1
  76. package/dist/components/radio-group/index.d.ts +366 -4
  77. package/dist/components/radio-group/index.js +16 -25
  78. package/dist/components/radio-group/index.js.map +1 -1
  79. package/dist/components/segmented/index.d.ts +366 -4
  80. package/dist/components/segmented/index.js +26 -35
  81. package/dist/components/segmented/index.js.map +1 -1
  82. package/dist/components/segmented/style.js +1 -1
  83. package/dist/components/segmented/style.js.map +1 -1
  84. package/dist/components/segmented-trigger/style.js +1 -1
  85. package/dist/components/segmented-trigger/style.js.map +1 -1
  86. package/dist/components/select/index.d.ts +368 -5
  87. package/dist/components/select/index.js +65 -67
  88. package/dist/components/select/index.js.map +1 -1
  89. package/dist/components/select/style.js +1 -1
  90. package/dist/components/select/style.js.map +1 -1
  91. package/dist/components/slider/index.d.ts +366 -5
  92. package/dist/components/slider/index.js +38 -50
  93. package/dist/components/slider/index.js.map +1 -1
  94. package/dist/components/slider/style.js +1 -1
  95. package/dist/components/slider/style.js.map +1 -1
  96. package/dist/components/spinner/style.js +1 -1
  97. package/dist/components/spinner/style.js.map +1 -1
  98. package/dist/components/switch/index.d.ts +366 -5
  99. package/dist/components/switch/index.js +26 -38
  100. package/dist/components/switch/index.js.map +1 -1
  101. package/dist/components/switch/style.js +1 -1
  102. package/dist/components/switch/style.js.map +1 -1
  103. package/dist/components/textarea/index.d.ts +366 -5
  104. package/dist/components/textarea/index.js +43 -57
  105. package/dist/components/textarea/index.js.map +1 -1
  106. package/dist/components/textarea/style.js +1 -1
  107. package/dist/components/textarea/style.js.map +1 -1
  108. package/dist/components/theme/style.js +1 -1
  109. package/dist/components/theme/style.js.map +1 -1
  110. package/dist/components/toast/style.js +1 -1
  111. package/dist/components/toast/style.js.map +1 -1
  112. package/dist/components/tooltip/index.d.ts +1 -0
  113. package/dist/components/tooltip/index.js +32 -46
  114. package/dist/components/tooltip/index.js.map +1 -1
  115. package/dist/components/tooltip/style.js +1 -1
  116. package/dist/components/tooltip/style.js.map +1 -1
  117. package/dist/shared/form-association/index.js +31 -4
  118. package/dist/shared/form-association/index.js.map +1 -1
  119. package/dist/shared/menu-behavior/index.js +112 -0
  120. package/dist/shared/menu-behavior/index.js.map +1 -0
  121. package/dist/shared/menu-portal/menu-tree.js +60 -1
  122. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  123. package/dist/shared/open-state/index.js +12 -0
  124. package/dist/shared/open-state/index.js.map +1 -0
  125. package/dist/shared/option-portal/combobox-shell.js +41 -0
  126. package/dist/shared/option-portal/combobox-shell.js.map +1 -0
  127. package/dist/shared/option-portal/index.js +23 -22
  128. package/dist/shared/option-portal/index.js.map +1 -1
  129. package/dist/shared/overlay/overlay.js.map +1 -1
  130. package/dist/shared/overlay/placement-props.js +19 -0
  131. package/dist/shared/overlay/placement-props.js.map +1 -0
  132. package/dist/shared/overlay/portal.js +94 -20
  133. package/dist/shared/overlay/portal.js.map +1 -1
  134. package/package.json +6 -7
package/README.CN.md CHANGED
@@ -120,10 +120,30 @@ useEffect(() => {
120
120
  <web-ui-dropdown-item ref={itemRef}>粘贴并关闭</web-ui-dropdown-item>
121
121
  ```
122
122
 
123
+ 在 `portal` 模式下,库会把面板内容物理移入浮层 Shadow DOM:
124
+
125
+ - React 按记录的插入父节点执行删除,因此裸条件子元素(`{condition && <el/>}`)的节点一旦已迁移,在面板打开期间无法删除:commit 失败,且该节点可能在面板关闭时重新出现。
126
+ - 请改为在稳定的包装元素内部做条件渲染——React 记录的插入父节点是包装元素,包装元素内部的增删在面板打开期间与开合周期内都保持可用(示例如下)。
127
+ - 面板打开期间的裸条件新增(向宿主追加内容)不受影响,会自动迁入面板。
128
+ - 保持内容始终挂载、仅切换可见性仍是有效的回退方案。
129
+
130
+ ```tsx
131
+ <web-ui-popover portal open={open} trigger="manual">
132
+ <div className="panel-body">{editing && <TagEditor />}</div>
133
+ </web-ui-popover>
134
+ ```
135
+
123
136
  ### Vue
124
137
 
125
138
  需要 `vue >= 3.5` 作为可选 peer 依赖。
126
139
 
140
+ Portal 面板支持实时渲染:浮层打开期间条件新增或删除的内容(`web-ui-select`、`web-ui-autocomplete`、
141
+ `web-ui-popover`、`web-ui-tooltip`、`web-ui-dropdown`、`web-ui-context-menu` 内的 Vue `v-if`)会按模板序
142
+ 自动迁入打开中的面板;关闭时所有内容按原锚点位置恢复,后续 patch 继续正常工作。边界:面板打开期间对
143
+ keyed `v-for` 列表做中段 splice 或重排不受支持——Vue 的 keyed children diff 会以已迁入面板的兄弟节点
144
+ 计算插入锚点,patch 失败且可能丢项;与编译路径无关(编译模板同样命中)。此类列表更新请在面板关闭后
145
+ 进行,或只做尾部追加/删除。
146
+
127
147
  ```ts
128
148
  // vite.config.ts
129
149
  import vue from '@vitejs/plugin-vue'
@@ -198,16 +218,22 @@ hover 与按压反馈阶段保持箭头光标,仅在真实拖拽进行中切
198
218
 
199
219
  **请求-写回模式(仅 dialog 与 drawer 的 `controlled`)。**
200
220
  `controlled=true` 时,用户关闭操作(Escape、backdrop、内置关闭、拖拽释放)只*请求* `open=false`;组件不改自己的
201
- 状态,保持打开,直到消费者写回 `open=false`。这是模态确认语义——关对话框/抽屉通常是需要消费者批准的操作(未保存
221
+ 状态,保持打开,直到Consumer写回 `open=false`。这是模态确认语义——关对话框/抽屉通常是需要Consumer批准的操作(未保存
202
222
  表单、需确认),与即时开合不同,不能由组件自行提交。只有这两个模态组件使用该模式;即时开合家族(collapse、popover、
203
223
  dropdown、tooltip)不需要它。
204
224
 
205
225
  **原生表单模型(input、textarea、input-number、select、checkbox、radio、switch、autocomplete)。**
206
226
  控件内部自管理 value/checked 状态;用户交互立即翻转,然后派发原生 `input`/`change` 事件。程序化赋值
207
227
  (`el.checked = true`)覆盖内部状态。这与原生 `<input type="checkbox">` 一致——**没有 `controlled` prop 是因为
208
- 值总是可读可写**,React/Vue 层自备受控包装。若翻转的持久化需要外部往返(例如开关应只有 API 调用成功后保持开启),
209
- 使用**乐观更新**路径:立即翻转、监听 `change`、请求期间设 `loading`(阻断后续交互并显示 spinner),失败后回写
210
- property(`el.checked = false`)并提示 toast。翻转先于批准的窗口被接受;不提供「批准前不翻转」的 `controlled` prop。
228
+ 值总是可读可写**,React/Vue 层自备受控包装。
229
+
230
+ 若翻转的持久化需要外部往返(例如开关应只有 API 调用成功后保持开启),使用**乐观更新**路径:
231
+
232
+ - 立即翻转,然后监听 `change`。
233
+ - 请求期间设 `loading`,阻断后续交互并显示 spinner。
234
+ - 失败后回写 property(`el.checked = false`)并提示 toast。
235
+
236
+ 翻转先于批准的窗口被接受;不提供「批准前不翻转」的 `controlled` prop。
211
237
 
212
238
  ### 表单关联控件
213
239
 
@@ -670,18 +696,27 @@ Portal 面板创建时会镜像 host 上解析后的这些变量;更新 host
670
696
 
671
697
  关闭时保留原生 dialog 的 top layer,待退出过渡完成后调用 `dialog.close()`。Escape 始终走此关闭路径;`no-backdrop-close` 仅控制遮罩点击。
672
698
 
673
- **拖拽关闭:** 启用 `draggable` 后,打开的抽屉在内缘显示灰色胶囊 drag bar(`right` 在左缘、`left` 在右缘、`top` 在下缘、`bottom` 在上缘)。拖拽实时跟手(遮罩透明度按比例淡出);松手时位移超过抽屉尺寸约 1/3 或快速甩动即弹簧关闭,否则弹回打开位,方向随 placement 适配。启用 `controlled` 后,超过阈值松手仅派发 `open-change(false)`;抽屉在闭合位短暂等待(120ms 回写窗口),Consumer 拒绝或超时未回写时弹回打开位。不支持拖拽打开——关闭态的抽屉在原生 dialog 之外没有任何渲染物。`prefers-reduced-motion` 下松手即时到位,不播放弹簧动画。
699
+ **拖拽关闭:** 启用 `draggable` 后,打开的抽屉在内缘显示灰色胶囊 drag bar(默认 4×56px,视觉中线距内缘 10px,位于 32px 厚的命中热区内;`right` 在左缘、`left` 在右缘、`top` 在下缘、`bottom` 在上缘):
700
+
701
+ - 拖拽实时跟手,遮罩透明度按比例淡出。
702
+ - 松手时位移超过抽屉尺寸约 1/3 或快速甩动即弹簧关闭,否则弹回打开位;方向随 placement 适配。
703
+ - 启用 `controlled` 后,超过阈值松手仅派发 `open-change(false)`;抽屉在闭合位短暂等待(120ms 回写窗口),Consumer 拒绝或超时未回写时弹回打开位。
704
+ - 不支持拖拽打开——关闭态的抽屉在原生 dialog 之外没有任何渲染物。
705
+ - `prefers-reduced-motion` 下松手即时到位,不播放弹簧动画。
674
706
 
675
707
  **CSS 自定义属性:**
676
708
 
677
- | 属性 | 默认值 | 说明 |
678
- | ------------------------- | ---------------------------------- | -------------------------------------------------- |
679
- | `--wui-drawer-width` | `320px` | 抽屉宽度 |
680
- | `--wui-drawer-height` | `300px` | 抽屉高度(上/下) |
681
- | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | 抽屉背景色 |
682
- | `--wui-drawer-radius` | `28px` | 浮动卡片圆角(非 headless) |
683
- | `--wui-drawer-inset` | `8px` | 浮动卡片视口留边(非 headless);置 `0` 为贴边几何 |
684
- | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | 遮罩背景色 |
709
+ | 属性 | 默认值 | 说明 |
710
+ | --------------------------------- | ---------------------------------- | -------------------------------------------------- |
711
+ | `--wui-drawer-width` | `320px` | 抽屉宽度 |
712
+ | `--wui-drawer-height` | `300px` | 抽屉高度(上/下) |
713
+ | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | 抽屉背景色 |
714
+ | `--wui-drawer-radius` | `var(--wui-radius-overlay, 28px)` | 浮动卡片圆角(非 headless) |
715
+ | `--wui-drawer-inset` | `8px` | 浮动卡片视口留边(非 headless);置 `0` 为贴边几何 |
716
+ | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | 遮罩背景色 |
717
+ | `--wui-drawer-drag-zone-size` | `32px` | Drag-to-close 命中热区厚度(draggable) |
718
+ | `--wui-drawer-drag-bar-thickness` | `4px` | Drag bar 胶囊厚度(短轴) |
719
+ | `--wui-drawer-drag-bar-length` | `56px` | Drag bar 胶囊长度(沿抽屉边缘) |
685
720
 
686
721
  ---
687
722
 
@@ -715,7 +750,7 @@ Portal 面板创建时会镜像 host 上解析后的这些变量;更新 host
715
750
 
716
751
  **trigger 语义:** 交互语义完全来自 default slot 放入的元素——原生 `<button>`、`<web-ui-button>` 或其他可交互元素原生提供 Enter/Space 激活与焦点。collapse 把 `aria-expanded` / `aria-controls`(指向内容轨道)与 `aria-disabled` 回写到 trigger slot 的首个 assigned element。trigger 请使用可交互元素:纯 `<span>` 可点击但没有键盘/焦点语义。
717
752
 
718
- **关闭稳态语义:** 消费者的 light DOM 永不移动或卸载。默认关闭稳态在内部内容容器上设 `hidden`;`keep-mounted` 时内部容器标记 `inert`,保留在收起轨道内可测量。
753
+ **关闭稳态语义:** Consumer的 light DOM 永不移动或卸载。默认关闭稳态在内部内容容器上设 `hidden`;`keep-mounted` 时内部容器标记 `inert`,保留在收起轨道内可测量。
719
754
 
720
755
  **已知限制:** `horizontal` 动画期间内容随宽度变化 reflow。
721
756
 
@@ -793,7 +828,7 @@ Hover 模式使用 `pointerenter`/`pointerleave` 加延迟控制。Click 模式
793
828
 
794
829
  通过 `contextmenu` 事件打开。菜单项:`web-ui-dropdown-item`、`web-ui-dropdown-divider`、`web-ui-dropdown-header`。支持键盘导航和子菜单 hover。
795
830
 
796
- 菜单打开期间,消费者可以安全地使用条件渲染(如 Vue `v-if`)切换、移动或删除菜单项,无需重新插入到宿主元素;portal 内的变更会自动 reconcile,关闭时框架锚点随元素迁回宿主,保证后续框架更新正常。
831
+ 菜单打开期间,Consumer可以安全地使用条件渲染(如 Vue `v-if`)切换、移动或删除菜单项,无需重新插入到宿主元素;portal 内的变更会自动 reconcile,关闭时框架锚点随元素迁回宿主,保证后续框架更新正常。
797
832
 
798
833
  ---
799
834
 
@@ -974,7 +1009,12 @@ WebUiSpinner.hide() // 隐藏
974
1009
 
975
1010
  **事件:** `sidebar-collapsed-change`(`CustomEvent<{ collapsed: boolean }>`)用于请求更新桌面端折叠状态;`sidebar-open-change`(`CustomEvent<{ open: boolean }>`)用于请求更新移动端 Drawer 打开状态;`sidebar-width-change`(`CustomEvent<{ width: string }>`)用于请求在拖拽调整结束后更新侧边栏宽度。Consumer 必须将请求值回写到对应的受控属性。
976
1011
 
977
- **侧边栏调整宽度:** 启用 `sidebar-resizable` 后,桌面端侧边栏右边缘会出现调整手柄(折叠状态下隐藏)。悬停或拖拽时显示 3px 宽的强调色垂直线和 `col-resize` 光标。拖拽时实时更新宽度(禁止过渡动画,限制在 `[min, max]` 和视口范围内);释放时触发 `sidebar-width-change` 事件并携带最终像素宽度,控制权交还给 `sidebar-width` 属性等待 Consumer 回写。`pointercancel` 会恢复属性控制的宽度且不触发事件。手柄同时支持键盘(WAI-ARIA splitter 模式):聚焦后用 ←/→ 以 16px 步进调整(Shift 加速到 64px),Home/End 跳到 min/max,Enter 以同一 `sidebar-width-change` 请求提交,Escape 撤回未提交的调整。移动端 Drawer 始终通过其内置 `draggable` 抽屉支持拖拽关闭。
1012
+ **侧边栏调整宽度:** 启用 `sidebar-resizable` 后,桌面端侧边栏右边缘会出现调整手柄(折叠状态下隐藏);悬停或拖拽时显示 3px 宽的强调色垂直线和 `col-resize` 光标。
1013
+
1014
+ - 拖拽时实时更新宽度(禁止过渡动画,限制在 `[min, max]` 和视口范围内)。
1015
+ - 释放时触发 `sidebar-width-change` 事件并携带最终像素宽度,Consumer 回写后宽度重新由 `sidebar-width` 属性接管;`pointercancel` 会恢复属性控制的宽度且不触发事件。
1016
+ - 键盘操作(WAI-ARIA splitter 模式):聚焦后用 ←/→ 以 16px 步进调整(Shift 加速到 64px),Home/End 跳到 min/max,Enter 以同一 `sidebar-width-change` 请求提交,Escape 撤回未提交的调整。
1017
+ - 移动端 Drawer 始终通过其内置 `draggable` 抽屉支持拖拽关闭。
978
1018
 
979
1019
  | 插槽 | 说明 |
980
1020
  | --------- | ------------------------------------------------------------ |
@@ -984,7 +1024,33 @@ WebUiSpinner.hide() // 隐藏
984
1024
  | `default` | 主内容区 |
985
1025
  | `tabbar` | 底部 tabbar |
986
1026
 
987
- `web-ui-layout` 只约束侧边栏卡片的可用空间并管理桌面端 Toggle,不创建侧边栏 scrollport。若仅让侧边栏的一部分滚动,请将 `sidebar` 插槽根节点设为 `height: 100%; min-height: 0` 的 flex column,再将 `overflow-y: auto` 设置到目标子元素。这样 Consumer 可自行固定头部和底部,无需额外的公共 slot。
1027
+ `web-ui-layout` 只约束侧边栏卡片的可用空间并管理桌面端 Toggle,不创建侧边栏 scrollport。若仅让侧边栏的一部分滚动,请将 `sidebar` 插槽根节点设为 `height: 100%; min-height: 0` 的 flex column,再将 `overflow-y: auto` 设置到目标子元素。这样 Consumer 可自行固定头部和底部,无需额外的公共 slot:
1028
+
1029
+ ```html
1030
+ <div slot="sidebar" class="sidebar-root">
1031
+ <div class="sidebar-title">组件列表</div>
1032
+ <nav class="sidebar-nav">...</nav>
1033
+ </div>
1034
+ ```
1035
+
1036
+ ```css
1037
+ .sidebar-root {
1038
+ display: flex;
1039
+ flex-direction: column;
1040
+ height: 100%;
1041
+ min-height: 0;
1042
+ }
1043
+
1044
+ .sidebar-title {
1045
+ flex-shrink: 0;
1046
+ }
1047
+
1048
+ .sidebar-nav {
1049
+ flex: 1;
1050
+ min-height: 0;
1051
+ overflow-y: auto;
1052
+ }
1053
+ ```
988
1054
 
989
1055
  在 `640px` 及以下,侧边栏会切换为 headless 模式的 `web-ui-drawer`。Consumer 内容仍渲染在相同的圆角侧边栏卡片中,移动端 Toggle 以 glass 变体位于 header 行内。其左缩进默认 `8px`,可通过 `--wui-layout-mobile-toggle-inset` 与 Consumer 自身的 header 内边距对齐。
990
1056
 
@@ -992,10 +1058,10 @@ WebUiSpinner.hide() // 隐藏
992
1058
 
993
1059
  **CSS 自定义属性:**
994
1060
 
995
- | 属性 | 默认值 | 说明 |
996
- | ---------------------------------- | ------ | ------------------------------------ |
997
- | `--wui-layout-sidebar-radius` | `24px` | 侧边栏卡片圆角(桌面端和移动端共用) |
998
- | `--wui-layout-mobile-toggle-inset` | `8px` | 移动端 header Toggle 的左缩进 |
1061
+ | 属性 | 默认值 | 说明 |
1062
+ | ---------------------------------- | --------------------------------- | ------------------------------------ |
1063
+ | `--wui-layout-sidebar-radius` | `var(--wui-radius-overlay, 28px)` | 侧边栏卡片圆角(桌面端和移动端共用) |
1064
+ | `--wui-layout-mobile-toggle-inset` | `8px` | 移动端 header Toggle 的左缩进 |
999
1065
 
1000
1066
  #### `<web-ui-back-top>`
1001
1067
 
@@ -1067,6 +1133,14 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
1067
1133
  | `--wui-overlay-min-width` | `200px` | 锚定浮层最小宽度 |
1068
1134
  | `--wui-focus-ring-width` | `3px` | Focus 指示器宽度 |
1069
1135
 
1136
+ **圆角 token:**
1137
+
1138
+ | 属性 | 默认值 | 说明 |
1139
+ | ---------------------- | ---------------------- | ---------------------------------------------------- |
1140
+ | `--wui-radius-control` | `calc(infinity * 1px)` | 小型控件的胶囊圆角(button、input、switch、option…) |
1141
+ | `--wui-radius-menu` | `18px` | 菜单/Popover 浮动面板、多行 textarea 与 toast |
1142
+ | `--wui-radius-overlay` | `28px` | 大型覆盖层:dialog、drawer、layout sidebar |
1143
+
1070
1144
  **层级 token:**
1071
1145
 
1072
1146
  | 属性 | 默认值 | 说明 |
@@ -1130,9 +1204,9 @@ SVG 线条绘制动画,基于 `stroke-dashoffset`。直接在原元素上动
1130
1204
  | `--wui-shadow-panel` | `0 3px 9px rgb(0 0 0 / 0.27)` | `0 4px 16px rgb(0 0 0 / 0.32)` | 小型浮动面板阴影 |
1131
1205
  | `--wui-shadow-glass` | 四层扩散阴影 | `0 8px 24px rgb(0 0 0 / 0.08)` | 液态玻璃基础阴影 |
1132
1206
 
1133
- **玻璃效果 token:** `--wui-glass-brightness` 浅色模式为 `1.06`,深色模式为 `1.02`。`--wui-glass-corner-radius` 默认值为 `32px`;玻璃组件会以自身的圆角半径覆盖它,使对角描边光影与形状对齐。
1207
+ **玻璃效果 token:** `--wui-glass-brightness` 浅色模式为 `1.06`,深色模式为 `1.02`。`--wui-glass-corner-radius` 默认值为 `32px`;非 pill 玻璃表面以自身语义圆角(`--wui-radius-menu` / `--wui-radius-overlay`,drawer 为 `--wui-drawer-radius`)覆盖它,使对角描边光影跟随 token 覆盖联动。pill 控件例外:光影渐变需要物理尺寸,继续使用由控件实际尺寸或内部尺寸 token 派生的有限圆角值。
1134
1208
 
1135
- **内部 token:** 以 `--wui-internal-*` 为前缀的变量是 Shadow DOM 内部接线变量,不属于公共 token API,消费方不应覆盖。
1209
+ **内部 token:** 以 `--wui-internal-*` 为前缀的变量是 Shadow DOM 内部接线变量,不属于公共 token API,Consumer 不应覆盖。
1136
1210
 
1137
1211
  ---
1138
1212
 
package/README.md CHANGED
@@ -123,10 +123,48 @@ useEffect(() => {
123
123
  <web-ui-dropdown-item ref={itemRef}>Paste and close</web-ui-dropdown-item>
124
124
  ```
125
125
 
126
+ In `portal` mode the library physically moves panel content into the overlay Shadow DOM:
127
+
128
+ - React removes nodes through its recorded insertion parent, so a bare conditional child (`{condition && <el/>}`) whose node was already migrated cannot be removed while the panel is open: the commit fails and the node can reappear when the panel closes.
129
+ - Conditionally render inside a stable wrapper element instead — React records the wrapper as the insertion parent, so wrapper-local additions and removals keep working while the panel is open and across open/close cycles (example below).
130
+ - Bare conditional additions while the panel is open (appending to the host) keep working and migrate into the panel automatically.
131
+ - Keeping content mounted and toggling visibility remains a valid fallback.
132
+
133
+ ```tsx
134
+ <web-ui-popover portal open={open} trigger="manual">
135
+ <div className="panel-body">{editing && <TagEditor />}</div>
136
+ </web-ui-popover>
137
+ ```
138
+
139
+ ### Lit
140
+
141
+ Portal panels support live rendering for Lit child parts: `${condition ? html`<el/>` : nothing}` inside
142
+ `web-ui-popover`, `web-ui-tooltip`, `web-ui-select` and `web-ui-autocomplete` migrates into the open panel
143
+ automatically, removals and element-to-element swaps work while the panel is open, and on close content is
144
+ restored to its original anchor position. lit-html child-part markers stay in the host light DOM, so
145
+ subsequent patches keep anchoring correctly. Boundary: reordering a `repeat()` list while a panel is open is
146
+ not supported — lit inserts relative to host part markers while sibling items already live in the panel, the
147
+ same cross-container anchoring boundary as Vue's keyed `v-for`. Apply list reorders while the panel is closed.
148
+
149
+ `web-ui-dropdown` manages menu items through the shared menu portal, which reconciles from both the host and
150
+ the panel: child-part additions while the panel is open work, but lit cannot reach items that already live in
151
+ the panel, so removals and element swaps there are not supported — apply them while the panel is closed.
152
+ `web-ui-context-menu` does not observe host-side insertions and is not covered by these live-rendering
153
+ guarantees.
154
+
126
155
  ### Vue
127
156
 
128
157
  Requires `vue >= 3.5` as optional peer dependency.
129
158
 
159
+ Portal panels support live rendering: content conditionally added or removed while a panel is open (Vue
160
+ `v-if` inside `web-ui-select`, `web-ui-autocomplete`, `web-ui-popover`, `web-ui-tooltip`, `web-ui-dropdown`,
161
+ `web-ui-context-menu`) migrates into the open panel automatically in template order, and on close everything
162
+ is restored to its original anchor position so subsequent patches keep working. Boundary: splicing or
163
+ reordering a keyed `v-for` list while a panel is open is not supported — Vue's keyed children diff resolves
164
+ insertion anchors against sibling nodes already migrated into the panel, so its patch fails and items can be
165
+ lost, regardless of compilation path (compiled templates included). Apply such list updates while the panel
166
+ is closed, or keep to appends/removals at the list tail.
167
+
130
168
  ```ts
131
169
  // vite.config.ts
132
170
  import vue from '@vitejs/plugin-vue'
@@ -216,11 +254,16 @@ components use this mode; the instant open/close family (collapse, popover, drop
216
254
  The control manages its own value/checked state internally; user interaction flips it immediately and then dispatches
217
255
  native `input`/`change` events. Assigning the property programmatically (`el.checked = true`) overrides the internal
218
256
  state. This mirrors native `<input type="checkbox">` — there is no `controlled` prop because the value is always readable
219
- and writable, and React/Vue layers provide their own controlled wrappers on top. For interactions that need an external
220
- round-trip before the flip is durable (e.g. a switch that should only stay on after an API call succeeds), use the
221
- optimistic-update path: flip immediately, observe `change`, set the control's `loading` during the request (this blocks
222
- further interaction and shows a spinner), and on failure write the property back (`el.checked = false`) plus surface a
223
- toast. The flip-before-approval window is accepted; there is no `controlled` prop for a reject-before-flip contract.
257
+ and writable, and React/Vue layers provide their own controlled wrappers on top.
258
+
259
+ For interactions that need an external round-trip before the flip is durable (e.g. a switch that should only stay on
260
+ after an API call succeeds), use the optimistic-update path:
261
+
262
+ - Flip immediately, then observe `change`.
263
+ - Set the control's `loading` during the request; this blocks further interaction and shows a spinner.
264
+ - On failure, write the property back (`el.checked = false`) and surface a toast.
265
+
266
+ The flip-before-approval window is accepted; there is no `controlled` prop for a reject-before-flip contract.
224
267
 
225
268
  ### Form-associated controls
226
269
 
@@ -689,18 +732,27 @@ Side drawer using native `<dialog>` with closing animation. In non-headless mode
689
732
 
690
733
  Closing keeps the native dialog in the top layer until the `--wui-duration-drawer-exit` transition completes (240ms by default), then calls `dialog.close()`. Escape always follows this close path; `no-backdrop-close` controls backdrop clicks only.
691
734
 
692
- **Drag to close:** With `draggable`, a gray capsule drag bar appears on the drawer's inner edge (left edge for `right`, right edge for `left`, bottom edge for `top`, top edge for `bottom`) while open. Dragging follows the pointer in real time (backdrop fades proportionally); releasing past ~1/3 of the drawer size or with a fast closing flick springs the drawer shut, otherwise it springs back open. The close direction is placement-aware. With `controlled`, release past the threshold only emits `open-change(false)`; the drawer holds at the closed position briefly (120ms write-back window) and springs back open if the consumer rejects or misses the write-back. Drag-to-open is not supported because the closed drawer renders nothing outside the native dialog. Under `prefers-reduced-motion`, release snaps instantly without spring animation.
735
+ **Drag to close:** With `draggable`, a gray capsule drag bar (4×56px by default, visually centered 10px from the inner edge inside a 32px-thick hit zone) appears on the drawer's inner edge (left edge for `right`, right edge for `left`, bottom edge for `top`, top edge for `bottom`) while open:
736
+
737
+ - Dragging follows the pointer in real time; the backdrop fades proportionally.
738
+ - Releasing past ~1/3 of the drawer size, or with a fast closing flick, springs the drawer shut; otherwise it springs back open. The close direction is placement-aware.
739
+ - With `controlled`, release past the threshold only emits `open-change(false)`; the drawer holds at the closed position briefly (120ms write-back window) and springs back open if the consumer rejects or misses the write-back.
740
+ - Drag-to-open is not supported because the closed drawer renders nothing outside the native dialog.
741
+ - Under `prefers-reduced-motion`, release snaps instantly without spring animation.
693
742
 
694
743
  **CSS Custom Properties:**
695
744
 
696
- | Property | Default | Description |
697
- | ------------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
698
- | `--wui-drawer-width` | `320px` | Drawer width |
699
- | `--wui-drawer-height` | `300px` | Drawer height (top/bottom) |
700
- | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | Drawer body background |
701
- | `--wui-drawer-radius` | `28px` | Floating card corner radius (non-headless) |
702
- | `--wui-drawer-inset` | `8px` | Floating card viewport inset (non-headless); `0` gives edge-to-edge geometry |
703
- | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | Backdrop background |
745
+ | Property | Default | Description |
746
+ | --------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
747
+ | `--wui-drawer-width` | `320px` | Drawer width |
748
+ | `--wui-drawer-height` | `300px` | Drawer height (top/bottom) |
749
+ | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | Drawer body background |
750
+ | `--wui-drawer-radius` | `var(--wui-radius-overlay, 28px)` | Floating card corner radius (non-headless) |
751
+ | `--wui-drawer-inset` | `8px` | Floating card viewport inset (non-headless); `0` gives edge-to-edge geometry |
752
+ | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | Backdrop background |
753
+ | `--wui-drawer-drag-zone-size` | `32px` | Drag-to-close hit zone thickness on the inner edge (draggable) |
754
+ | `--wui-drawer-drag-bar-thickness` | `4px` | Drag bar capsule thickness (short axis) |
755
+ | `--wui-drawer-drag-bar-length` | `56px` | Drag bar capsule length (along the drawer edge) |
704
756
 
705
757
  ---
706
758
 
@@ -993,7 +1045,12 @@ Responsive page layout with an optional full-width banner, a collapsible desktop
993
1045
 
994
1046
  **Events:** `sidebar-collapsed-change` (`CustomEvent<{ collapsed: boolean }>`) requests a desktop collapse-state update. `sidebar-open-change` (`CustomEvent<{ open: boolean }>`) requests a mobile drawer open-state update. `sidebar-width-change` (`CustomEvent<{ width: string }>`) requests a sidebar width update after a resize drag ends. Consumers must write the requested value back to the corresponding controlled property.
995
1047
 
996
- **Sidebar resize:** With `sidebar-resizable`, a resize handle appears on the desktop sidebar's right edge (hidden while collapsed). Hovering or dragging shows a 3px accent vertical line with a `col-resize` cursor. Dragging updates the width in real time (transition suppressed, clamped to `[min, max]` and the viewport); releasing emits `sidebar-width-change` with the final pixel width and returns control to the `sidebar-width` property once the consumer writes it back. `pointercancel` restores the property-controlled width without emitting. The handle is keyboard-operable (WAI-ARIA splitter pattern): focus it and use ←/→ to step by 16px (Shift for 64px), Home/End to jump to min/max, Enter to commit via the same `sidebar-width-change` request, and Escape to revert an uncommitted adjustment. The mobile drawer always supports drag-to-close via its built-in `draggable` drawer.
1048
+ **Sidebar resize:** With `sidebar-resizable`, a resize handle appears on the desktop sidebar's right edge (hidden while collapsed); hovering or dragging shows a 3px accent vertical line with a `col-resize` cursor.
1049
+
1050
+ - Dragging updates the width in real time (transition suppressed, clamped to `[min, max]` and the viewport).
1051
+ - Releasing emits `sidebar-width-change` with the final pixel width; the width is property-controlled again once the consumer writes it back. `pointercancel` restores the property-controlled width without emitting.
1052
+ - Keyboard (WAI-ARIA splitter pattern): focus the handle and use ←/→ to step by 16px (Shift for 64px), Home/End to jump to min/max, Enter to commit via the same `sidebar-width-change` request, and Escape to revert an uncommitted adjustment.
1053
+ - The mobile drawer always supports drag-to-close via its built-in `draggable` drawer.
997
1054
 
998
1055
  | Slot | Description |
999
1056
  | --------- | ----------------------------------------------------------------------------------------- |
@@ -1003,7 +1060,33 @@ Responsive page layout with an optional full-width banner, a collapsible desktop
1003
1060
  | `default` | Main content |
1004
1061
  | `tabbar` | Bottom tab bar |
1005
1062
 
1006
- `web-ui-layout` constrains the sidebar card and owns the desktop toggle area, but does not create a sidebar scrollport. To make only part of the sidebar scroll, make the `sidebar` slot root a `height: 100%; min-height: 0` flex column and apply `overflow-y: auto` to the intended child. This keeps consumer-defined headers and footers fixed without adding extra public slots.
1063
+ `web-ui-layout` constrains the sidebar card and owns the desktop toggle area, but does not create a sidebar scrollport. To make only part of the sidebar scroll, make the `sidebar` slot root a `height: 100%; min-height: 0` flex column and apply `overflow-y: auto` to the intended child. This keeps consumer-defined headers and footers fixed without adding extra public slots:
1064
+
1065
+ ```html
1066
+ <div slot="sidebar" class="sidebar-root">
1067
+ <div class="sidebar-title">Components</div>
1068
+ <nav class="sidebar-nav">...</nav>
1069
+ </div>
1070
+ ```
1071
+
1072
+ ```css
1073
+ .sidebar-root {
1074
+ display: flex;
1075
+ flex-direction: column;
1076
+ height: 100%;
1077
+ min-height: 0;
1078
+ }
1079
+
1080
+ .sidebar-title {
1081
+ flex-shrink: 0;
1082
+ }
1083
+
1084
+ .sidebar-nav {
1085
+ flex: 1;
1086
+ min-height: 0;
1087
+ overflow-y: auto;
1088
+ }
1089
+ ```
1007
1090
 
1008
1091
  At `640px` and below, the sidebar becomes a headless `web-ui-drawer`. The consumer content is rendered in the same rounded sidebar card; the mobile toggle appears in the header row as a glass button. Its left inset defaults to `8px`; align it with your own header padding via `--wui-layout-mobile-toggle-inset`.
1009
1092
 
@@ -1011,10 +1094,10 @@ At `640px` and below, the sidebar becomes a headless `web-ui-drawer`. The consum
1011
1094
 
1012
1095
  **CSS Custom Properties:**
1013
1096
 
1014
- | Property | Default | Description |
1015
- | ---------------------------------- | ------- | ------------------------------------------------ |
1016
- | `--wui-layout-sidebar-radius` | `24px` | Border radius of sidebar card (desktop & mobile) |
1017
- | `--wui-layout-mobile-toggle-inset` | `8px` | Left inset of the mobile header toggle |
1097
+ | Property | Default | Description |
1098
+ | ---------------------------------- | --------------------------------- | ------------------------------------------------ |
1099
+ | `--wui-layout-sidebar-radius` | `var(--wui-radius-overlay, 28px)` | Border radius of sidebar card (desktop & mobile) |
1100
+ | `--wui-layout-mobile-toggle-inset` | `8px` | Left inset of the mobile header toggle |
1018
1101
 
1019
1102
  #### `<web-ui-back-top>`
1020
1103
 
@@ -1086,6 +1169,14 @@ Defines foundation, color, layer, shadow, and motion tokens for its subtree. `mo
1086
1169
  | `--wui-overlay-min-width` | `200px` | Minimum anchored overlay width |
1087
1170
  | `--wui-focus-ring-width` | `3px` | Focus indicator width |
1088
1171
 
1172
+ **Radius tokens:**
1173
+
1174
+ | Property | Default | Description |
1175
+ | ---------------------- | ---------------------- | --------------------------------------------------------------- |
1176
+ | `--wui-radius-control` | `calc(infinity * 1px)` | Pill radius for small controls (button, input, switch, option…) |
1177
+ | `--wui-radius-menu` | `18px` | Menu/popover floating panels, multiline textarea and toast |
1178
+ | `--wui-radius-overlay` | `28px` | Large overlay surfaces: dialog, drawer, layout sidebar |
1179
+
1089
1180
  **Layer tokens:**
1090
1181
 
1091
1182
  | Property | Default | Description |
@@ -1149,7 +1240,7 @@ Defines foundation, color, layer, shadow, and motion tokens for its subtree. `mo
1149
1240
  | `--wui-shadow-panel` | `0 3px 9px rgb(0 0 0 / 0.27)` | `0 4px 16px rgb(0 0 0 / 0.32)` | Small floating panel shadow |
1150
1241
  | `--wui-shadow-glass` | four-layer diffuse shadow | `0 8px 24px rgb(0 0 0 / 0.08)` | Base liquid glass shadow |
1151
1242
 
1152
- **Glass effect tokens:** `--wui-glass-brightness` is `1.06` in light mode and `1.02` in dark mode. `--wui-glass-corner-radius` defaults to `32px`; glass components set it from their own corner radius so the diagonal border lighting aligns with their shape.
1243
+ **Glass effect tokens:** `--wui-glass-brightness` is `1.06` in light mode and `1.02` in dark mode. `--wui-glass-corner-radius` defaults to `32px`; non-pill glass surfaces set it from their own semantic radius (`--wui-radius-menu` / `--wui-radius-overlay`, or `--wui-drawer-radius` for the drawer) so the diagonal border lighting follows token overrides. Pill controls keep a finite corner radius derived from their physical size or internal size token instead, because the lighting gradient needs a physical size.
1153
1244
 
1154
1245
  **Internal tokens:** variables prefixed `--wui-internal-*` are private wiring between shadow DOM parts; they are not part of the public token API and must not be overridden by consumers.
1155
1246
 
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/glass.css?inline
2
- var e = ".wui-glass{--wui-internal-glass-focus-ring:0 0 0 0 transparent;--wui-internal-glass-shadow:var(--wui-shadow-glass,0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004);background-color:var(--wui-color-surface-glass,#fafafa57);-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));box-shadow:inset 0 0 0 .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 38%, transparent), inset 0 1px .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 52%, transparent), inset 0 -.5px 1px #00000008, var(--wui-internal-glass-focus-ring,0 0 0 0 transparent), var(--wui-internal-glass-shadow,var(--wui-shadow-glass,0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004));background-clip:padding-box;border:none;position:relative}.wui-glass:before{pointer-events:none;content:\"\";border-radius:inherit;background-color:var(--wui-color-glass-border,#3333331f);background-image:radial-gradient(var(--wui-glass-corner-radius,32px) at 100% 0, var(--wui-color-glass-shade,#0003), transparent), radial-gradient(var(--wui-glass-corner-radius,32px) at 0 100%, var(--wui-color-glass-shade,#0003), transparent), radial-gradient(calc(var(--wui-glass-corner-radius,32px) * 2) at 0 0, var(--wui-color-glass-corner,#ffffff14), transparent), radial-gradient(calc(var(--wui-glass-corner-radius,32px) * 2) at 100% 100%, var(--wui-color-glass-corner,#ffffff14), transparent);-webkit-mask-composite:xor;-webkit-mask-composite:xor;-webkit-mask-source-type:auto,auto;padding:1px;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0;-webkit-mask-size:auto,auto;mask-size:auto,auto;-webkit-mask-repeat:repeat,repeat;mask-repeat:repeat,repeat;-webkit-mask-clip:content-box,border-box;mask-clip:content-box,border-box;-webkit-mask-origin:content-box,border-box;mask-origin:content-box,border-box;-webkit-mask-composite:xor;mask-composite:exclude;-webkit-mask-source-type:auto,auto;mask-mode:match-source,match-source}";
2
+ var e = ".wui-glass{--wui-internal-glass-shadow:var(--wui-shadow-glass,0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004);background-color:var(--wui-color-surface-glass,#fafafa57);-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));box-shadow:inset 0 0 0 .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 38%, transparent), inset 0 1px .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 52%, transparent), inset 0 -.5px 1px #00000008, var(--wui-internal-glass-shadow,var(--wui-shadow-glass,0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004));background-clip:padding-box;border:none;position:relative}.wui-glass:before{pointer-events:none;content:\"\";border-radius:inherit;background-color:var(--wui-color-glass-border,transparent);background-image:radial-gradient(var(--wui-glass-corner-radius,32px) at 100% 0, var(--wui-color-glass-shade,#0000000f), transparent), radial-gradient(var(--wui-glass-corner-radius,32px) at 0 100%, var(--wui-color-glass-shade,#0000000f), transparent), radial-gradient(calc(var(--wui-glass-corner-radius,32px) * 2) at 0 0, var(--wui-color-glass-corner,#ffffff14), transparent), radial-gradient(calc(var(--wui-glass-corner-radius,32px) * 2) at 100% 100%, var(--wui-color-glass-corner,#ffffff14), transparent);-webkit-mask-composite:xor;-webkit-mask-composite:xor;-webkit-mask-source-type:auto,auto;padding:1px;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);mask-image:linear-gradient(#000 0 0),linear-gradient(#000 0 0);-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0;-webkit-mask-size:auto,auto;mask-size:auto,auto;-webkit-mask-repeat:repeat,repeat;mask-repeat:repeat,repeat;-webkit-mask-clip:content-box,border-box;mask-clip:content-box,border-box;-webkit-mask-origin:content-box,border-box;mask-origin:content-box,border-box;-webkit-mask-composite:xor;mask-composite:exclude;-webkit-mask-source-type:auto,auto;mask-mode:match-source,match-source}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n /*\n * 内部变量在 glass 元素上自声明默认值,切断从祖先 glass 容器(drawer/dialog\n * body 等声明了 overlay 阴影的元素)沿 flattened tree 继承进 slotted 内容的\n * 通道;各组件在自身元素上的同变量配置(特异性/源顺序恒胜出)不受影响。\n */\n --wui-internal-glass-focus-ring: 0 0 0 0 transparent;\n --wui-internal-glass-shadow: var(\n --wui-shadow-glass,\n 0 0 1px rgb(0 0 0 / 0.05),\n 0 0 8px rgb(0 0 0 / 0.03),\n 0 2px 16px rgb(0 0 0 / 0.025),\n 0 8px 32px rgb(0 0 0 / 0.015)\n );\n\n position: relative;\n\n border: none;\n\n background-color: var(--wui-color-surface-glass, rgb(250 250 250 / 0.34));\n background-clip: padding-box;\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(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n var(--wui-internal-glass-focus-ring, 0 0 0 0 transparent),\n var(\n --wui-internal-glass-shadow,\n var(\n --wui-shadow-glass,\n 0 0 1px rgb(0 0 0 / 0.05),\n 0 0 8px rgb(0 0 0 / 0.03),\n 0 2px 16px rgb(0 0 0 / 0.025),\n 0 8px 32px rgb(0 0 0 / 0.015)\n )\n );\n}\n\n/*\n * 玻璃描边:底环 + 对角受光/背光。background-color 用 border 色铺满整圈(含圆角\n * 弧段,修复胶囊弧段无着色发暗的问题);叠两枚 corner→transparent radial 作左上/\n * 右下受光光泽,再叠两枚 shade→transparent radial(置于最上层)压暗右上/左下背光\n * 角,形成对角光影的玻璃立体感。四枚渐变均为锚定角点、半径 --wui-glass-corner-radius\n * 的固定物理尺寸正圆——视觉覆盖范围不随元素宽高缩放(百分比方案在大面板上暗边\n * 过长、小控件上过弱),各组件用与自身 border-radius 同源的值覆盖该变量即可联动。\n * 颜色由 theme 按明暗主题提供 --wui-color-glass-corner / --wui-color-glass-shade /\n * --wui-color-glass-border;-webkit-mask-composite 旧语法覆盖 Chrome 111-119,\n * 无前缀 mask-composite 留给 Chrome 120+。\n */\n.wui-glass::before {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n padding: 1px;\n border-radius: inherit;\n\n background-color: var(--wui-color-glass-border, rgb(51 51 51 / 0.12));\n background-image:\n radial-gradient(\n var(--wui-glass-corner-radius, 32px) at 100% 0,\n var(--wui-color-glass-shade, rgb(0 0 0 / 0.2)),\n transparent\n ),\n radial-gradient(\n var(--wui-glass-corner-radius, 32px) at 0 100%,\n var(--wui-color-glass-shade, rgb(0 0 0 / 0.2)),\n transparent\n ),\n radial-gradient(\n calc(var(--wui-glass-corner-radius, 32px) * 2) at 0 0,\n var(--wui-color-glass-corner, rgb(255 255 255 / 0.08)),\n transparent\n ),\n radial-gradient(\n calc(var(--wui-glass-corner-radius, 32px) * 2) at 100% 100%,\n var(--wui-color-glass-corner, rgb(255 255 255 / 0.08)),\n transparent\n );\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n /*\n * 内部阴影变量在 glass 元素上自声明默认值,切断从祖先 glass 容器(drawer/dialog\n * body 等声明了 overlay 阴影的元素)沿 flattened tree 继承进 slotted 内容的\n * 通道;各组件在自身元素上的同变量配置(特异性/源顺序恒胜出)不受影响。\n */\n --wui-internal-glass-shadow: var(\n --wui-shadow-glass,\n 0 0 1px rgb(0 0 0 / 0.05),\n 0 0 8px rgb(0 0 0 / 0.03),\n 0 2px 16px rgb(0 0 0 / 0.025),\n 0 8px 32px rgb(0 0 0 / 0.015)\n );\n\n position: relative;\n\n border: none;\n\n background-color: var(--wui-color-surface-glass, rgb(250 250 250 / 0.34));\n background-clip: padding-box;\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(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n var(\n --wui-internal-glass-shadow,\n var(\n --wui-shadow-glass,\n 0 0 1px rgb(0 0 0 / 0.05),\n 0 0 8px rgb(0 0 0 / 0.03),\n 0 2px 16px rgb(0 0 0 / 0.025),\n 0 8px 32px rgb(0 0 0 / 0.015)\n )\n );\n}\n\n/*\n * 玻璃描边:底环 + 对角受光/背光。background-color 用 border 色铺满整圈(含圆角\n * 弧段,修复胶囊弧段无着色发暗的问题);叠两枚 corner→transparent radial 作左上/\n * 右下受光光泽,再叠两枚 shade→transparent radial(置于最上层)压暗右上/左下背光\n * 角,形成对角光影的玻璃立体感。四枚渐变均为锚定角点、半径 --wui-glass-corner-radius\n * 的固定物理尺寸正圆——视觉覆盖范围不随元素宽高缩放(百分比方案在大面板上暗边\n * 过长、小控件上过弱),各组件用与自身 border-radius 同源的值覆盖该变量即可联动。\n * 颜色由 theme 按明暗主题提供 --wui-color-glass-corner / --wui-color-glass-shade /\n * --wui-color-glass-border;-webkit-mask-composite 旧语法覆盖 Chrome 111-119,\n * 无前缀 mask-composite 留给 Chrome 120+。\n */\n.wui-glass::before {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n padding: 1px;\n border-radius: inherit;\n\n background-color: var(--wui-color-glass-border, transparent);\n background-image:\n radial-gradient(\n var(--wui-glass-corner-radius, 32px) at 100% 0,\n var(--wui-color-glass-shade, rgb(0 0 0 / 0.06)),\n transparent\n ),\n radial-gradient(\n var(--wui-glass-corner-radius, 32px) at 0 100%,\n var(--wui-color-glass-shade, rgb(0 0 0 / 0.06)),\n transparent\n ),\n radial-gradient(\n calc(var(--wui-glass-corner-radius, 32px) * 2) at 0 0,\n var(--wui-color-glass-corner, rgb(255 255 255 / 0.08)),\n transparent\n ),\n radial-gradient(\n calc(var(--wui-glass-corner-radius, 32px) * 2) at 100% 100%,\n var(--wui-color-glass-corner, rgb(255 255 255 / 0.08)),\n transparent\n );\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/menu-portal.css?inline
2
- var e = ".wui-menu-portal-overlay.wui-glass{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-internal-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-internal-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:var(--wui-overlay-min-width,200px);max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#f6f6f6d1);border-radius:20px;position:fixed;overflow:hidden}.wui-menu-portal-overlay.wui-glass .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay.wui-glass .wui-menu-content{padding:4px}.wui-menu-portal-overlay.wui-glass.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.wui-glass.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.wui-glass.context-submenu{z-index:var(--wui-layer-menu-nested,110)}";
2
+ var e = ".wui-menu-portal-overlay.wui-glass{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-internal-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-internal-duration-overlay-exit:var(--wui-duration-menu-exit,.1s);--wui-glass-corner-radius:var(--wui-radius-menu,18px);-webkit-user-select:none;user-select:none;z-index:var(--wui-layer-menu,100);box-sizing:border-box;min-width:var(--wui-overlay-min-width,200px);border-radius:var(--wui-radius-menu,18px);max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#f6f6f6d1);position:fixed;overflow:hidden}.wui-menu-portal-overlay.wui-glass .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay.wui-glass .wui-menu-content{padding:4px}.wui-menu-portal-overlay.wui-glass.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.wui-glass.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.wui-glass.context-submenu{z-index:var(--wui-layer-menu-nested,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-glass { position: relative },保持 fixed 定位。 */\n.wui-menu-portal-overlay.wui-glass {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-internal-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-internal-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: var(--wui-overlay-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-menu, rgb(246 246 246 / 0.82));\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-nested, 110);\n }\n }\n\n &.context-submenu {\n z-index: var(--wui-layer-menu-nested, 110);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":["/* 双类选择器覆盖 .wui-glass { position: relative },保持 fixed 定位。 */\n.wui-menu-portal-overlay.wui-glass {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-internal-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-internal-duration-overlay-exit: var(--wui-duration-menu-exit, 100ms);\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\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: var(--wui-overlay-min-width, 200px);\n max-width: 90vw;\n max-height: 80vh;\n border-radius: var(--wui-radius-menu, 18px);\n\n color: var(--wui-color-text, #1b1b1b);\n\n background-color: var(--wui-color-surface-menu, rgb(246 246 246 / 0.82));\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-nested, 110);\n }\n }\n\n &.context-submenu {\n z-index: var(--wui-layer-menu-nested, 110);\n }\n}\n"],"mappings":""}