@greypan/web-ui 8.1.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.CN.md +246 -133
  2. package/README.md +246 -133
  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/assets/selection-control.js +1 -1
  8. package/dist/assets/selection-control.js.map +1 -1
  9. package/dist/assets/toast-containers.js +1 -1
  10. package/dist/assets/toast-containers.js.map +1 -1
  11. package/dist/components/autocomplete/index.d.ts +3 -2
  12. package/dist/components/autocomplete/index.js +40 -44
  13. package/dist/components/autocomplete/index.js.map +1 -1
  14. package/dist/components/autocomplete/style.js +1 -1
  15. package/dist/components/autocomplete/style.js.map +1 -1
  16. package/dist/components/avatar/index.js.map +1 -1
  17. package/dist/components/avatar/style.js +1 -1
  18. package/dist/components/avatar/style.js.map +1 -1
  19. package/dist/components/back-top/style.js +1 -1
  20. package/dist/components/back-top/style.js.map +1 -1
  21. package/dist/components/badge/style.js +1 -1
  22. package/dist/components/badge/style.js.map +1 -1
  23. package/dist/components/button/style.js +1 -1
  24. package/dist/components/button/style.js.map +1 -1
  25. package/dist/components/button-group/index.js +0 -1
  26. package/dist/components/button-group/index.js.map +1 -1
  27. package/dist/components/button-group/style.js +1 -1
  28. package/dist/components/button-group/style.js.map +1 -1
  29. package/dist/components/checkbox/index.js +4 -4
  30. package/dist/components/checkbox/index.js.map +1 -1
  31. package/dist/components/checkbox-group/style.js +1 -1
  32. package/dist/components/checkbox-group/style.js.map +1 -1
  33. package/dist/components/context-menu/index.d.ts +167 -3
  34. package/dist/components/context-menu/index.js +162 -91
  35. package/dist/components/context-menu/index.js.map +1 -1
  36. package/dist/components/context-menu/scrim.js +6 -0
  37. package/dist/components/context-menu/scrim.js.map +1 -0
  38. package/dist/components/context-menu/style.js +1 -1
  39. package/dist/components/context-menu/style.js.map +1 -1
  40. package/dist/components/dialog/index.d.ts +9 -0
  41. package/dist/components/dialog/index.js +61 -46
  42. package/dist/components/dialog/index.js.map +1 -1
  43. package/dist/components/dialog/style.js +1 -1
  44. package/dist/components/dialog/style.js.map +1 -1
  45. package/dist/components/drawer/index.d.ts +45 -0
  46. package/dist/components/drawer/index.js +116 -52
  47. package/dist/components/drawer/index.js.map +1 -1
  48. package/dist/components/drawer/style.js +1 -1
  49. package/dist/components/drawer/style.js.map +1 -1
  50. package/dist/components/dropdown/index.d.ts +12 -0
  51. package/dist/components/dropdown/index.js +13 -10
  52. package/dist/components/dropdown/index.js.map +1 -1
  53. package/dist/components/dropdown-divider/style.js +1 -1
  54. package/dist/components/dropdown-divider/style.js.map +1 -1
  55. package/dist/components/dropdown-header/style.js +1 -1
  56. package/dist/components/dropdown-header/style.js.map +1 -1
  57. package/dist/components/dropdown-item/style.js +1 -1
  58. package/dist/components/dropdown-item/style.js.map +1 -1
  59. package/dist/components/editable-text/index.d.ts +39 -0
  60. package/dist/components/editable-text/index.js +6 -2
  61. package/dist/components/editable-text/index.js.map +1 -1
  62. package/dist/components/empty/index.d.ts +21 -4
  63. package/dist/components/empty/index.js +37 -32
  64. package/dist/components/empty/index.js.map +1 -1
  65. package/dist/components/empty/style.js +1 -1
  66. package/dist/components/empty/style.js.map +1 -1
  67. package/dist/components/image-preview/index.js +9 -2
  68. package/dist/components/image-preview/index.js.map +1 -1
  69. package/dist/components/image-preview/style.js +1 -1
  70. package/dist/components/image-preview/style.js.map +1 -1
  71. package/dist/components/index.js +23 -23
  72. package/dist/components/input/style.js +1 -1
  73. package/dist/components/input/style.js.map +1 -1
  74. package/dist/components/input-number/style.js +1 -1
  75. package/dist/components/input-number/style.js.map +1 -1
  76. package/dist/components/layout/index.d.ts +0 -3
  77. package/dist/components/layout/index.js +1 -1
  78. package/dist/components/layout/index.js.map +1 -1
  79. package/dist/components/layout/style.js +1 -1
  80. package/dist/components/layout/style.js.map +1 -1
  81. package/dist/components/option/style.js +1 -1
  82. package/dist/components/option/style.js.map +1 -1
  83. package/dist/components/popover/index.js.map +1 -1
  84. package/dist/components/popover/style.js +1 -1
  85. package/dist/components/popover/style.js.map +1 -1
  86. package/dist/components/radio/style.js +1 -1
  87. package/dist/components/radio/style.js.map +1 -1
  88. package/dist/components/radio-group/style.js +1 -1
  89. package/dist/components/radio-group/style.js.map +1 -1
  90. package/dist/components/segmented/index.d.ts +5 -0
  91. package/dist/components/segmented/index.js +45 -28
  92. package/dist/components/segmented/index.js.map +1 -1
  93. package/dist/components/segmented/style.js +1 -1
  94. package/dist/components/segmented/style.js.map +1 -1
  95. package/dist/components/segmented-trigger/style.js +1 -1
  96. package/dist/components/segmented-trigger/style.js.map +1 -1
  97. package/dist/components/select/index.js +0 -1
  98. package/dist/components/select/index.js.map +1 -1
  99. package/dist/components/select/style.js +1 -1
  100. package/dist/components/select/style.js.map +1 -1
  101. package/dist/components/slider/style.js +1 -1
  102. package/dist/components/slider/style.js.map +1 -1
  103. package/dist/components/spinner/style.js +1 -1
  104. package/dist/components/spinner/style.js.map +1 -1
  105. package/dist/components/svg-draw-lines/index.js.map +1 -1
  106. package/dist/components/switch/style.js +1 -1
  107. package/dist/components/switch/style.js.map +1 -1
  108. package/dist/components/textarea/index.js +2 -2
  109. package/dist/components/textarea/index.js.map +1 -1
  110. package/dist/components/textarea/style.js +1 -1
  111. package/dist/components/textarea/style.js.map +1 -1
  112. package/dist/components/theme/style.js +1 -1
  113. package/dist/components/theme/style.js.map +1 -1
  114. package/dist/components/toast/style.js +1 -1
  115. package/dist/components/toast/style.js.map +1 -1
  116. package/dist/components/tooltip/index.js.map +1 -1
  117. package/dist/components/tooltip/style.js +1 -1
  118. package/dist/components/tooltip/style.js.map +1 -1
  119. package/dist/icons/generated/akar-icons-circle-check.d.ts +6 -0
  120. package/dist/icons/generated/akar-icons-circle-check.js +10 -0
  121. package/dist/icons/generated/akar-icons-circle-check.js.map +1 -0
  122. package/dist/icons/generated/bi-check-lg.d.ts +6 -0
  123. package/dist/icons/generated/bi-check-lg.js +10 -0
  124. package/dist/icons/generated/bi-check-lg.js.map +1 -0
  125. package/dist/icons/generated/fluent-tag-search-24-regular.d.ts +6 -0
  126. package/dist/icons/generated/fluent-tag-search-24-regular.js +10 -0
  127. package/dist/icons/generated/fluent-tag-search-24-regular.js.map +1 -0
  128. package/dist/icons/generated/mdi-tag-search-outline.d.ts +6 -0
  129. package/dist/icons/generated/mdi-tag-search-outline.js +10 -0
  130. package/dist/icons/generated/mdi-tag-search-outline.js.map +1 -0
  131. package/dist/icons/index.d.ts +4 -0
  132. package/dist/icons/index.js +5 -1
  133. package/dist/shared/element-height/index.js +47 -0
  134. package/dist/shared/element-height/index.js.map +1 -0
  135. package/dist/shared/menu-portal/menu-portal.js +11 -11
  136. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  137. package/dist/shared/menu-portal/menu-tree.js +2 -2
  138. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  139. package/dist/shared/overlay/anchored-panel.js.map +1 -1
  140. package/dist/shared/overlay/native-dialog-presence.js +23 -11
  141. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  142. package/dist/shared/overlay/nested-drawer-layers.js +30 -23
  143. package/dist/shared/overlay/nested-drawer-layers.js.map +1 -1
  144. package/dist/shared/scroll-lock/scroll-lock.js +3 -3
  145. package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
  146. package/package.json +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/image-preview/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\n/*\n * 全视口 dialog:遮罩由独立 .wui-image-preview-backdrop 层提供(而非 ::backdrop /\n * dialog 自身背景)。dialog 自身 opacity 恒 1、无任何 transform——opacity < 1 会让\n * dialog 成为 backdrop root,后代玻璃控件(toolbar/counter/nav)的 backdrop-filter\n * 在过渡期被禁用、blur 在端点生硬跳变;transform 会把遮罩一起缩放。进场缩放\n * (scale 0.95→1)由 .wui-image-preview-surface 图片舞台层承担(见下)。本组件是满视口\n * 表面,起点 >1 会越出视口,只能用 <1 的档位;缩放也不能落在包住控件层的\n * .wui-image-preview-content 上,否则贴边控件会随缩放从视口边缘向内飞行。遮罩、图片\n * 舞台各自用独立层 opacity 过渡;控件层不参与 opacity 过渡,玻璃控件永不在 opacity < 1\n * 的祖先内,blur 全程连续。\n */\ndialog {\n /* 显式 position: fixed(防御性):UA 的 dialog:modal 默认 fixed,但作者样式若覆盖\n position 会把它退回文档流——top layer 里的 modal dialog 变成按文档流定位,出现在\n 页面顶部且跟随页面滚动。image-preview 的 dialog 铺满视口,fixed 是硬前提。 */\n position: fixed;\n\n overflow: hidden;\n\n box-sizing: border-box;\n width: 100%;\n max-width: none;\n height: 100%;\n height: 100dvh;\n max-height: none;\n margin: 0;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 1;\n background: transparent;\n}\n\n/* 遮罩层:承接原先 dialog 背景的淡入淡出,自身 opacity 过渡不构成 backdrop root。 */\n.wui-image-preview-backdrop {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n opacity: 0;\n background: var(--wui-image-preview-overlay-bg, rgb(0 0 0 / 0.72));\n\n transition: opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 内容包裹层:仅作「图片舞台层 + 控件层」的结构容器,自身不做任何过渡。\n scale 不能放在 dialog 上(会带着遮罩一起缩放),也不能放在本层(控件层在其内,\n 带 transform 会让贴边控件从视口边缘向内飞行)。 */\n.wui-image-preview-content {\n position: absolute;\n inset: 0;\n}\n\n/* 图片舞台层:与遮罩同尺寸叠放,承接图片的进场缩放与淡入淡出(0.95→1)。内部无玻璃\n 元素,自身 opacity 过渡不影响 backdrop-filter;transform 不构成 backdrop root,\n 也不会波及兄弟的控件层。 */\n.wui-image-preview-surface {\n position: absolute;\n inset: 0;\n transform: scale(var(--wui-scale-enter, 0.95));\n\n opacity: 0;\n\n transition:\n opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1)),\n transform var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 玻璃控件(counter/toolbar)各自做 own opacity 过渡:玻璃元素自身 opacity 淡入\n 不禁用自身 backdrop-filter(backdrop root 只关闭后代 blur),因此控件淡入淡出时\n blur 仍连续;nav/close 是 glass 按钮,blur 在其 shadow 内层原生 button 上,必须\n 经 ::part(button) 落在该玻璃元素自身,若对按钮 host 做 opacity 过渡反而会让\n host 成为 backdrop root、禁掉内层 blur(与祖先 opacity 禁后代 blur 同一机制)。 */\n.wui-image-preview-counter,\n.wui-image-preview-toolbar,\n.wui-image-preview-close::part(button),\n.wui-image-preview-nav::part(button) {\n opacity: 0;\n transition: opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 面板本身是模态表面,不作为可聚焦控件;Safari showModal() 会把焦点放到 dialog,不应画 UA ring。内部控件保留 focus ring。 */\ndialog:focus,\ndialog:focus-visible {\n outline: none;\n}\n\n/* dialog 已铺满视口,原生遮罩不再叠加着色,避免双重变暗。 */\ndialog::backdrop {\n background: transparent;\n}\n\n.wui-image-preview-stage {\n touch-action: none;\n cursor: zoom-in;\n\n position: relative;\n\n overflow: hidden;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-stage.is-zoomed {\n cursor: grab;\n}\n\n.wui-image-preview-stage.is-dragging {\n cursor: grabbing;\n}\n\n/* 单轨道轮播(相邻图渲染):轨道撑满舞台,当前图在原点、左右相邻用绝对定位放在\n ±100%(= 舞台宽度)处,与当前图同尺寸同基线;舞台 overflow 裁切,轨道整体随跟手\n 位移平移。相邻图只在当前索引两侧各渲染一张(loop 环绕、非 loop 缺省一侧),任何\n 索引拖拽(含首尾环绕)相邻图都真实跟手,不会越过轨道末端滑空。\n pointer-events: none 让空白的轨道区域穿透命中到舞台(空白点击仍算遮罩),图片自身\n 恢复 auto 接收手势。 */\n.wui-image-preview-track {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-slide {\n pointer-events: none;\n\n position: absolute;\n top: 0;\n left: 0;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-slide.is-prev {\n left: -100%;\n}\n\n.wui-image-preview-slide.is-next {\n left: 100%;\n}\n\n.wui-image-preview-image {\n pointer-events: auto;\n user-select: none;\n\n display: block;\n\n max-width: 100%;\n max-height: 100%;\n\n opacity: 0;\n object-fit: contain;\n\n /* 拖拽(平移)不参与 transform 过渡(见 .is-dragging),避免跟手位移滞后;\n swipe 只动轨道,图片 transform 在滑动期间不变。 */\n transition:\n opacity var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n -webkit-user-drag: none;\n}\n\n.wui-image-preview-image.is-loaded {\n opacity: 1;\n}\n\n.wui-image-preview-stage.is-dragging .wui-image-preview-image {\n transition: opacity var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n/* 轮播滑入/回位:跟手结束后把轨道 transform 过渡到目标位(当前图滑出、相邻图入位或\n 弹回)。transitionend 会触发组件内的收尾提交;时长/缓动可用组件级变量覆盖。 */\n.wui-image-preview-stage.is-settling .wui-image-preview-track {\n transition: transform var(--wui-duration-swipe-settle, 220ms) var(--wui-ease-swipe, cubic-bezier(0.32, 0.72, 0, 1));\n}\n\n.wui-image-preview-stage.is-dragging .wui-image-preview-track {\n transition: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-image-preview-image,\n .wui-image-preview-stage.is-dragging .wui-image-preview-image,\n .wui-image-preview-stage.is-settling .wui-image-preview-track {\n transition: opacity var(--wui-duration-feedback, 100ms);\n }\n}\n\n.wui-image-preview-controls {\n pointer-events: none;\n position: absolute;\n inset: 0;\n}\n\n.wui-image-preview-controls > * {\n pointer-events: auto;\n}\n\n.wui-image-preview-counter {\n /* pill 高 ≈ 24px(13px 行盒 + 上下 4px padding),光影取短边一半 */\n --wui-glass-corner-radius: 12px;\n\n position: absolute;\n top: var(--wui-image-preview-edge-gap, 20px);\n left: var(--wui-image-preview-edge-gap, 20px);\n\n padding: 4px 12px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n.wui-image-preview-close {\n position: absolute;\n top: var(--wui-image-preview-edge-gap, 20px);\n right: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-nav {\n position: absolute;\n top: 50%;\n translate: 0 -50%;\n}\n\n.wui-image-preview-nav-prev {\n left: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-nav-next {\n right: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-toolbar {\n /* 高 = 30px 图标按钮 + 上下 6px padding,光影取短边一半 */\n --wui-glass-corner-radius: 21px;\n\n position: absolute;\n bottom: var(--wui-image-preview-edge-gap, 20px);\n left: 50%;\n translate: -50% 0;\n\n display: flex;\n gap: 6px;\n align-items: center;\n\n padding: 6px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.wui-image-preview-scale {\n min-width: 48px;\n\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n color: var(--wui-color-text, #1b1b1b);\n text-align: center;\n}\n\ndialog[open].is-visible {\n .wui-image-preview-surface {\n transform: scale(1);\n }\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n opacity: 1;\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n opacity: 1;\n }\n}\n\ndialog[open].is-closing {\n pointer-events: none;\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n dialog,\n dialog[open].is-visible {\n transition-duration: var(--wui-duration-feedback, 100ms);\n\n .wui-image-preview-surface {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/image-preview/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\n/*\n * 全视口 dialog:遮罩由独立 .wui-image-preview-backdrop 层提供(而非 ::backdrop /\n * dialog 自身背景)。dialog 自身 opacity 恒 1、无任何 transform——opacity < 1 会让\n * dialog 成为 backdrop root,后代玻璃控件(toolbar/counter/nav)的 backdrop-filter\n * 在过渡期被禁用、blur 在端点生硬跳变;transform 会把遮罩一起缩放。进场缩放\n * (scale 0.95→1)由 .wui-image-preview-surface 图片舞台层承担(见下)。本组件是满视口\n * 表面,起点 >1 会越出视口,只能用 <1 的档位;缩放也不能落在包住控件层的\n * .wui-image-preview-content 上,否则贴边控件会随缩放从视口边缘向内飞行。遮罩、图片\n * 舞台各自用独立层 opacity 过渡;控件层不参与 opacity 过渡,玻璃控件永不在 opacity < 1\n * 的祖先内,blur 全程连续。\n */\ndialog {\n /* 显式 position: fixed(防御性):UA 的 dialog:modal 默认 fixed,但作者样式若覆盖\n position 会把它退回文档流——top layer 里的 modal dialog 变成按文档流定位,出现在\n 页面顶部且跟随页面滚动。image-preview 的 dialog 铺满视口,fixed 是硬前提。 */\n position: fixed;\n\n overflow: hidden;\n\n box-sizing: border-box;\n width: 100%;\n max-width: none;\n height: 100%;\n height: 100dvh;\n max-height: none;\n margin: 0;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 1;\n background: transparent;\n}\n\n/* 遮罩层:承接原先 dialog 背景的淡入淡出,自身 opacity 过渡不构成 backdrop root。 */\n.wui-image-preview-backdrop {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n opacity: 0;\n background: var(--wui-image-preview-overlay-bg, rgb(0 0 0 / 0.72));\n\n transition: opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 内容包裹层:仅作「图片舞台层 + 控件层」的结构容器,自身不做任何过渡。\n scale 不能放在 dialog 上(会带着遮罩一起缩放),也不能放在本层(控件层在其内,\n 带 transform 会让贴边控件从视口边缘向内飞行)。 */\n.wui-image-preview-content {\n position: absolute;\n inset: 0;\n}\n\n/* 图片舞台层:与遮罩同尺寸叠放,承接图片的进场缩放与淡入淡出(0.95→1)。内部无玻璃\n 元素,自身 opacity 过渡不影响 backdrop-filter;transform 不构成 backdrop root,\n 也不会波及兄弟的控件层。 */\n.wui-image-preview-surface {\n position: absolute;\n inset: 0;\n transform: scale(var(--wui-scale-enter, 0.95));\n\n opacity: 0;\n\n transition:\n opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1)),\n transform var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 玻璃控件(counter/toolbar)各自做 own opacity 过渡:玻璃元素自身 opacity 淡入\n 不禁用自身 backdrop-filter(backdrop root 只关闭后代 blur),因此控件淡入淡出时\n blur 仍连续;nav/close 是 glass 按钮,blur 在其 shadow 内层原生 button 上,必须\n 经 ::part(button) 落在该玻璃元素自身,若对按钮 host 做 opacity 过渡反而会让\n host 成为 backdrop root、禁掉内层 blur(与祖先 opacity 禁后代 blur 同一机制)。 */\n.wui-image-preview-counter,\n.wui-image-preview-toolbar,\n.wui-image-preview-close::part(button),\n.wui-image-preview-nav::part(button) {\n opacity: 0;\n transition: opacity var(--wui-duration-dialog-enter, 320ms) var(--wui-ease-dialog, cubic-bezier(0.2, 0, 0, 1));\n}\n\n/* 面板本身是模态表面,不作为可聚焦控件;Safari showModal() 会把焦点放到 dialog,不应画 UA ring。内部控件保留 focus ring。 */\ndialog:focus,\ndialog:focus-visible {\n outline: none;\n}\n\n/* dialog 已铺满视口,原生遮罩不再叠加着色,避免双重变暗。 */\ndialog::backdrop {\n background: transparent;\n}\n\n.wui-image-preview-stage {\n touch-action: none;\n cursor: zoom-in;\n\n position: relative;\n\n overflow: hidden;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-stage.is-zoomed {\n cursor: grab;\n}\n\n.wui-image-preview-stage.is-dragging {\n cursor: grabbing;\n}\n\n/* 单轨道轮播(相邻图渲染):轨道撑满舞台,当前图在原点、左右相邻用绝对定位放在\n ±100%(= 舞台宽度)处,与当前图同尺寸同基线;舞台 overflow 裁切,轨道整体随跟手\n 位移平移。相邻图只在当前索引两侧各渲染一张(loop 环绕、非 loop 缺省一侧),任何\n 索引拖拽(含首尾环绕)相邻图都真实跟手,不会越过轨道末端滑空。\n pointer-events: none 让空白的轨道区域穿透命中到舞台(空白点击仍算遮罩),图片自身\n 恢复 auto 接收手势。 */\n.wui-image-preview-track {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-slide {\n pointer-events: none;\n\n position: absolute;\n top: 0;\n left: 0;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 100%;\n}\n\n.wui-image-preview-slide.is-prev {\n left: -100%;\n}\n\n.wui-image-preview-slide.is-next {\n left: 100%;\n}\n\n.wui-image-preview-image {\n pointer-events: auto;\n user-select: none;\n\n display: block;\n\n max-width: 100%;\n max-height: 100%;\n\n opacity: 0;\n object-fit: contain;\n\n /* 拖拽(平移)不参与 transform 过渡(见 .is-dragging),避免跟手位移滞后;\n swipe 只动轨道,图片 transform 在滑动期间不变。 */\n transition:\n opacity var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n -webkit-user-drag: none;\n}\n\n.wui-image-preview-image.is-loaded {\n opacity: 1;\n}\n\n.wui-image-preview-stage.is-dragging .wui-image-preview-image {\n transition: opacity var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n/* 轮播滑入/回位:跟手结束后把轨道 transform 过渡到目标位(当前图滑出、相邻图入位或\n 弹回)。transitionend 会触发组件内的收尾提交;时长/缓动可用组件级变量覆盖。 */\n.wui-image-preview-stage.is-settling .wui-image-preview-track {\n transition: transform var(--wui-duration-swipe-settle, 220ms) var(--wui-ease-swipe, cubic-bezier(0.32, 0.72, 0, 1));\n}\n\n.wui-image-preview-stage.is-dragging .wui-image-preview-track {\n transition: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-image-preview-image,\n .wui-image-preview-stage.is-dragging .wui-image-preview-image,\n .wui-image-preview-stage.is-settling .wui-image-preview-track {\n transition: opacity var(--wui-duration-feedback, 100ms);\n }\n}\n\n.wui-image-preview-controls {\n pointer-events: none;\n position: absolute;\n inset: 0;\n}\n\n.wui-image-preview-controls > * {\n pointer-events: auto;\n}\n\n.wui-image-preview-counter {\n /* pill 高 ≈ 24px(13px 行盒 + 上下 4px padding),光影取短边一半 */\n --wui-glass-corner-radius: 12px;\n\n position: absolute;\n top: var(--wui-image-preview-edge-gap, 20px);\n left: var(--wui-image-preview-edge-gap, 20px);\n\n padding: var(--wui-space-1, 4px) var(--wui-space-3, 12px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size-readout, 13px);\n font-variant-numeric: tabular-nums;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n.wui-image-preview-close {\n position: absolute;\n top: var(--wui-image-preview-edge-gap, 20px);\n right: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-nav {\n position: absolute;\n top: 50%;\n translate: 0 -50%;\n}\n\n.wui-image-preview-nav-prev {\n left: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-nav-next {\n right: var(--wui-image-preview-edge-gap, 20px);\n}\n\n.wui-image-preview-toolbar {\n /* 高 = 30px 图标按钮 + 上下 6px padding,光影取短边一半 */\n --wui-glass-corner-radius: 21px;\n\n position: absolute;\n bottom: var(--wui-image-preview-edge-gap, 20px);\n left: 50%;\n translate: -50% 0;\n\n display: flex;\n gap: 6px;\n align-items: center;\n\n padding: 6px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.wui-image-preview-scale {\n min-width: 48px;\n\n font-size: var(--wui-font-size-readout, 13px);\n font-variant-numeric: tabular-nums;\n color: var(--wui-color-text, #1b1b1b);\n text-align: center;\n}\n\ndialog[open].is-visible {\n .wui-image-preview-surface {\n transform: scale(1);\n }\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n opacity: 1;\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n opacity: 1;\n }\n}\n\ndialog[open].is-closing {\n pointer-events: none;\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n transition-duration: var(--wui-duration-dialog-exit, 260ms);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n dialog,\n dialog[open].is-visible {\n transition-duration: var(--wui-duration-feedback, 100ms);\n\n .wui-image-preview-surface {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n\n .wui-image-preview-backdrop,\n .wui-image-preview-surface,\n .wui-image-preview-counter,\n .wui-image-preview-toolbar {\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n\n .wui-image-preview-close::part(button),\n .wui-image-preview-nav::part(button) {\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n }\n}\n"],"mappings":""}
@@ -1,28 +1,28 @@
1
1
  import { WebUiIcon as e } from "./icon/index.js";
2
2
  import { WebUiButton as t } from "./button/index.js";
3
3
  import { WebUiInput as n } from "./input/index.js";
4
- import { WebUiOption as r } from "./option/index.js";
5
- import { WebUiAutocomplete as i } from "./autocomplete/index.js";
6
- import { WebUiAvatar as a } from "./avatar/index.js";
7
- import { WebUiBackTop as o } from "./back-top/index.js";
8
- import { WebUiBadge as s } from "./badge/index.js";
9
- import { WebUiButtonGroup as c } from "./button-group/index.js";
10
- import { WebUiSvgDrawLines as l } from "./svg-draw-lines/index.js";
11
- import { WebUiCheckbox as u } from "./checkbox/index.js";
12
- import { WebUiCheckboxGroup as d } from "./checkbox-group/index.js";
13
- import { WebUiCollapse as f } from "./collapse/index.js";
14
- import { WebUiDropdownDivider as p } from "./dropdown-divider/index.js";
15
- import { WebUiDropdownHeader as m } from "./dropdown-header/index.js";
16
- import { WebUiDropdownItem as h } from "./dropdown-item/index.js";
17
- import { WebUiContextMenu as g } from "./context-menu/index.js";
18
- import { WebUiDialog as _ } from "./dialog/index.js";
19
- import { WebUiDrawer as v } from "./drawer/index.js";
20
- import { WebUiDropdown as y } from "./dropdown/index.js";
21
- import { WebUiEditableText as b } from "./editable-text/index.js";
22
- import { WebUiEmpty as x } from "./empty/index.js";
23
- import { imagePreview as S } from "./image-preview/index.js";
24
- import { WebUiInputNumber as C } from "./input-number/index.js";
25
- import { WebUiLayout as w } from "./layout/index.js";
4
+ import { WebUiAutocomplete as r } from "./autocomplete/index.js";
5
+ import { WebUiAvatar as i } from "./avatar/index.js";
6
+ import { WebUiBackTop as a } from "./back-top/index.js";
7
+ import { WebUiBadge as o } from "./badge/index.js";
8
+ import { WebUiButtonGroup as s } from "./button-group/index.js";
9
+ import { WebUiSvgDrawLines as c } from "./svg-draw-lines/index.js";
10
+ import { WebUiCheckbox as l } from "./checkbox/index.js";
11
+ import { WebUiCheckboxGroup as u } from "./checkbox-group/index.js";
12
+ import { WebUiCollapse as d } from "./collapse/index.js";
13
+ import { WebUiContextMenu as f } from "./context-menu/index.js";
14
+ import { WebUiDialog as p } from "./dialog/index.js";
15
+ import { WebUiDrawer as m } from "./drawer/index.js";
16
+ import { WebUiDropdownDivider as h } from "./dropdown-divider/index.js";
17
+ import { WebUiDropdownHeader as g } from "./dropdown-header/index.js";
18
+ import { WebUiDropdownItem as _ } from "./dropdown-item/index.js";
19
+ import { WebUiDropdown as v } from "./dropdown/index.js";
20
+ import { WebUiEditableText as y } from "./editable-text/index.js";
21
+ import { WebUiEmpty as b } from "./empty/index.js";
22
+ import { imagePreview as x } from "./image-preview/index.js";
23
+ import { WebUiInputNumber as S } from "./input-number/index.js";
24
+ import { WebUiLayout as C } from "./layout/index.js";
25
+ import { WebUiOption as w } from "./option/index.js";
26
26
  import { WebUiPopover as T } from "./popover/index.js";
27
27
  import { WebUiRadio as E } from "./radio/index.js";
28
28
  import { WebUiRadioGroup as D } from "./radio-group/index.js";
@@ -38,4 +38,4 @@ import { WebUiToast as I } from "./toast/toast.js";
38
38
  import "./toast/index.js";
39
39
  import { WebUiSwitch as L } from "./switch/index.js";
40
40
  import { WebUiTooltip as R } from "./tooltip/index.js";
41
- export { i as WebUiAutocomplete, a as WebUiAvatar, o as WebUiBackTop, s as WebUiBadge, t as WebUiButton, c as WebUiButtonGroup, u as WebUiCheckbox, d as WebUiCheckboxGroup, f as WebUiCollapse, g as WebUiContextMenu, _ as WebUiDialog, v as WebUiDrawer, y as WebUiDropdown, p as WebUiDropdownDivider, m as WebUiDropdownHeader, h as WebUiDropdownItem, b as WebUiEditableText, x as WebUiEmpty, e as WebUiIcon, n as WebUiInput, C as WebUiInputNumber, w as WebUiLayout, r as WebUiOption, T as WebUiPopover, E as WebUiRadio, D as WebUiRadioGroup, O as WebUiSegmented, k as WebUiSegmentedTrigger, A as WebUiSelect, j as WebUiSlider, M as WebUiSpinner, l as WebUiSvgDrawLines, L as WebUiSwitch, N as WebUiTextarea, P as WebUiTheme, I as WebUiToast, R as WebUiTooltip, S as imagePreview, F as toast };
41
+ export { r as WebUiAutocomplete, i as WebUiAvatar, a as WebUiBackTop, o as WebUiBadge, t as WebUiButton, s as WebUiButtonGroup, l as WebUiCheckbox, u as WebUiCheckboxGroup, d as WebUiCollapse, f as WebUiContextMenu, p as WebUiDialog, m as WebUiDrawer, v as WebUiDropdown, h as WebUiDropdownDivider, g as WebUiDropdownHeader, _ as WebUiDropdownItem, y as WebUiEditableText, b as WebUiEmpty, e as WebUiIcon, n as WebUiInput, S as WebUiInputNumber, C as WebUiLayout, w as WebUiOption, T as WebUiPopover, E as WebUiRadio, D as WebUiRadioGroup, O as WebUiSegmented, k as WebUiSegmentedTrigger, A as WebUiSelect, j as WebUiSlider, M as WebUiSpinner, c as WebUiSvgDrawLines, L as WebUiSwitch, N as WebUiTextarea, P as WebUiTheme, I as WebUiToast, R as WebUiTooltip, x as imagePreview, F as toast };
@@ -1,5 +1,5 @@
1
1
  //#region src/components/input/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{--wui-input-clear-color:var(--wui-color-text-tertiary,color-mix(in srgb, var(--wui-color-text) 35%, transparent));display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-input-inner{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);border-radius:var(--wui-radius-control,calc(infinity * 1px));align-items:center;gap:8px;padding:0 12px;display:flex;position:relative}:host([full]){display:block}:host([full]) .wui-input-inner{width:100%}:host([borderless]) .wui-input-inner{-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;background:0 0;border:none}:host([borderless]) .wui-input-inner:before{content:none}.wui-input-inner:after{pointer-events:none;content:\"\";border-radius:inherit;box-shadow:inset 0 0 0 1px transparent, 0 0 0 var(--wui-focus-ring-width,3px) transparent;transition:box-shadow var(--wui-duration-focus,.2s);position:absolute;inset:0}:host([focused]) .wui-input-inner:after{box-shadow:inset 0 0 0 1px var(--wui-color-accent,#08f), 0 0 0 var(--wui-focus-ring-width,3px) var(--wui-color-focus-ring,#08f6)}input{min-width:0;height:100%;font:inherit;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background:0 0;border:none;outline:none;flex:1;margin:0;padding:0}input::placeholder{color:var(--wui-color-text-secondary,#6a6a6a)}input:disabled{cursor:not-allowed;opacity:.4}@media (pointer:coarse){input{font-size:max(16px, var(--wui-font-size,14px))}}slot{font-size:var(--wui-font-size,14px);color:var(--wui-color-text-secondary,#6a6a6a);flex-shrink:0;align-items:center;display:flex}slot.empty{display:none}.wui-input-inner web-ui-button[variant=ghost]{--wui-button-color:var(--wui-input-clear-color);margin-left:-8px;margin-right:-4px}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{--wui-input-clear-color:var(--wui-color-text-tertiary,color-mix(in srgb, var(--wui-color-text) 35%, transparent));display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-input-inner{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);gap:var(--wui-space-2,8px);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);padding:0 var(--wui-space-3,12px);border-radius:var(--wui-radius-control,calc(infinity * 1px));align-items:center;display:flex;position:relative}:host([full]){display:block}:host([full]) .wui-input-inner{width:100%}:host([borderless]) .wui-input-inner{-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;background:0 0;border:none}:host([borderless]) .wui-input-inner:before{content:none}.wui-input-inner:after{pointer-events:none;content:\"\";border-radius:inherit;box-shadow:inset 0 0 0 1px transparent, 0 0 0 var(--wui-focus-ring-width,3px) transparent;transition:box-shadow var(--wui-duration-focus,.2s);position:absolute;inset:0}:host([focused]) .wui-input-inner:after{box-shadow:inset 0 0 0 1px var(--wui-color-accent,#08f), 0 0 0 var(--wui-focus-ring-width,3px) var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent))}input{min-width:0;height:100%;font:inherit;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background:0 0;border:none;outline:none;flex:1;margin:0;padding:0}input::placeholder{color:var(--wui-color-text-secondary,#6a6a6a)}input:disabled{cursor:not-allowed;opacity:.4}@media (pointer:coarse){input{font-size:max(16px, var(--wui-font-size,14px))}}slot{font-size:var(--wui-font-size,14px);color:var(--wui-color-text-secondary,#6a6a6a);flex-shrink:0;align-items:center;display:flex}slot.empty{display:none}.wui-input-inner web-ui-button[variant=ghost]{--wui-button-color:var(--wui-input-clear-color);margin-left:-8px;margin-right:-4px}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/input/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-input-clear-color: var(--wui-color-text-tertiary, color-mix(in srgb, var(--wui-color-text) 35%, transparent));\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-input-inner {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n position: relative;\n\n display: flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 12px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n:host([full]) {\n display: block;\n}\n\n:host([full]) .wui-input-inner {\n width: 100%;\n}\n\n:host([borderless]) .wui-input-inner {\n border: none;\n background: transparent;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n/* borderless 必须移除 glass 描边环(.wui-glass::before 底环 + 对角光泽),\n 否则无框后仍残留 1px 胶囊描边 */\n:host([borderless]) .wui-input-inner::before {\n content: none;\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-input-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-input-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px) var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n}\n\ninput {\n flex: 1;\n\n min-width: 0;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: var(--wui-color-text-secondary, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n input {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\nslot {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n/* slot 无 slotted 内容时折叠 */\nslot.empty {\n display: none;\n}\n\n/* 复用 web-ui-button icon ghost:仅覆盖颜色为 faint,保持弱意图清除图标观感;\n 负 margin-left 抵消容器 flex gap,让清除按钮紧贴输入文本\n 负 margin-right 抵消 button padding,让清除按钮右侧 spacing 视觉上协调 */\n.wui-input-inner web-ui-button[variant='ghost'] {\n --wui-button-color: var(--wui-input-clear-color);\n margin-right: -4px;\n margin-left: -8px;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/input/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-input-clear-color: var(--wui-color-text-tertiary, color-mix(in srgb, var(--wui-color-text) 35%, transparent));\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-input-inner {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n position: relative;\n\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 var(--wui-space-3, 12px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n:host([full]) {\n display: block;\n}\n\n:host([full]) .wui-input-inner {\n width: 100%;\n}\n\n:host([borderless]) .wui-input-inner {\n border: none;\n background: transparent;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n/* borderless 必须移除 glass 描边环(.wui-glass::before 底环 + 对角光泽),\n 否则无框后仍残留 1px 胶囊描边 */\n:host([borderless]) .wui-input-inner::before {\n content: none;\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-input-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-input-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px)\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n}\n\ninput {\n flex: 1;\n\n min-width: 0;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: var(--wui-color-text-secondary, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n input {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\nslot {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\nslot.empty {\n display: none;\n}\n\n/* 复用 web-ui-button icon ghost:仅覆盖颜色为 faint,保持弱意图清除图标观感;\n 负 margin-left 抵消容器 flex gap,让清除按钮紧贴输入文本\n 负 margin-right 抵消 button padding,让清除按钮右侧 spacing 视觉上协调 */\n.wui-input-inner web-ui-button[variant='ghost'] {\n --wui-button-color: var(--wui-input-clear-color);\n margin-right: -4px;\n margin-left: -8px;\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/input-number/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-input-inner{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);border-radius:var(--wui-radius-control,calc(infinity * 1px));align-items:center;gap:4px;padding:0 4px;display:flex;position:relative}input{min-width:48px;height:100%;font:inherit;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-align:center;background:0 0;border:none;outline:none;flex:1;margin:0;padding:0}input::-webkit-inner-spin-button{appearance:none;margin:0}input::-webkit-outer-spin-button{appearance:none;margin:0}input[type=number]{appearance:textfield}input:disabled{cursor:not-allowed;opacity:.4}@media (pointer:coarse){input{font-size:max(16px, var(--wui-font-size,14px))}}.wui-input-inner:after{pointer-events:none;content:\"\";border-radius:inherit;box-shadow:inset 0 0 0 1px transparent, 0 0 0 var(--wui-focus-ring-width,3px) transparent;transition:box-shadow var(--wui-duration-focus,.2s);position:absolute;inset:0}:host([focused]) .wui-input-inner:after{box-shadow:inset 0 0 0 1px var(--wui-color-accent,#08f), 0 0 0 var(--wui-focus-ring-width,3px) var(--wui-color-focus-ring,#08f6)}.num-btn{cursor:default;border-radius:var(--wui-radius-control,calc(infinity * 1px));width:30px;height:30px;color:var(--wui-color-text-secondary,#6a6a6a);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:flex}.num-btn:disabled{cursor:not-allowed;opacity:.4}.num-btn:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}@media (hover:hover) and (pointer:fine){.num-btn:hover:not(:disabled){background:var(--wui-color-state-layer-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent))}}.num-btn:active:not(:disabled){background:var(--wui-color-state-layer-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent))}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-input-inner{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);gap:var(--wui-space-1,4px);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);padding:0 var(--wui-space-1,4px);border-radius:var(--wui-radius-control,calc(infinity * 1px));align-items:center;display:flex;position:relative}input{min-width:48px;height:100%;font:inherit;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-align:center;background:0 0;border:none;outline:none;flex:1;margin:0;padding:0}input::-webkit-inner-spin-button{appearance:none;margin:0}input::-webkit-outer-spin-button{appearance:none;margin:0}input[type=number]{appearance:textfield}input:disabled{cursor:not-allowed;opacity:.4}@media (pointer:coarse){input{font-size:max(16px, var(--wui-font-size,14px))}}.wui-input-inner:after{pointer-events:none;content:\"\";border-radius:inherit;box-shadow:inset 0 0 0 1px transparent, 0 0 0 var(--wui-focus-ring-width,3px) transparent;transition:box-shadow var(--wui-duration-focus,.2s);position:absolute;inset:0}:host([focused]) .wui-input-inner:after{box-shadow:inset 0 0 0 1px var(--wui-color-accent,#08f), 0 0 0 var(--wui-focus-ring-width,3px) var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent))}.num-btn{cursor:default;border-radius:var(--wui-radius-control,calc(infinity * 1px));width:30px;height:30px;color:var(--wui-color-text-secondary,#6a6a6a);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:flex}.num-btn:disabled{cursor:not-allowed;opacity:.4}.num-btn:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent));outline-offset:2px}@media (hover:hover) and (pointer:fine){.num-btn:hover:not(:disabled){background:var(--wui-color-state-layer-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent))}}.num-btn:active:not(:disabled){background:var(--wui-color-state-layer-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent))}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/input-number/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-input-inner {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n position: relative;\n\n display: flex;\n gap: 4px;\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 4px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\ninput {\n flex: 1;\n\n min-width: 48px;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-align: center;\n\n background: transparent;\n outline: none;\n\n &::-webkit-inner-spin-button,\n &::-webkit-outer-spin-button {\n margin: 0;\n appearance: none;\n }\n\n &[type='number'] {\n appearance: textfield;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n input {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-input-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-input-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px) var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n}\n\n.num-btn {\n cursor: default;\n\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 30px;\n height: 30px;\n padding: 0;\n border: none;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n color: var(--wui-color-text-secondary, #6a6a6a);\n\n background: transparent;\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n .num-btn:hover:not(:disabled) {\n background: var(--wui-color-state-layer-hover, color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent));\n }\n}\n\n.num-btn:active:not(:disabled) {\n background: var(--wui-color-state-layer-active, color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent));\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/input-number/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-input-inner {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n position: relative;\n\n display: flex;\n gap: var(--wui-space-1, 4px);\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 var(--wui-space-1, 4px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\ninput {\n flex: 1;\n\n min-width: 48px;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-align: center;\n\n background: transparent;\n outline: none;\n\n &::-webkit-inner-spin-button,\n &::-webkit-outer-spin-button {\n margin: 0;\n appearance: none;\n }\n\n &[type='number'] {\n appearance: textfield;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n input {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-input-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-input-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px)\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n}\n\n.num-btn {\n cursor: default;\n\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 30px;\n height: 30px;\n padding: 0;\n border: none;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n color: var(--wui-color-text-secondary, #6a6a6a);\n\n background: transparent;\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n outline-offset: 2px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n .num-btn:hover:not(:disabled) {\n background: var(--wui-color-state-layer-hover, color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent));\n }\n}\n\n.num-btn:active:not(:disabled) {\n background: var(--wui-color-state-layer-active, color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent));\n}\n"],"mappings":""}
@@ -38,9 +38,6 @@ export declare class WebUiLayout extends LitElement {
38
38
  * 因而不与 `sidebarCollapsed` 合并,避免响应式切换时将一次移动端交互误写为桌面端布局选择。
39
39
  */
40
40
  sidebarOpen: boolean;
41
- /**
42
- * 启用 header 晕染效果
43
- */
44
41
  headerGlow: boolean;
45
42
  private _isMobile;
46
43
  private readonly _visibleBanner;
@@ -154,7 +154,7 @@ var _ = class extends c {
154
154
  <web-ui-button
155
155
  class="sidebar-toggle"
156
156
  icon
157
- variant="glass"
157
+ variant="secondary"
158
158
  @click="${this._toggleSidebar}"
159
159
  aria-label="${r}"
160
160
  >
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/layout/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport '@/components/icon'\nimport '@/components/button'\nimport '@/components/drawer'\nimport { radixIconsPanelLeftMinimized } from '@/icons'\nimport { attachDragGesture, clamp, type DragGestureHandle } from '@/shared/gesture'\nimport { defineVisibleAreaTracker, VisibleAreaController } from '@/shared/visible-area'\n\nimport style from './style.css?inline'\n\n/**\n * Layout 组件 - 提供页面布局框架,支持可折叠侧边栏\n *\n * @fires sidebar-collapsed-change - 桌面端侧边栏折叠状态变更请求时触发\n * @fires sidebar-open-change - 移动端侧边栏 Drawer 开关请求时触发\n * @fires sidebar-width-change - 桌面端侧边栏拖拽调宽结束时触发,携带最终宽度(受控请求)\n * @slot banner - 顶部 Banner 区域(全宽,随页面滚动,可选)\n * @slot header - 内容区顶部 header(sticky)\n * @slot sidebar - 侧边栏内容;Consumer 决定其内部固定区域与滚动容器\n * @slot tabbar - 底部 tabbar 区域\n * @slot default - 主内容区\n */\n@customElement('web-ui-layout')\nexport class WebUiLayout extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n /**\n * 桌面端 Sidebar 的持久布局偏好。\n *\n * `true` 只会将桌面 Sidebar 收窄到 `collapsedWidth`,不会影响移动端 Drawer。\n * 它不与 `sidebarOpen` 合并:前者是跨视口保留的密度选择,后者是移动端瞬时的 modal 可见性。\n */\n @property({ type: Boolean, attribute: 'sidebar-collapsed', reflect: true })\n sidebarCollapsed = false\n\n @property({ type: String, attribute: 'sidebar-width', reflect: true })\n sidebarWidth = '240px'\n\n @property({ type: String, attribute: 'collapsed-width', reflect: true })\n collapsedWidth = '68px'\n\n /** 启用桌面端 Sidebar 拖拽调宽(折叠态隐藏 handle)。 */\n @property({ type: Boolean, attribute: 'sidebar-resizable', reflect: true })\n sidebarResizable = false\n\n /**\n * 拖拽调宽的下限(px,其他单位不解析);未设置时回退为 `collapsedWidth`,\n * 防止拖到不可用宽度。上限 `sidebar-max-width` 受内置 50vw 硬上限钳制。\n */\n @property({ type: String, attribute: 'sidebar-min-width', reflect: true })\n sidebarMinWidth = ''\n\n /** 拖拽调宽的上限(px,其他单位不解析);始终受内置 50vw 硬上限钳制。 */\n @property({ type: String, attribute: 'sidebar-max-width', reflect: true })\n sidebarMaxWidth = ''\n\n /**\n * 移动端 web-ui-drawer 的瞬时可见性。\n *\n * Drawer Toggle、Escape 和遮罩关闭都通过 `sidebar-open-change` 请求更新它;它不会改变桌面端的折叠偏好。\n * 因而不与 `sidebarCollapsed` 合并,避免响应式切换时将一次移动端交互误写为桌面端布局选择。\n */\n @property({ type: Boolean, attribute: 'sidebar-open', reflect: true })\n sidebarOpen = false\n\n /**\n * 启用 header 晕染效果\n */\n @property({ type: Boolean, attribute: 'header-glow', reflect: true })\n headerGlow = false\n\n @state() private _isMobile = false\n\n private readonly _visibleBanner = defineVisibleAreaTracker({\n onVisibleAreaChange: area => {\n this.style.setProperty('--wui-layout-visible-banner-height', `${area.height}px`)\n }\n }).make()\n\n private readonly _visibleBannerController = new VisibleAreaController(this, this._visibleBanner)\n\n private _toggleSidebar() {\n if (this._isMobile) {\n this._emitSidebarOpenChange(!this.sidebarOpen)\n return\n }\n\n this._emitSidebarCollapsedChange(!this.sidebarCollapsed)\n }\n\n private _emitSidebarCollapsedChange(collapsed: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-collapsed-change', {\n detail: { collapsed },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _emitSidebarOpenChange(open: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _onDrawerChange(e: CustomEvent<{ open: boolean }>) {\n e.stopPropagation()\n this._emitSidebarOpenChange(e.detail.open)\n }\n\n private _resizeGesture: DragGestureHandle | null = null\n private _resizeStartWidth = 0\n // 拖拽中的临时宽度;由 render 的 styleMap 统一写入,避免与 Lit 样式管理竞争。\n @state() private _resizeWidth: string | null = null\n\n private _parsePx(value: string, fallback: number): number {\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) ? parsed : fallback\n }\n\n private _resolveSidebarMinWidth(): number {\n return this.sidebarMinWidth\n ? this._parsePx(this.sidebarMinWidth, this._parsePx(this.collapsedWidth, 68))\n : this._parsePx(this.collapsedWidth, 68)\n }\n\n private _resolveSidebarMaxWidth(): number {\n // 组件内置硬上限:Sidebar 最多占视口一半(无需调用方设置)。\n // 调用方 sidebar-max-width 在该上限内生效,防止拖拽占据整个视口。\n const halfViewport = Math.floor(window.innerWidth / 2)\n const configured = this.sidebarMaxWidth ? this._parsePx(this.sidebarMaxWidth, halfViewport) : halfViewport\n const upper = Math.min(configured, halfViewport)\n return Math.max(upper, this._resolveSidebarMinWidth())\n }\n\n private _isResizing(): boolean {\n return this._resizeGesture?.isDragging() ?? false\n }\n\n private _handleResizePointerDown(e: PointerEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n // jsdom 等环境的 PointerEvent 可能缺失 isPrimary,仅在明确为 false(多点触控副指针)时拒绝。\n if (e.isPrimary === false) return\n\n const aside = this.renderRoot.querySelector('aside')\n if (!aside) return\n\n // 拖拽起点以 computed width 为准,并丢弃键盘未提交的调整(Enter 才提交、\n // Escape 撤回;抓取隐式放弃),保证零位移松手不会派发陈旧宽度。\n this._resizeStartWidth = this._parsePx(window.getComputedStyle(aside).width, this._parsePx(this.sidebarWidth, 240))\n this._resizeWidth = null\n aside.classList.add('is-resizing')\n\n this._resizeGesture = attachDragGesture(e, {\n axis: 'x',\n onMove: info => {\n // 向右拖增宽、向左拖收窄(handle 在右缘);钳制在 [min, max] 与视口内。\n const next = this._resizeStartWidth + info.deltaX\n const clamped = clamp(next, this._resolveSidebarMinWidth(), this._resolveSidebarMaxWidth())\n this._resizeWidth = `${Math.round(clamped)}px`\n },\n onEnd: () => {\n // 零位移松手(点击而非拖拽)不视为调宽动作:按 cancel 语义静默收尾。\n if (this._resizeWidth === null) {\n this._resetActiveResize()\n return\n }\n const width = this._resizeWidth\n this._resetActiveResize()\n // 受控契约:松手派发请求并交还 prop 管辖,由 Consumer 回写 sidebar-width。\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', {\n detail: { width },\n bubbles: true,\n composed: true\n })\n )\n },\n onCancel: () => {\n this._resetActiveResize()\n }\n })\n }\n\n // 终结进行中的拖拽:清手势状态、移除跟手 class,宽度过渡回 prop 管辖,不派发事件。\n // pointer cancel 与视口跨越移动端断点(handle 随桌面 layout 卸载)共用此收尾。\n private _resetActiveResize() {\n this._resizeGesture?.destroy()\n this._resizeGesture = null\n this.renderRoot.querySelector('aside')?.classList.remove('is-resizing')\n this._resizeWidth = null\n }\n\n // 键盘调宽(WAI-ARIA splitter 模式):方向键步进 16px(Shift 加速 64px)调整\n // 临时宽度,Enter 以受控请求派发 `sidebar-width-change`(与指针松手同语义),\n // Escape 撤回临时宽度交还 prop 管辖,Home/End 直接到 min/max。\n private _handleResizeKeydown(e: KeyboardEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n\n const min = this._resolveSidebarMinWidth()\n const max = this._resolveSidebarMaxWidth()\n const aside = this.renderRoot.querySelector('aside')\n const current = this._resizeWidth\n ? this._parsePx(this._resizeWidth, min)\n : this._parsePx(aside ? window.getComputedStyle(aside).width : this.sidebarWidth, min)\n const step = e.shiftKey ? 64 : 16\n let next: number | null = null\n\n switch (e.key) {\n case 'ArrowLeft':\n next = Math.max(min, current - step)\n break\n case 'ArrowRight':\n next = Math.min(max, current + step)\n break\n case 'Home':\n next = min\n break\n case 'End':\n next = max\n break\n case 'Enter':\n // 无未提交调整时不派发(焦点停留时的回车噪声)\n if (this._resizeWidth !== null) {\n const width = this._resizeWidth\n this._resizeWidth = null\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', { detail: { width }, bubbles: true, composed: true })\n )\n }\n e.preventDefault()\n return\n case 'Escape':\n this._resizeWidth = null\n e.preventDefault()\n return\n default:\n return\n }\n e.preventDefault()\n this._resizeWidth = `${Math.round(next)}px`\n }\n\n private _checkMobile() {\n const nextMobile = window.innerWidth <= 640\n // 视口跨越移动端断点会卸载桌面 layout(handle 随之消失);必须先终结进行中的\n // 拖拽,否则 _resizePointerId 悬挂,切回桌面后所有新的拖拽在入口被拦截。\n if (nextMobile !== this._isMobile && this._isResizing()) this._resetActiveResize()\n this._isMobile = nextMobile\n }\n\n private _resizeTimeout: ReturnType<typeof setTimeout> | null = null\n\n private _handleResize = () => {\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = setTimeout(() => {\n this._checkMobile()\n this._resizeTimeout = null\n }, 100)\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._checkMobile()\n window.addEventListener('resize', this._handleResize)\n void this.updateComplete.then(() => {\n if (this.isConnected) this._syncBannerPresence()\n })\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._resetActiveResize()\n window.removeEventListener('resize', this._handleResize)\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = null\n }\n\n override firstUpdated() {\n this._syncBannerPresence()\n }\n\n private _onBannerSlotChange() {\n this._syncBannerPresence()\n }\n\n private _syncBannerPresence() {\n const bannerSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"banner\"]')\n const hasBanner =\n bannerSlot\n ?.assignedNodes()\n .some(\n node =>\n node.nodeType === Node.ELEMENT_NODE || (node.nodeType === Node.TEXT_NODE && !!node.textContent?.trim())\n ) ?? false\n const banner = this.shadowRoot?.querySelector<HTMLElement>('.layout-banner') ?? null\n this._visibleBanner.setTarget(hasBanner ? banner : null)\n }\n\n override render() {\n const isSidebarOpen = !this.sidebarCollapsed\n // 拖拽中的临时宽度优先于 prop 宽度;移动端宽度由 Drawer 内部变量管理。\n const sidebarStyle = this._isMobile\n ? {}\n : { width: this._resizeWidth ?? (this.sidebarCollapsed ? this.collapsedWidth : this.sidebarWidth) }\n\n const toggleLabel = isSidebarOpen ? '折叠侧边栏' : '展开侧边栏'\n\n const desktopToggle = html`\n <web-ui-button\n class=\"sidebar-toggle\"\n icon\n variant=\"glass\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"${toggleLabel}\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n `\n\n const sidebarViewport = html`\n <div class=\"sidebar-viewport\">\n <slot name=\"sidebar\"></slot>\n </div>\n `\n\n const desktopLayout = html`\n <div class=\"layout-body\">\n <div class=\"sidebar-wrapper\">\n <aside\n class=\"${classMap({\n collapsed: !isSidebarOpen\n })}\"\n style=\"${styleMap(sidebarStyle)}\"\n >\n <div class=\"aside-panel wui-glass\">\n ${sidebarViewport}\n <div class=\"sidebar-toggle-area\">${desktopToggle}</div>\n </div>\n ${\n this.sidebarResizable && !this.sidebarCollapsed\n ? html`\n <div\n class=\"sidebar-resize-handle\"\n role=\"separator\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n aria-label=\"调整侧边栏宽度\"\n @pointerdown=${this._handleResizePointerDown}\n @keydown=${this._handleResizeKeydown}\n ></div>\n `\n : nothing\n }\n </aside>\n </div>\n <div class=\"layout-content\">\n <header>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n </div>\n `\n\n const mobileLayout = html`\n <div class=\"layout-content\">\n <header>\n <web-ui-button\n class=\"mobile-toggle\"\n icon\n variant=\"glass\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"打开导航菜单\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n\n <web-ui-drawer\n placement=\"left\"\n ?open=\"${this.sidebarOpen}\"\n controlled\n draggable\n dialog-label=\"主导航\"\n @open-change=\"${this._onDrawerChange}\"\n style=\"${styleMap({\n '--wui-drawer-width': this.sidebarWidth,\n '--wui-drawer-radius': 'var(--wui-layout-sidebar-radius, 24px)'\n })}\"\n >\n ${sidebarViewport}\n </web-ui-drawer>\n `\n\n return html`\n <div class=\"layout-page\">\n <div class=\"layout-banner\">\n <slot name=\"banner\" @slotchange=\"${this._onBannerSlotChange}\"></slot>\n </div>\n ${this._isMobile ? mobileLayout : desktopLayout}\n </div>\n `\n }\n\n declare readonly $events: {\n 'sidebar-collapsed-change': CustomEvent<{ collapsed: boolean }>\n 'sidebar-open-change': CustomEvent<{ open: boolean }>\n 'sidebar-width-change': CustomEvent<{ width: string }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-layout': WebUiLayout\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/layout/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport '@/components/icon'\nimport '@/components/button'\nimport '@/components/drawer'\nimport { radixIconsPanelLeftMinimized } from '@/icons'\nimport { attachDragGesture, clamp, type DragGestureHandle } from '@/shared/gesture'\nimport { defineVisibleAreaTracker, VisibleAreaController } from '@/shared/visible-area'\n\nimport style from './style.css?inline'\n\n/**\n * Layout 组件 - 提供页面布局框架,支持可折叠侧边栏\n *\n * @fires sidebar-collapsed-change - 桌面端侧边栏折叠状态变更请求时触发\n * @fires sidebar-open-change - 移动端侧边栏 Drawer 开关请求时触发\n * @fires sidebar-width-change - 桌面端侧边栏拖拽调宽结束时触发,携带最终宽度(受控请求)\n * @slot banner - 顶部 Banner 区域(全宽,随页面滚动,可选)\n * @slot header - 内容区顶部 header(sticky)\n * @slot sidebar - 侧边栏内容;Consumer 决定其内部固定区域与滚动容器\n * @slot tabbar - 底部 tabbar 区域\n * @slot default - 主内容区\n */\n@customElement('web-ui-layout')\nexport class WebUiLayout extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n /**\n * 桌面端 Sidebar 的持久布局偏好。\n *\n * `true` 只会将桌面 Sidebar 收窄到 `collapsedWidth`,不会影响移动端 Drawer。\n * 它不与 `sidebarOpen` 合并:前者是跨视口保留的密度选择,后者是移动端瞬时的 modal 可见性。\n */\n @property({ type: Boolean, attribute: 'sidebar-collapsed', reflect: true })\n sidebarCollapsed = false\n\n @property({ type: String, attribute: 'sidebar-width', reflect: true })\n sidebarWidth = '240px'\n\n @property({ type: String, attribute: 'collapsed-width', reflect: true })\n collapsedWidth = '68px'\n\n /** 启用桌面端 Sidebar 拖拽调宽(折叠态隐藏 handle)。 */\n @property({ type: Boolean, attribute: 'sidebar-resizable', reflect: true })\n sidebarResizable = false\n\n /**\n * 拖拽调宽的下限(px,其他单位不解析);未设置时回退为 `collapsedWidth`,\n * 防止拖到不可用宽度。上限 `sidebar-max-width` 受内置 50vw 硬上限钳制。\n */\n @property({ type: String, attribute: 'sidebar-min-width', reflect: true })\n sidebarMinWidth = ''\n\n /** 拖拽调宽的上限(px,其他单位不解析);始终受内置 50vw 硬上限钳制。 */\n @property({ type: String, attribute: 'sidebar-max-width', reflect: true })\n sidebarMaxWidth = ''\n\n /**\n * 移动端 web-ui-drawer 的瞬时可见性。\n *\n * Drawer Toggle、Escape 和遮罩关闭都通过 `sidebar-open-change` 请求更新它;它不会改变桌面端的折叠偏好。\n * 因而不与 `sidebarCollapsed` 合并,避免响应式切换时将一次移动端交互误写为桌面端布局选择。\n */\n @property({ type: Boolean, attribute: 'sidebar-open', reflect: true })\n sidebarOpen = false\n\n @property({ type: Boolean, attribute: 'header-glow', reflect: true })\n headerGlow = false\n\n @state() private _isMobile = false\n\n private readonly _visibleBanner = defineVisibleAreaTracker({\n onVisibleAreaChange: area => {\n this.style.setProperty('--wui-layout-visible-banner-height', `${area.height}px`)\n }\n }).make()\n\n private readonly _visibleBannerController = new VisibleAreaController(this, this._visibleBanner)\n\n private _toggleSidebar() {\n if (this._isMobile) {\n this._emitSidebarOpenChange(!this.sidebarOpen)\n return\n }\n\n this._emitSidebarCollapsedChange(!this.sidebarCollapsed)\n }\n\n private _emitSidebarCollapsedChange(collapsed: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-collapsed-change', {\n detail: { collapsed },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _emitSidebarOpenChange(open: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _onDrawerChange(e: CustomEvent<{ open: boolean }>) {\n e.stopPropagation()\n this._emitSidebarOpenChange(e.detail.open)\n }\n\n private _resizeGesture: DragGestureHandle | null = null\n private _resizeStartWidth = 0\n // 拖拽中的临时宽度;由 render 的 styleMap 统一写入,避免与 Lit 样式管理竞争。\n @state() private _resizeWidth: string | null = null\n\n private _parsePx(value: string, fallback: number): number {\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) ? parsed : fallback\n }\n\n private _resolveSidebarMinWidth(): number {\n return this.sidebarMinWidth\n ? this._parsePx(this.sidebarMinWidth, this._parsePx(this.collapsedWidth, 68))\n : this._parsePx(this.collapsedWidth, 68)\n }\n\n private _resolveSidebarMaxWidth(): number {\n // 组件内置硬上限:Sidebar 最多占视口一半(无需调用方设置)。\n // 调用方 sidebar-max-width 在该上限内生效,防止拖拽占据整个视口。\n const halfViewport = Math.floor(window.innerWidth / 2)\n const configured = this.sidebarMaxWidth ? this._parsePx(this.sidebarMaxWidth, halfViewport) : halfViewport\n const upper = Math.min(configured, halfViewport)\n return Math.max(upper, this._resolveSidebarMinWidth())\n }\n\n private _isResizing(): boolean {\n return this._resizeGesture?.isDragging() ?? false\n }\n\n private _handleResizePointerDown(e: PointerEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n // jsdom 等环境的 PointerEvent 可能缺失 isPrimary,仅在明确为 false(多点触控副指针)时拒绝。\n if (e.isPrimary === false) return\n\n const aside = this.renderRoot.querySelector('aside')\n if (!aside) return\n\n // 拖拽起点以 computed width 为准,并丢弃键盘未提交的调整(Enter 才提交、\n // Escape 撤回;抓取隐式放弃),保证零位移松手不会派发陈旧宽度。\n this._resizeStartWidth = this._parsePx(window.getComputedStyle(aside).width, this._parsePx(this.sidebarWidth, 240))\n this._resizeWidth = null\n aside.classList.add('is-resizing')\n\n this._resizeGesture = attachDragGesture(e, {\n axis: 'x',\n onMove: info => {\n // 向右拖增宽、向左拖收窄(handle 在右缘);钳制在 [min, max] 与视口内。\n const next = this._resizeStartWidth + info.deltaX\n const clamped = clamp(next, this._resolveSidebarMinWidth(), this._resolveSidebarMaxWidth())\n this._resizeWidth = `${Math.round(clamped)}px`\n },\n onEnd: () => {\n // 零位移松手(点击而非拖拽)不视为调宽动作:按 cancel 语义静默收尾。\n if (this._resizeWidth === null) {\n this._resetActiveResize()\n return\n }\n const width = this._resizeWidth\n this._resetActiveResize()\n // 受控契约:松手派发请求并交还 prop 管辖,由 Consumer 回写 sidebar-width。\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', {\n detail: { width },\n bubbles: true,\n composed: true\n })\n )\n },\n onCancel: () => {\n this._resetActiveResize()\n }\n })\n }\n\n // 终结进行中的拖拽:清手势状态、移除跟手 class,宽度过渡回 prop 管辖,不派发事件。\n // pointer cancel 与视口跨越移动端断点(handle 随桌面 layout 卸载)共用此收尾。\n private _resetActiveResize() {\n this._resizeGesture?.destroy()\n this._resizeGesture = null\n this.renderRoot.querySelector('aside')?.classList.remove('is-resizing')\n this._resizeWidth = null\n }\n\n // 键盘调宽(WAI-ARIA splitter 模式):方向键步进 16px(Shift 加速 64px)调整\n // 临时宽度,Enter 以受控请求派发 `sidebar-width-change`(与指针松手同语义),\n // Escape 撤回临时宽度交还 prop 管辖,Home/End 直接到 min/max。\n private _handleResizeKeydown(e: KeyboardEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n\n const min = this._resolveSidebarMinWidth()\n const max = this._resolveSidebarMaxWidth()\n const aside = this.renderRoot.querySelector('aside')\n const current = this._resizeWidth\n ? this._parsePx(this._resizeWidth, min)\n : this._parsePx(aside ? window.getComputedStyle(aside).width : this.sidebarWidth, min)\n const step = e.shiftKey ? 64 : 16\n let next: number | null = null\n\n switch (e.key) {\n case 'ArrowLeft':\n next = Math.max(min, current - step)\n break\n case 'ArrowRight':\n next = Math.min(max, current + step)\n break\n case 'Home':\n next = min\n break\n case 'End':\n next = max\n break\n case 'Enter':\n // 无未提交调整时不派发(焦点停留时的回车噪声)\n if (this._resizeWidth !== null) {\n const width = this._resizeWidth\n this._resizeWidth = null\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', { detail: { width }, bubbles: true, composed: true })\n )\n }\n e.preventDefault()\n return\n case 'Escape':\n this._resizeWidth = null\n e.preventDefault()\n return\n default:\n return\n }\n e.preventDefault()\n this._resizeWidth = `${Math.round(next)}px`\n }\n\n private _checkMobile() {\n const nextMobile = window.innerWidth <= 640\n // 视口跨越移动端断点会卸载桌面 layout(handle 随之消失);必须先终结进行中的\n // 拖拽,否则 _resizePointerId 悬挂,切回桌面后所有新的拖拽在入口被拦截。\n if (nextMobile !== this._isMobile && this._isResizing()) this._resetActiveResize()\n this._isMobile = nextMobile\n }\n\n private _resizeTimeout: ReturnType<typeof setTimeout> | null = null\n\n private _handleResize = () => {\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = setTimeout(() => {\n this._checkMobile()\n this._resizeTimeout = null\n }, 100)\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._checkMobile()\n window.addEventListener('resize', this._handleResize)\n void this.updateComplete.then(() => {\n if (this.isConnected) this._syncBannerPresence()\n })\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._resetActiveResize()\n window.removeEventListener('resize', this._handleResize)\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = null\n }\n\n override firstUpdated() {\n this._syncBannerPresence()\n }\n\n private _onBannerSlotChange() {\n this._syncBannerPresence()\n }\n\n private _syncBannerPresence() {\n const bannerSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"banner\"]')\n const hasBanner =\n bannerSlot\n ?.assignedNodes()\n .some(\n node =>\n node.nodeType === Node.ELEMENT_NODE || (node.nodeType === Node.TEXT_NODE && !!node.textContent?.trim())\n ) ?? false\n const banner = this.shadowRoot?.querySelector<HTMLElement>('.layout-banner') ?? null\n this._visibleBanner.setTarget(hasBanner ? banner : null)\n }\n\n override render() {\n const isSidebarOpen = !this.sidebarCollapsed\n // 拖拽中的临时宽度优先于 prop 宽度;移动端宽度由 Drawer 内部变量管理。\n const sidebarStyle = this._isMobile\n ? {}\n : { width: this._resizeWidth ?? (this.sidebarCollapsed ? this.collapsedWidth : this.sidebarWidth) }\n\n const toggleLabel = isSidebarOpen ? '折叠侧边栏' : '展开侧边栏'\n\n const desktopToggle = html`\n <web-ui-button\n class=\"sidebar-toggle\"\n icon\n variant=\"secondary\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"${toggleLabel}\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n `\n\n const sidebarViewport = html`\n <div class=\"sidebar-viewport\">\n <slot name=\"sidebar\"></slot>\n </div>\n `\n\n const desktopLayout = html`\n <div class=\"layout-body\">\n <div class=\"sidebar-wrapper\">\n <aside\n class=\"${classMap({\n collapsed: !isSidebarOpen\n })}\"\n style=\"${styleMap(sidebarStyle)}\"\n >\n <div class=\"aside-panel wui-glass\">\n ${sidebarViewport}\n <div class=\"sidebar-toggle-area\">${desktopToggle}</div>\n </div>\n ${\n this.sidebarResizable && !this.sidebarCollapsed\n ? html`\n <div\n class=\"sidebar-resize-handle\"\n role=\"separator\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n aria-label=\"调整侧边栏宽度\"\n @pointerdown=${this._handleResizePointerDown}\n @keydown=${this._handleResizeKeydown}\n ></div>\n `\n : nothing\n }\n </aside>\n </div>\n <div class=\"layout-content\">\n <header>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n </div>\n `\n\n const mobileLayout = html`\n <div class=\"layout-content\">\n <header>\n <web-ui-button\n class=\"mobile-toggle\"\n icon\n variant=\"glass\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"打开导航菜单\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n\n <web-ui-drawer\n placement=\"left\"\n ?open=\"${this.sidebarOpen}\"\n controlled\n draggable\n dialog-label=\"主导航\"\n @open-change=\"${this._onDrawerChange}\"\n style=\"${styleMap({\n '--wui-drawer-width': this.sidebarWidth,\n '--wui-drawer-radius': 'var(--wui-layout-sidebar-radius, 24px)'\n })}\"\n >\n ${sidebarViewport}\n </web-ui-drawer>\n `\n\n return html`\n <div class=\"layout-page\">\n <div class=\"layout-banner\">\n <slot name=\"banner\" @slotchange=\"${this._onBannerSlotChange}\"></slot>\n </div>\n ${this._isMobile ? mobileLayout : desktopLayout}\n </div>\n `\n }\n\n declare readonly $events: {\n 'sidebar-collapsed-change': CustomEvent<{ collapsed: boolean }>\n 'sidebar-open-change': CustomEvent<{ open: boolean }>\n 'sidebar-width-change': CustomEvent<{ width: string }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-layout': WebUiLayout\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BO,IAAM,IAAN,cAA0B,EAAW;;EAwOZ,aA9NX,KAAA,mBAAA,IAGJ,KAAA,eAAA,SAGE,KAAA,iBAAA,QAIE,KAAA,mBAAA,IAOD,KAAA,kBAAA,IAIA,KAAA,kBAAA,IASJ,KAAA,cAAA,IAGD,KAAA,aAAA,IAEgB,KAAA,YAAA,IAEK,KAAA,iBAAA,EAAyB,EACzD,sBAAqB,MAAQ;GAC3B,KAAK,MAAM,YAAY,sCAAsC,GAAG,EAAK,OAAO,GAAG;EACjF,EACF,CAAC,CAAC,CAAC,KAAK,GAEoC,KAAA,2BAAA,IAAI,EAAsB,MAAM,KAAK,cAAc,GAoC5C,KAAA,iBAAA,MACvB,KAAA,oBAAA,GAEmB,KAAA,eAAA,MA0IgB,KAAA,iBAAA,MAEjC,KAAA,sBAAA;GAE5B,AADI,KAAK,mBAAmB,QAAM,aAAa,KAAK,cAAc,GAClE,KAAK,iBAAiB,iBAAiB;IAErC,AADA,KAAK,aAAa,GAClB,KAAK,iBAAiB;GACxB,GAAG,GAAG;EACR;;;EA7OyB,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAsD5D,iBAAyB;EACvB,IAAI,KAAK,WAAW;GAClB,KAAK,uBAAuB,CAAC,KAAK,WAAW;GAC7C;EACF;EAEA,KAAK,4BAA4B,CAAC,KAAK,gBAAgB;CACzD;CAEA,4BAAoC,GAAoB;EACtD,KAAK,cACH,IAAI,YAAY,4BAA4B;GAC1C,QAAQ,EAAE,aAAU;GACpB,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAEA,uBAA+B,GAAe;EAC5C,KAAK,cACH,IAAI,YAAY,uBAAuB;GACrC,QAAQ,EAAE,QAAK;GACf,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAEA,gBAAwB,GAAmC;EAEzD,AADA,EAAE,gBAAgB,GAClB,KAAK,uBAAuB,EAAE,OAAO,IAAI;CAC3C;CAOA,SAAiB,GAAe,GAA0B;EACxD,IAAM,IAAS,OAAO,WAAW,CAAK;EACtC,OAAO,OAAO,SAAS,CAAM,IAAI,IAAS;CAC5C;CAEA,0BAA0C;EACxC,OAAO,KAAK,kBACR,KAAK,SAAS,KAAK,iBAAiB,KAAK,SAAS,KAAK,gBAAgB,EAAE,CAAC,IAC1E,KAAK,SAAS,KAAK,gBAAgB,EAAE;CAC3C;CAEA,0BAA0C;EAGxC,IAAM,IAAe,KAAK,MAAM,OAAO,aAAa,CAAC,GAC/C,IAAa,KAAK,kBAAkB,KAAK,SAAS,KAAK,iBAAiB,CAAY,IAAI;EAE9F,OAAO,KAAK,IADE,KAAK,IAAI,GAAY,CACnB,GAAO,KAAK,wBAAwB,CAAC;CACvD;CAEA,cAA+B;EAC7B,OAAO,KAAK,gBAAgB,WAAW,KAAK;CAC9C;CAEA,yBAAiC,GAAiB;EAGhD,IAFI,CAAC,KAAK,oBAAoB,KAAK,oBAAoB,KAAK,aAAa,KAAK,YAAY,KAEtF,EAAE,cAAc,IAAO;EAE3B,IAAM,IAAQ,KAAK,WAAW,cAAc,OAAO;EAC9C,MAIL,KAAK,oBAAoB,KAAK,SAAS,OAAO,iBAAiB,CAAK,CAAC,CAAC,OAAO,KAAK,SAAS,KAAK,cAAc,GAAG,CAAC,GAClH,KAAK,eAAe,MACpB,EAAM,UAAU,IAAI,aAAa,GAEjC,KAAK,iBAAiB,EAAkB,GAAG;GACzC,MAAM;GACN,SAAQ,MAAQ;IAEd,IAAM,IAAO,KAAK,oBAAoB,EAAK,QACrC,IAAU,EAAM,GAAM,KAAK,wBAAwB,GAAG,KAAK,wBAAwB,CAAC;IAC1F,KAAK,eAAe,GAAG,KAAK,MAAM,CAAO,EAAE;GAC7C;GACA,aAAa;IAEX,IAAI,KAAK,iBAAiB,MAAM;KAC9B,KAAK,mBAAmB;KACxB;IACF;IACA,IAAM,IAAQ,KAAK;IAGnB,AAFA,KAAK,mBAAmB,GAExB,KAAK,cACH,IAAI,YAAY,wBAAwB;KACtC,QAAQ,EAAE,SAAM;KAChB,SAAS;KACT,UAAU;IACZ,CAAC,CACH;GACF;GACA,gBAAgB;IACd,KAAK,mBAAmB;GAC1B;EACF,CAAC;CACH;CAIA,qBAA6B;EAI3B,AAHA,KAAK,gBAAgB,QAAQ,GAC7B,KAAK,iBAAiB,MACtB,KAAK,WAAW,cAAc,OAAO,CAAC,EAAE,UAAU,OAAO,aAAa,GACtE,KAAK,eAAe;CACtB;CAKA,qBAA6B,GAAkB;EAC7C,IAAI,CAAC,KAAK,oBAAoB,KAAK,oBAAoB,KAAK,aAAa,KAAK,YAAY,GAAG;EAE7F,IAAM,IAAM,KAAK,wBAAwB,GACnC,IAAM,KAAK,wBAAwB,GACnC,IAAQ,KAAK,WAAW,cAAc,OAAO,GAC7C,IAAU,KAAK,eACjB,KAAK,SAAS,KAAK,cAAc,CAAG,IACpC,KAAK,SAAS,IAAQ,OAAO,iBAAiB,CAAK,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAG,GACjF,IAAO,EAAE,WAAW,KAAK,IAC3B,IAAsB;EAE1B,QAAQ,EAAE,KAAV;GACE,KAAK;IACH,IAAO,KAAK,IAAI,GAAK,IAAU,CAAI;IACnC;GACF,KAAK;IACH,IAAO,KAAK,IAAI,GAAK,IAAU,CAAI;IACnC;GACF,KAAK;IACH,IAAO;IACP;GACF,KAAK;IACH,IAAO;IACP;GACF,KAAK;IAEH,IAAI,KAAK,iBAAiB,MAAM;KAC9B,IAAM,IAAQ,KAAK;KAEnB,AADA,KAAK,eAAe,MACpB,KAAK,cACH,IAAI,YAAY,wBAAwB;MAAE,QAAQ,EAAE,SAAM;MAAG,SAAS;MAAM,UAAU;KAAK,CAAC,CAC9F;IACF;IACA,EAAE,eAAe;IACjB;GACF,KAAK;IAEH,AADA,KAAK,eAAe,MACpB,EAAE,eAAe;IACjB;GACF,SACE;EACJ;EAEA,AADA,EAAE,eAAe,GACjB,KAAK,eAAe,GAAG,KAAK,MAAM,CAAI,EAAE;CAC1C;CAEA,eAAuB;EACrB,IAAM,IAAa,OAAO,cAAc;EAIxC,AADI,MAAe,KAAK,aAAa,KAAK,YAAY,KAAG,KAAK,mBAAmB,GACjF,KAAK,YAAY;CACnB;CAYA,oBAA6B;EAI3B,AAHA,MAAM,kBAAkB,GACxB,KAAK,aAAa,GAClB,OAAO,iBAAiB,UAAU,KAAK,aAAa,GACpD,KAAU,eAAe,WAAW;GAClC,AAAI,KAAK,eAAa,KAAK,oBAAoB;EACjD,CAAC;CACH;CAEA,uBAAgC;EAK9B,AAJA,MAAM,qBAAqB,GAC3B,KAAK,mBAAmB,GACxB,OAAO,oBAAoB,UAAU,KAAK,aAAa,GACnD,KAAK,mBAAmB,QAAM,aAAa,KAAK,cAAc,GAClE,KAAK,iBAAiB;CACxB;CAEA,eAAwB;EACtB,KAAK,oBAAoB;CAC3B;CAEA,sBAA8B;EAC5B,KAAK,oBAAoB;CAC3B;CAEA,sBAA8B;EAE5B,IAAM,IADa,KAAK,WAAW,cAA+B,uBAEhE,CAAA,EACI,cAAc,CAAC,CAChB,MACC,MACE,EAAK,aAAa,KAAK,gBAAiB,EAAK,aAAa,KAAK,aAAa,CAAC,CAAC,EAAK,aAAa,KAAK,CACzG,KAAK,IACH,IAAS,KAAK,YAAY,cAA2B,gBAAgB,KAAK;EAChF,KAAK,eAAe,UAAU,IAAY,IAAS,IAAI;CACzD;CAEA,SAAkB;EAChB,IAAM,IAAgB,CAAC,KAAK,kBAEtB,IAAe,KAAK,YACtB,CAAC,IACD,EAAE,OAAO,KAAK,iBAAiB,KAAK,mBAAmB,KAAK,iBAAiB,KAAK,cAAc,GAE9F,IAAc,IAAgB,UAAU,SAExC,IAAgB,CAAI;;;;;kBAKZ,KAAK,eAAe;sBAChB,EAAY;;6BAEL,EAA6B;;OAIhD,IAAkB,CAAI;;;;OAMtB,IAAgB,CAAI;;;;qBAIT,EAAS,EAChB,WAAW,CAAC,EACd,CAAC,EAAE;qBACM,EAAS,CAAY,EAAE;;;gBAG5B,EAAgB;iDACiB,EAAc;;cAGjD,KAAK,oBAAoB,CAAC,KAAK,mBAC3B,CAAI;;;;;;;qCAOe,KAAK,yBAAyB;iCAClC,KAAK,qBAAqB;;sBAGzC,EACL;;;;;;;;;;;OAaH,IAAe,CAAI;;;;;;;sBAOP,KAAK,eAAe;;;iCAGT,EAA6B;;;;;;;;;;iBAU7C,KAAK,YAAY;;;;wBAIV,KAAK,gBAAgB;iBAC5B,EAAS;GAChB,sBAAsB,KAAK;GAC3B,uBAAuB;EACzB,CAAC,EAAE;;UAED,EAAgB;;;EAItB,OAAO,CAAI;;;6CAG8B,KAAK,oBAAoB;;UAE5D,KAAK,YAAY,IAAe,EAAc;;;CAGtD;AAOF;AAjYG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,WAAW;CAAqB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,oBAAA,KAAA,CAAA,GAGzE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;CAAiB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GAGpE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;CAAmB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,kBAAA,KAAA,CAAA,GAItE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,WAAW;CAAqB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,oBAAA,KAAA,CAAA,GAOzE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;CAAqB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GAIxE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;CAAqB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GASxE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,WAAW;CAAgB,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GAGpE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,WAAW;CAAe,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GAGnE,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GA+CN,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GA7FR,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/layout/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{--wui-layout-visible-banner-height:0px;--wui-layout-header-glow-color:var(--wui-color-page,#fff);display:block}.layout-page{flex-direction:column;min-height:100dvh;display:flex}.layout-banner{z-index:var(--wui-layer-banner,30);position:relative}.layout-body{flex:1;display:flex}.sidebar-wrapper{align-self:stretch;position:relative}.sidebar-viewport{flex:1;min-height:0}aside{z-index:var(--wui-layer-sidebar,50);max-width:50vw;height:calc(100vh - var(--wui-layout-visible-banner-height));height:calc(100dvh - var(--wui-layout-visible-banner-height));max-height:calc(100vh - var(--wui-layout-visible-banner-height));max-height:calc(100dvh - var(--wui-layout-visible-banner-height));transition:width var(--wui-duration-layout,.2s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));flex-direction:column;flex-shrink:0;padding:8px 0 8px 8px;display:flex;position:sticky;top:0}aside .aside-panel{--wui-glass-corner-radius:var(--wui-layout-sidebar-radius,24px);border-radius:var(--wui-layout-sidebar-radius,24px);background-color:var(--wui-color-surface-sidebar,#e9e9e9d1);flex-direction:column;flex:1;min-height:0;display:flex}aside .sidebar-toggle-area{flex-shrink:0;align-items:center;display:flex}aside .sidebar-toggle{--wui-button-width:44px;margin:8px}aside.collapsed .sidebar-viewport{overflow:hidden}.sidebar-resize-handle{touch-action:none;cursor:col-resize;z-index:1;width:12px;position:absolute;top:0;bottom:0;right:-6px}.sidebar-resize-handle:before{content:\"\";border-radius:var(--wui-radius-control,calc(infinity * 1px));opacity:0;background:var(--wui-color-accent,#08f);width:3px;transition:opacity var(--wui-duration-feedback,.1s) ease;position:absolute;top:0;bottom:0;left:50%;translate:-50%}.sidebar-resize-handle:hover:before,.sidebar-resize-handle:focus-visible:before,aside.is-resizing .sidebar-resize-handle:before{opacity:1}aside.is-resizing{transition:none}.layout-content{flex-direction:column;flex:1;min-width:0;display:flex}header{isolation:isolate;z-index:var(--wui-layer-header,10);align-items:center;gap:8px;display:flex;position:sticky;top:0;overflow-x:clip}.mobile-toggle{margin-left:var(--wui-layout-mobile-toggle-inset,8px)}:host([header-glow]) header:before{pointer-events:none;content:\"\";z-index:-1;opacity:.95;background-color:var(--wui-layout-header-glow-color);filter:blur(10px);position:absolute;inset:0;transform:translateY(-50%)scale(1.05,2)}main{flex:1}footer{z-index:var(--wui-layer-tabbar,40);position:sticky;bottom:0}@media (width<=640px){aside,.sidebar-wrapper{display:none}header{align-items:flex-start}.mobile-toggle{align-self:flex-start;margin-top:8px}}@media (prefers-reduced-motion:reduce){aside,.sidebar-resize-handle:before{transition:none}}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{--wui-layout-visible-banner-height:0px;display:block}.layout-page{flex-direction:column;min-height:100dvh;display:flex}.layout-banner{z-index:var(--wui-layer-banner,30);position:relative}.layout-body{flex:1;display:flex}.sidebar-wrapper{align-self:stretch;position:relative}.sidebar-viewport{flex:1;min-height:0}aside{z-index:var(--wui-layer-sidebar,50);max-width:50vw;height:calc(100vh - var(--wui-layout-visible-banner-height));height:calc(100dvh - var(--wui-layout-visible-banner-height));max-height:calc(100vh - var(--wui-layout-visible-banner-height));max-height:calc(100dvh - var(--wui-layout-visible-banner-height));padding:var(--wui-space-2,8px) 0 var(--wui-space-2,8px) var(--wui-space-2,8px);transition:width var(--wui-duration-layout,.2s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));flex-direction:column;flex-shrink:0;display:flex;position:sticky;top:0}aside .aside-panel{--wui-glass-corner-radius:var(--wui-layout-sidebar-radius,24px);border-radius:var(--wui-layout-sidebar-radius,24px);background-color:var(--wui-color-surface-sidebar,#e9e9e9d1);flex-direction:column;flex:1;min-height:0;display:flex}aside .sidebar-toggle-area{flex-shrink:0;align-items:center;display:flex}aside .sidebar-toggle{--wui-button-width:var(--wui-layout-sidebar-toggle-width,44px);margin:var(--wui-space-2,8px)}aside.collapsed .sidebar-viewport{overflow:hidden}.sidebar-resize-handle{touch-action:none;cursor:col-resize;z-index:1;width:12px;position:absolute;top:0;bottom:0;right:-6px}.sidebar-resize-handle:before{content:\"\";border-radius:var(--wui-radius-control,calc(infinity * 1px));opacity:0;background:var(--wui-color-accent,#08f);width:3px;transition:opacity var(--wui-duration-feedback,.1s) ease;position:absolute;top:0;bottom:0;left:50%;translate:-50%}.sidebar-resize-handle:hover:before,.sidebar-resize-handle:focus-visible:before,aside.is-resizing .sidebar-resize-handle:before{opacity:1}.sidebar-resize-handle:focus-visible{border-radius:var(--wui-radius-control,calc(infinity * 1px));outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent));outline-offset:2px}aside.is-resizing{transition:none}.layout-content{flex-direction:column;flex:1;min-width:0;display:flex;overflow-x:clip}header{isolation:isolate;z-index:var(--wui-layer-header,10);gap:var(--wui-space-2,8px);align-items:center;display:flex;position:sticky;top:0}.mobile-toggle{margin-left:var(--wui-layout-mobile-toggle-inset,8px)}:host([header-glow]) header:before{pointer-events:none;content:\"\";z-index:-1;background:linear-gradient(to bottom, var(--wui-color-page,#fff), transparent);margin:-10px;position:absolute;inset:0}:host([header-glow]) header:after{pointer-events:none;content:\"\";z-index:-1;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);margin:-30px;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#000 0% 60%,#0000 100%);mask-image:linear-gradient(#000 0% 60%,#0000 100%);-webkit-mask-size:100% 100%;mask-size:100% 100%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}main{flex:1}footer{z-index:var(--wui-layer-tabbar,40);position:sticky;bottom:0}@media (width<=640px){aside,.sidebar-wrapper{display:none}header{align-items:flex-start}.mobile-toggle{margin-top:var(--wui-space-2,8px);align-self:flex-start}}@media (prefers-reduced-motion:reduce){aside,.sidebar-resize-handle:before{transition:none}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/layout/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-layout-visible-banner-height: 0px;\n --wui-layout-header-glow-color: var(--wui-color-page, #fff);\n\n display: block;\n}\n\n/* 页面级滚动容器。Banner 位于正文前,随页面一起滚动。 */\n.layout-page {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n min-height: 100dvh;\n}\n\n.layout-banner {\n position: relative;\n z-index: var(--wui-layer-banner, 30);\n}\n\n/* 参考 book-fe:正文区域负责撑高 sidebar 的 relative wrapper。 */\n.layout-body {\n display: flex;\n flex: 1;\n}\n\n.sidebar-wrapper {\n position: relative;\n align-self: stretch;\n}\n\n/* Layout 只提供可用高度;桌面端由 Consumer 决定 scrollport,移动端由 Drawer content 提供。 */\n.sidebar-viewport {\n flex: 1;\n min-height: 0;\n}\n\n/*\n * Banner 可见时,组件用它的当前可见高度缩短 aside;Banner 滚出后该值归零。\n * 因而圆角卡片始终完整可见,同时 sticky Sidebar 可在 Banner 消失后填满视口。\n */\naside {\n position: sticky;\n z-index: var(--wui-layer-sidebar, 50);\n top: 0;\n\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n\n max-width: 50vw;\n height: calc(100vh - var(--wui-layout-visible-banner-height));\n height: calc(100dvh - var(--wui-layout-visible-banner-height));\n max-height: calc(100vh - var(--wui-layout-visible-banner-height));\n max-height: calc(100dvh - var(--wui-layout-visible-banner-height));\n padding: 8px 0 8px 8px;\n\n transition: width var(--wui-duration-layout, 200ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n .aside-panel {\n --wui-glass-corner-radius: var(--wui-layout-sidebar-radius, 24px);\n\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-height: 0;\n border-radius: var(--wui-layout-sidebar-radius, 24px);\n\n /* 深色下比 page 浅一档的专用表面 token。不直接复用 --wui-color-surface-overlay:\n 该 token 同时服务 dialog/drawer/toast,整体抬升会带偏不在本次范围内的表面。\n 浅色保持中性分层,无 theme 时回退到同一字面量。 */\n background-color: var(--wui-color-surface-sidebar, rgb(233 233 233 / 0.82));\n }\n\n .sidebar-toggle-area {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n }\n\n .sidebar-toggle {\n --wui-button-width: 44px;\n margin: 8px;\n }\n\n &.collapsed {\n .sidebar-viewport {\n overflow: hidden;\n }\n }\n}\n\n/*\n * 命中条贴 aside 右缘(约 12px 宽),hover 或拖拽中显示 3px accent 竖线。\n * aside 有 8px padding,handle 定位在 padding 区外缘,不遮挡 aside-panel 内容。\n */\n.sidebar-resize-handle {\n touch-action: none;\n cursor: col-resize;\n\n position: absolute;\n z-index: 1;\n top: 0;\n right: -6px;\n bottom: 0;\n\n width: 12px;\n}\n\n.sidebar-resize-handle::before {\n content: '';\n\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n translate: -50%;\n\n width: 3px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n opacity: 0;\n background: var(--wui-color-accent, #08f);\n\n transition: opacity var(--wui-duration-feedback, 100ms) ease;\n}\n\n.sidebar-resize-handle:hover::before,\n.sidebar-resize-handle:focus-visible::before,\naside.is-resizing .sidebar-resize-handle::before {\n opacity: 1;\n}\n\n/* 拖拽中禁用宽度过渡,保证实时跟手。 */\naside.is-resizing {\n transition: none;\n}\n\n.layout-content {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n}\n\nheader {\n /* 将负层级 glow 限定在 Header 的局部 stacking context,slot 内容自然位于其上。 */\n isolation: isolate;\n position: sticky;\n z-index: var(--wui-layer-header, 10);\n top: 0;\n\n /*\n * glow 伪元素用 scale + translate 向外扩展,会溢出 header 盒子并撑出页面横向滚动条\n * (移动端约 30px)。这里只裁横向:纵向保持 visible,下拉浮层等槽位内容仍可溢出。\n * clip 不创建滚动容器,因此不影响 header 自身的 sticky。\n */\n overflow-x: clip;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* 移动端 Toggle 属于组件自身,不随 Consumer 的 header 内边距缩进;\n 默认 8px 使其脱离视口边缘,Consumer 可用同名变量对齐自身内容左缘。 */\n.mobile-toggle {\n margin-left: var(--wui-layout-mobile-toggle-inset, 8px);\n}\n\n/*\n * Header 的装饰性背景晕染\n * ========================\n *\n * 伪元素随 header 的实际盒子尺寸和 sticky 位置变化,自然适配 header slot 的\n * 高度与位置,无需单独维护一层 DOM。\n */\n:host([header-glow]) header::before {\n pointer-events: none;\n content: '';\n\n position: absolute;\n z-index: -1;\n inset: 0;\n transform: translateY(-50%) scale(1.05, 2);\n\n opacity: 0.95;\n background-color: var(--wui-layout-header-glow-color);\n filter: blur(10px);\n}\n\nmain {\n flex: 1;\n}\n\nfooter {\n position: sticky;\n z-index: var(--wui-layer-tabbar, 40);\n bottom: 0;\n}\n\n@media (width <= 640px) {\n aside,\n .sidebar-wrapper {\n display: none;\n }\n\n /* Slot 可能包含展开后的多行 header;Toggle 对齐首行,而不是被整段 header 高度居中。 */\n header {\n align-items: flex-start;\n }\n\n .mobile-toggle {\n align-self: flex-start;\n margin-top: 8px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n aside {\n transition: none;\n }\n\n .sidebar-resize-handle::before {\n transition: none;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/layout/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-layout-visible-banner-height: 0px;\n\n display: block;\n}\n\n/* 页面级滚动容器。Banner 位于正文前,随页面一起滚动。 */\n.layout-page {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n min-height: 100dvh;\n}\n\n.layout-banner {\n position: relative;\n z-index: var(--wui-layer-banner, 30);\n}\n\n/* 参考 book-fe:正文区域负责撑高 sidebar 的 relative wrapper。 */\n.layout-body {\n display: flex;\n flex: 1;\n}\n\n.sidebar-wrapper {\n position: relative;\n align-self: stretch;\n}\n\n/* Layout 只提供可用高度;桌面端由 Consumer 决定 scrollport,移动端由 Drawer content 提供。 */\n.sidebar-viewport {\n flex: 1;\n min-height: 0;\n}\n\n/*\n * Banner 可见时,组件用它的当前可见高度缩短 aside;Banner 滚出后该值归零。\n * 因而圆角卡片始终完整可见,同时 sticky Sidebar 可在 Banner 消失后填满视口。\n */\naside {\n position: sticky;\n z-index: var(--wui-layer-sidebar, 50);\n top: 0;\n\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n\n max-width: 50vw;\n height: calc(100vh - var(--wui-layout-visible-banner-height));\n height: calc(100dvh - var(--wui-layout-visible-banner-height));\n max-height: calc(100vh - var(--wui-layout-visible-banner-height));\n max-height: calc(100dvh - var(--wui-layout-visible-banner-height));\n padding: var(--wui-space-2, 8px) 0 var(--wui-space-2, 8px) var(--wui-space-2, 8px);\n\n transition: width var(--wui-duration-layout, 200ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n .aside-panel {\n --wui-glass-corner-radius: var(--wui-layout-sidebar-radius, 24px);\n\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-height: 0;\n border-radius: var(--wui-layout-sidebar-radius, 24px);\n\n /* 深色下比 page 浅一档的专用表面 token。不直接复用 --wui-color-surface-overlay:\n 该 token 同时服务 dialog/drawer/toast,整体抬升会带偏不在本次范围内的表面。\n 浅色保持中性分层,无 theme 时回退到同一字面量。 */\n background-color: var(--wui-color-surface-sidebar, rgb(233 233 233 / 0.82));\n }\n\n .sidebar-toggle-area {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n }\n\n .sidebar-toggle {\n /*\n * 走可覆盖的 var:`.sidebar-toggle` 自身声明的 `--wui-button-width` 优先于从\n * 祖先继承的同名变量,app 侧无法直接改写它。要让折叠态的 toggle 跟着折叠宽度\n * 一起变,只能由这里显式接一个出口。取值由 app 决定,本组件不假设折叠宽度。\n * 默认值与历史硬编码一致,不设置时行为不变。\n */\n --wui-button-width: var(--wui-layout-sidebar-toggle-width, 44px);\n\n margin: var(--wui-space-2, 8px);\n }\n\n &.collapsed {\n .sidebar-viewport {\n overflow: hidden;\n }\n }\n}\n\n/*\n * 命中条贴 aside 右缘(约 12px 宽),hover 或拖拽中显示 3px accent 竖线。\n * aside 有 8px padding,handle 定位在 padding 区外缘,不遮挡 aside-panel 内容。\n */\n.sidebar-resize-handle {\n touch-action: none;\n cursor: col-resize;\n\n position: absolute;\n z-index: 1;\n top: 0;\n right: -6px;\n bottom: 0;\n\n width: 12px;\n}\n\n.sidebar-resize-handle::before {\n content: '';\n\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n translate: -50%;\n\n width: 3px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n opacity: 0;\n background: var(--wui-color-accent, #08f);\n\n transition: opacity var(--wui-duration-feedback, 100ms) ease;\n}\n\n.sidebar-resize-handle:hover::before,\n.sidebar-resize-handle:focus-visible::before,\naside.is-resizing .sidebar-resize-handle::before {\n opacity: 1;\n}\n\n/*\n * 键盘 focus 同时给出两样东西:竖条与 hover / 拖拽同形,ring 与其余组件同一套浅蓝\n * 样式。竖条说明「命中条在哪」,ring 说明「键盘落点在哪」——handle 宽 12px 且通高,\n * 命中区远大于 3px 竖条本身,只靠竖条不足以说明焦点位置。\n *\n * ring 沿用 --wui-focus-ring-width / --wui-color-focus-ring 两个 token。圆角取\n * control token 后 outline 呈细长胶囊,与 button 的胶囊 ring 同一形状语言;offset\n * 2px 让 ring 骑在 aside 右缘内外两侧,不被 aside 裁掉。\n */\n.sidebar-resize-handle:focus-visible {\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n outline-offset: 2px;\n}\n\n/* 拖拽中禁用宽度过渡,保证实时跟手。 */\naside.is-resizing {\n transition: none;\n}\n\n.layout-content {\n /*\n * glow 的两层伪元素用负 margin 向外扩展(见 header::before / ::after),会溢出内容列\n * 并撑出页面横向滚动条(移动端约 30px),横向裁剪因此归属本层。它有 min-width: 0,\n * 是容纳横向溢出的位置。\n * clip 不创建滚动容器,因此不影响 header / footer 自身的 sticky;也不用 hidden——\n * 那会把本层变成滚动容器,sticky 随即失效。\n *\n * 这一层不负责纵向羽化,也切不到它:glow 的下缘断层来自 header 自身的裁剪上下文\n * (见 header 的注释),真 Safari 上把本层改成 overflow-x: visible / unset\n * 与保持 clip 的截图逐像素相同。\n */\n overflow-x: clip;\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-width: 0;\n}\n\nheader {\n /*\n * isolation: isolate 既把负层级 glow 限定在本 Header 的局部 stacking context\n * (slot 内容自然位于其上),也顺带使本层成为该上下文的裁剪边界:z-index: -1 的\n * glow 伪元素溢出 header 盒的部分会被切掉。横向裁剪上移到 .layout-content。\n *\n * 「纵向必须 visible 才留得住下拉浮层的溢出空间」仍然成立——overflow-* 一旦生效\n * 就会裁剪该轴,visible 是这些槽位内容唯一的溢出出口。\n */\n isolation: isolate;\n position: sticky;\n z-index: var(--wui-layer-header, 10);\n top: 0;\n\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n}\n\n/* 移动端 Toggle 属于组件自身,不随 Consumer 的 header 内边距缩进;\n 默认 8px 使其脱离视口边缘,Consumer 可用同名变量对齐自身内容左缘。 */\n.mobile-toggle {\n margin-left: var(--wui-layout-mobile-toggle-inset, 8px);\n}\n\n/*\n * Header 的装饰性背景晕染\n * ========================\n *\n * 两层伪元素随 header 的实际盒子尺寸和 sticky 位置变化,自然适配 header slot 的\n * 高度与位置,无需单独维护一层 DOM。::before 是晕染色本身,::after 在更外一圈叠一层\n * 真实模糊(backdrop-filter)。职责分开后,模糊强度与晕染浓度互不牵制。\n *\n * 两层都用负 margin 向外撑开,而不是 transform: scale。渐变完全画在盒内,底缘在\n * 触及 header 盒之前就归零,盒外那一段不带可见不透明度。\n *\n * ::after 的 backdrop-filter 按规范会把模糊延伸到盒外,而 `isolation: isolate` 让\n * header 成为 z-index: -1 伪元素的裁剪边界,WebKit 在这条边界上会切掉盒外那段\n * (真 Safari 实测 11 级台阶)。mask 把模糊沿高度收到 0,但**残余不为 0**:它的盒\n * 比 header 高 60px(两侧各 -30px),mask 在盒高 60% 之前保持不透明、之后线性归零,\n * header 底缘正落在衰减段上——header 高 52px 时该处 alpha 约 0.67,100px 时约 0.47。\n * #184 是否因此在真 Safari 上复现,取决于这段残余被切出来是否可读;Chrome 不复现\n * (盒外那段根本没被裁,本地量不到),判据仍需真 Safari 逐像素取证;当时的取证报告\n * 曾见于一份临时取证报告 ui-polish-260929-glow-clip-ownership.md(临时目录可丢失,\n * 取证结论以上述量值为准)。\n *\n * 端点用裸 `transparent`(即 rgb(0 0 0 / 0))而不是\n * `color-mix(in srgb, var(--wui-color-page) 100%, transparent)`:混色按预乘 alpha\n * 进行,后者算出来是完全不透明的原色(alpha = 1×1 + 0×0 = 1),终点没有羽化,实测\n * 台阶反而从 11 级恶化到 152 级。裸 transparent 在渐变插值中同样按预乘处理,各引擎\n * 一致淡到 0,且不引入新色相。\n */\n:host([header-glow]) header::before {\n pointer-events: none;\n content: '';\n\n position: absolute;\n z-index: -1;\n inset: 0;\n\n margin: -10px;\n\n background: linear-gradient(to bottom, var(--wui-color-page, #fff), transparent);\n}\n\n:host([header-glow]) header::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n z-index: -1;\n inset: 0;\n\n margin: -30px;\n\n backdrop-filter: blur(4px);\n\n mask-image: linear-gradient(to bottom, black 0%, black 60%, transparent 100%);\n mask-repeat: no-repeat;\n mask-size: 100% 100%;\n}\n\nmain {\n flex: 1;\n}\n\nfooter {\n position: sticky;\n z-index: var(--wui-layer-tabbar, 40);\n bottom: 0;\n}\n\n@media (width <= 640px) {\n aside,\n .sidebar-wrapper {\n display: none;\n }\n\n /* Slot 可能包含展开后的多行 header;Toggle 对齐首行,而不是被整段 header 高度居中。 */\n header {\n align-items: flex-start;\n }\n\n .mobile-toggle {\n align-self: flex-start;\n margin-top: var(--wui-space-2, 8px);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n aside {\n transition: none;\n }\n\n .sidebar-resize-handle::before {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/option/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.option-label{cursor:default;-webkit-user-select:none;user-select:none;box-sizing:border-box;border-radius:var(--wui-radius-control,calc(infinity * 1px));height:32px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:8px;padding:0 8px;display:flex;overflow:hidden}.check{display:var(--wui-option-check-display,block);flex-shrink:0}.content-wrap{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([selected])) .check{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0}.option-label:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}:host([active]) .option-label{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}@media (hover:hover) and (pointer:fine){:host(:not([active])) .option-label:hover{background:var(--wui-color-border,#0000001a)}}:host([disabled]) .option-label{cursor:not-allowed}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.option-label{cursor:default;-webkit-user-select:none;user-select:none;gap:var(--wui-space-2,8px);box-sizing:border-box;height:32px;padding:0 var(--wui-space-2,8px);border-radius:var(--wui-radius-control,calc(infinity * 1px));font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;align-items:center;display:flex;overflow:hidden}.check{display:var(--wui-option-check-display,block);flex-shrink:0}.content-wrap{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([selected])) .check{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0}.option-label:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent));outline-offset:2px}:host([active]) .option-label{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}@media (hover:hover) and (pointer:fine){:host(:not([active])) .option-label:hover{background:var(--wui-color-border,#0000001a)}}:host([disabled]) .option-label{cursor:not-allowed}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/option/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.option-label {\n cursor: default;\n user-select: none;\n\n overflow: hidden;\n display: flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n height: 32px;\n padding: 0 8px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.check {\n display: var(--wui-option-check-display, block);\n flex-shrink: 0;\n}\n\n.content-wrap {\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([selected])) .check {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n flex-shrink: 0;\n}\n\n.option-label:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n}\n\n:host([active]) .option-label {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not([active])) .option-label:hover {\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n }\n}\n\n:host([disabled]) .option-label {\n cursor: not-allowed;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/option/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.option-label {\n cursor: default;\n user-select: none;\n\n overflow: hidden;\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n box-sizing: border-box;\n height: 32px;\n padding: 0 var(--wui-space-2, 8px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.check {\n display: var(--wui-option-check-display, block);\n flex-shrink: 0;\n}\n\n.content-wrap {\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([selected])) .check {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n flex-shrink: 0;\n}\n\n.option-label:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n outline-offset: 2px;\n}\n\n:host([active]) .option-label {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not([active])) .option-label:hover {\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n }\n}\n\n:host([disabled]) .option-label {\n cursor: not-allowed;\n}\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/popover/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_TRIGGERS = ['click', 'hover', 'manual'] as const\n\nlet popoverIdCounter = 0\n\n@customElement('web-ui-popover')\nexport class WebUiPopover extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'bottom')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'bottom'\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 8)\n this.requestUpdate('offset', old)\n }\n private _offset = 8\n\n @property({ type: String, reflect: true })\n get trigger(): 'click' | 'hover' | 'manual' {\n return this._trigger\n }\n set trigger(v: string) {\n const old = this._trigger\n this._trigger = normalizeLiteral(v, ALLOWED_TRIGGERS, 'click')\n this.requestUpdate('trigger', old)\n }\n private _trigger: 'click' | 'hover' | 'manual' = 'click'\n\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n\n private _panelId = `wui-popover-panel-${++popoverIdCounter}`\n private _portal?: OverlayPortal\n /**\n * 开启态浮层(issue #120 Block 1):本组件不再自行监听 keydown,只声明「我开着」,\n * 由唯一仲裁者决定一次 Escape 关谁。实例作用域的帧事务入口也在这里(合并了原\n * lifecycle)—— 它的 lifetime 长于一次开合(跨 `suspend()`/`resume()`),\n * 但不长于实例本身。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => {\n this._userOpenChange.mark()\n this.open = false\n },\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n document.addEventListener('click', this._onClickOutside)\n this.addEventListener('focusout', this._onFocusOut)\n this._syncTriggerListeners()\n }\n\n override firstUpdated() {\n // trigger slot 内容增删不触发宿主响应式更新:显式请求一轮渲染,\n // 由 updated() 的 ARIA 回写覆盖晚到的 trigger 元素。\n this.shadowRoot\n ?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n ?.addEventListener('slotchange', () => this.requestUpdate())\n\n if (this.open) {\n // 建立会话的那一帧没有句柄可作 liveness 凭据:关闭路径会 invalidate()(见 updated),\n // 微任务先于 rAF 排空,因此该帧不可能跨过一次关闭执行。\n this._overlay.scheduleFrame(() => {\n this._openOverlay(this._shouldOpenInstantly)\n })\n this._shouldOpenInstantly = true\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this._onClickOutside)\n this.removeEventListener('focusout', this._onFocusOut)\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._panel.dispose()\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // ARIA 回写不依赖 open 分支,任何渲染后都保持与宿主状态同步。\n this._syncTriggerAria()\n\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能排两个回调;先结束旧事务,让 reconfigure 成为本帧唯一入口。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n if (this.open) {\n const isInstant = this._shouldOpenInstantly\n this._shouldOpenInstantly = true\n this._overlay.scheduleFrame(() => {\n this._openOverlay(isInstant)\n })\n if (this._userOpenChange.consume()) this._dispatchChange(true)\n this._focusPanel()\n } else {\n this._overlay.invalidate()\n this._returnFocus()\n void this._closeOverlay()\n if (this._userOpenChange.consume()) this._dispatchChange(false)\n }\n }\n\n if (changed.has('trigger')) {\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._syncTriggerListeners()\n }\n this._syncOverlayInert()\n }\n\n show() {\n if (this.disabled || this.open) return\n this.open = true\n }\n\n close() {\n if (!this.open) return\n this.open = false\n }\n\n toggle() {\n if (this.open) this.close()\n else this.show()\n }\n\n private _isInsideShadowRoot(e: MouseEvent): boolean {\n for (const node of e.composedPath()) {\n if (node instanceof Node && node.getRootNode() === this.shadowRoot) return true\n }\n return false\n }\n\n private _syncTriggerListeners() {\n if (this.trigger === 'hover') {\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n }\n }\n\n /*\n * `manual` 触发器的 popover 不由用户关闭,但仍是候选:Escape 被它吞掉(同时压掉\n * 原生 cancel),只是不走关闭入口。与旧的「跳过候选」语义不同 —— 旧语义放任 Escape\n * 落到下层浮层,把外层一起关掉。trigger 可在开启期间改写,所以走动态通道同步。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(this.trigger === 'manual')\n }\n\n private _openOverlay(isInstant = false) {\n /*\n * 登记与仲裁归属由 anchored panel 完成(claim 要求 panel 已就位,祖先链才判得对)。\n * 原实现在这里额外以宿主为 owner 再登记一次:anchor 是宿主 shadow 内的\n * `.popover-trigger` 包装 div(不是会被 slot 重定向的 trigger 内容),其祖先链上\n * 首个已开启浮层与从宿主上溯结果一致,因此那一次是冗余的。\n */\n this._panel.open(isInstant)\n this._syncOverlayInert()\n }\n\n private _migratableContentNodes(nodes: Node[]): Node[] {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:面板内容是实时渲染契约,\n // 框架后续 patch 以宿主内锚点为插入基准,锚点进面板会让插入落空。\n return nodes.filter(node => !(node instanceof Comment) && !(node instanceof HTMLElement && node.slot === 'trigger'))\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'popover-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n migrateAddedNodes: addedNodes => this._migratableContentNodes(addedNodes)\n })\n this._portal = portal\n portal.panel.id = this._panelId\n portal.panel.setAttribute('role', 'dialog')\n portal.panel.tabIndex = -1\n portal.panel.addEventListener('pointerenter', this._onPanelPointerEnter)\n portal.panel.addEventListener('pointerleave', this._onPanelPointerLeave)\n portal.moveContent(this._migratableContentNodes(Array.from(this.childNodes)))\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n // portal 变更也会登记 rAF;宿主卸载后不得再通过 reconfigure 重建面板。\n if (!this.isConnected) return\n this._panel.reconfigure(this.open)\n /*\n * reconfigure 重新 claim = 新会话,inert 回到 false。这里的重推是**承重的**,不是\n * 防御性备份:`reconfigure` 不触发 Lit 渲染,`updated()` 那次同步不会跟着来。\n * 实测摘掉本行,「portal 变更后 Escape 仍不关闭」立刻转红(select / autocomplete 的\n * 同类重推则被各自的渲染掩盖,摘掉仍绿)。\n */\n this._syncOverlayInert()\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n /*\n * trigger 包装 div 不可聚焦,AT 读不到其 aria 状态:把 aria-expanded /\n * aria-controls 同步回写到 trigger slot 的首个 assigned element(Q8a)。\n * 包装 div 上的同名属性保留(additive,兼容既有查询)。\n */\n private _syncTriggerAria() {\n const trigger = this._queryTrigger()\n if (!trigger) return\n trigger.setAttribute('aria-expanded', String(this.open))\n trigger.setAttribute('aria-controls', this._panelId)\n }\n\n private _focusPanel() {\n this._overlay.scheduleFrame(() => {\n const panel = this._panel.getPanel()\n const autofocus = panel?.querySelector<HTMLElement>('[autofocus]')\n if (autofocus && !autofocus.matches(':disabled, [disabled]')) autofocus.focus()\n })\n }\n\n private _returnFocus() {\n const panel = this._panel.getPanel()\n if (!panel?.matches(':focus-within')) return\n const trigger = this._queryTrigger()\n trigger?.focus()\n }\n\n private _queryTrigger(): HTMLElement | null {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const el = slot?.assignedElements()[0]\n return el instanceof HTMLElement ? el : null\n }\n\n private _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n if (this.trigger === 'hover') return\n if (!this.open) this._shouldOpenInstantly = event.detail === 0\n this._userOpenChange.mark()\n this.toggle()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n // 在监听器内部判定:composedPath() 在派发结束后会被清空。\n if (this._panel.getHandle()?.containsEvent(e)) return\n if (this._isInsideShadowRoot(e)) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _onFocusOut = () => {\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n\n this._overlay.scheduleFrame(() => {\n if (!this.matches(':focus-within') && !this._panel.getHandle()?.hasFocusWithin()) {\n this._userOpenChange.mark()\n this.open = false\n }\n })\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n this._showTimer = setTimeout(() => {\n this._shouldOpenInstantly = false\n if (this.open) return\n this._userOpenChange.mark()\n this.show()\n }, 100)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n private _onPanelPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n }\n\n private _onPanelPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n override render() {\n return html`\n <div class=\"popover-anchor\">\n <div\n class=\"popover-trigger\"\n aria-expanded=${String(this.open)}\n aria-controls=${this._panelId}\n @click=${this._onTriggerClick}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n id=${this._panelId}\n class=\"popover-panel wui-floating-panel wui-glass\"\n hidden\n role=\"dialog\"\n tabindex=\"-1\"\n @pointerenter=${this._onPanelPointerEnter}\n @pointerleave=${this._onPanelPointerLeave}\n >\n <slot></slot>\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-popover': WebUiPopover\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/popover/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal, type OverlayContainer, type OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_TRIGGERS = ['click', 'hover', 'manual'] as const\n\nlet popoverIdCounter = 0\n\n@customElement('web-ui-popover')\nexport class WebUiPopover extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'bottom')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'bottom'\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 8)\n this.requestUpdate('offset', old)\n }\n private _offset = 8\n\n @property({ type: String, reflect: true })\n get trigger(): 'click' | 'hover' | 'manual' {\n return this._trigger\n }\n set trigger(v: string) {\n const old = this._trigger\n this._trigger = normalizeLiteral(v, ALLOWED_TRIGGERS, 'click')\n this.requestUpdate('trigger', old)\n }\n private _trigger: 'click' | 'hover' | 'manual' = 'click'\n\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n\n private _panelId = `wui-popover-panel-${++popoverIdCounter}`\n private _portal?: OverlayPortal\n /**\n * 开启态浮层(issue #120 Block 1):本组件不再自行监听 keydown,只声明「我开着」,\n * 由唯一仲裁者决定一次 Escape 关谁。实例作用域的帧事务入口也在这里(合并了原\n * lifecycle)—— 它的 lifetime 长于一次开合(跨 `suspend()`/`resume()`),\n * 但不长于实例本身。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => {\n this._userOpenChange.mark()\n this.open = false\n },\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n document.addEventListener('click', this._onClickOutside)\n this.addEventListener('focusout', this._onFocusOut)\n this._syncTriggerListeners()\n }\n\n override firstUpdated() {\n // trigger slot 内容增删不触发宿主响应式更新:显式请求一轮渲染,\n // 由 updated() 的 ARIA 回写覆盖晚到的 trigger 元素。\n this.shadowRoot\n ?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n ?.addEventListener('slotchange', () => this.requestUpdate())\n\n if (this.open) {\n // 建立会话的那一帧没有句柄可作 liveness 凭据:关闭路径会 invalidate()(见 updated),\n // 微任务先于 rAF 排空,因此该帧不可能跨过一次关闭执行。\n this._overlay.scheduleFrame(() => {\n this._openOverlay(this._shouldOpenInstantly)\n })\n this._shouldOpenInstantly = true\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this._onClickOutside)\n this.removeEventListener('focusout', this._onFocusOut)\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._panel.dispose()\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // ARIA 回写不依赖 open 分支,任何渲染后都保持与宿主状态同步。\n this._syncTriggerAria()\n\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能排两个回调;先结束旧事务,让 reconfigure 成为本帧唯一入口。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n if (this.open) {\n const isInstant = this._shouldOpenInstantly\n this._shouldOpenInstantly = true\n this._overlay.scheduleFrame(() => {\n this._openOverlay(isInstant)\n })\n if (this._userOpenChange.consume()) this._dispatchChange(true)\n this._focusPanel()\n } else {\n this._overlay.invalidate()\n this._returnFocus()\n void this._closeOverlay()\n if (this._userOpenChange.consume()) this._dispatchChange(false)\n }\n }\n\n if (changed.has('trigger')) {\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._syncTriggerListeners()\n }\n this._syncOverlayInert()\n }\n\n show() {\n if (this.disabled || this.open) return\n this.open = true\n }\n\n close() {\n if (!this.open) return\n this.open = false\n }\n\n toggle() {\n if (this.open) this.close()\n else this.show()\n }\n\n private _isInsideShadowRoot(e: MouseEvent): boolean {\n for (const node of e.composedPath()) {\n if (node instanceof Node && node.getRootNode() === this.shadowRoot) return true\n }\n return false\n }\n\n private _syncTriggerListeners() {\n if (this.trigger === 'hover') {\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n }\n }\n\n /*\n * `manual` 触发器的 popover 不由用户关闭,但仍是候选:Escape 被它吞掉(同时压掉\n * 原生 cancel),只是不走关闭入口。与旧的「跳过候选」语义不同 —— 旧语义放任 Escape\n * 落到下层浮层,把外层一起关掉。trigger 可在开启期间改写,所以走动态通道同步。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(this.trigger === 'manual')\n }\n\n private _openOverlay(isInstant = false) {\n /*\n * 登记与仲裁归属由 anchored panel 完成(claim 要求 panel 已就位,祖先链才判得对)。\n * 原实现在这里额外以宿主为 owner 再登记一次:anchor 是宿主 shadow 内的\n * `.popover-trigger` 包装 div(不是会被 slot 重定向的 trigger 内容),其祖先链上\n * 首个已开启浮层与从宿主上溯结果一致,因此那一次是冗余的。\n */\n this._panel.open(isInstant)\n this._syncOverlayInert()\n }\n\n private _migratableContentNodes(nodes: Node[]): Node[] {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:面板内容是实时渲染契约,\n // 框架后续 patch 以宿主内锚点为插入基准,锚点进面板会让插入落空。\n return nodes.filter(node => !(node instanceof Comment) && !(node instanceof HTMLElement && node.slot === 'trigger'))\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'popover-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n migrateAddedNodes: addedNodes => this._migratableContentNodes(addedNodes)\n })\n this._portal = portal\n portal.panel.id = this._panelId\n portal.panel.setAttribute('role', 'dialog')\n portal.panel.tabIndex = -1\n portal.panel.addEventListener('pointerenter', this._onPanelPointerEnter)\n portal.panel.addEventListener('pointerleave', this._onPanelPointerLeave)\n portal.moveContent(this._migratableContentNodes(Array.from(this.childNodes)))\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n // portal 变更也会登记 rAF;宿主卸载后不得再通过 reconfigure 重建面板。\n if (!this.isConnected) return\n this._panel.reconfigure(this.open)\n /*\n * reconfigure 重新 claim = 新会话,inert 回到 false。这里的重推是**承重的**,不是\n * 防御性备份:`reconfigure` 不触发 Lit 渲染,`updated()` 那次同步不会跟着来。\n * 实测摘掉本行,「portal 变更后 Escape 仍不关闭」立刻转红(select / autocomplete 的\n * 同类重推则被各自的渲染掩盖,摘掉仍绿)。\n */\n this._syncOverlayInert()\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n /*\n * trigger 包装 div 不可聚焦,AT 读不到其 aria 状态:把 aria-expanded /\n * aria-controls 同步回写到 trigger slot 的首个 assigned element(Q8a)。\n * 包装 div 上的同名属性保留(additive,兼容既有查询)。\n */\n private _syncTriggerAria() {\n const trigger = this._queryTrigger()\n if (!trigger) return\n trigger.setAttribute('aria-expanded', String(this.open))\n trigger.setAttribute('aria-controls', this._panelId)\n }\n\n private _focusPanel() {\n this._overlay.scheduleFrame(() => {\n const panel = this._panel.getPanel()\n const autofocus = panel?.querySelector<HTMLElement>('[autofocus]')\n if (autofocus && !autofocus.matches(':disabled, [disabled]')) autofocus.focus()\n })\n }\n\n private _returnFocus() {\n const panel = this._panel.getPanel()\n if (!panel?.matches(':focus-within')) return\n const trigger = this._queryTrigger()\n trigger?.focus()\n }\n\n private _queryTrigger(): HTMLElement | null {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const el = slot?.assignedElements()[0]\n return el instanceof HTMLElement ? el : null\n }\n\n private _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n if (this.trigger === 'hover') return\n if (!this.open) this._shouldOpenInstantly = event.detail === 0\n this._userOpenChange.mark()\n this.toggle()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n // 在监听器内部判定:composedPath() 在派发结束后会被清空。\n if (this._panel.getHandle()?.containsEvent(e)) return\n if (this._isInsideShadowRoot(e)) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _onFocusOut = () => {\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n\n this._overlay.scheduleFrame(() => {\n if (!this.matches(':focus-within') && !this._panel.getHandle()?.hasFocusWithin()) {\n this._userOpenChange.mark()\n this.open = false\n }\n })\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n this._showTimer = setTimeout(() => {\n this._shouldOpenInstantly = false\n if (this.open) return\n this._userOpenChange.mark()\n this.show()\n }, 100)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n private _onPanelPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n }\n\n private _onPanelPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n override render() {\n return html`\n <div class=\"popover-anchor\">\n <div\n class=\"popover-trigger\"\n aria-expanded=${String(this.open)}\n aria-controls=${this._panelId}\n @click=${this._onTriggerClick}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n id=${this._panelId}\n class=\"popover-panel wui-floating-panel wui-glass\"\n hidden\n role=\"dialog\"\n tabindex=\"-1\"\n @pointerenter=${this._onPanelPointerEnter}\n @pointerleave=${this._onPanelPointerLeave}\n >\n <slot></slot>\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-popover': WebUiPopover\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/popover/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-flex}:host([disabled]){cursor:not-allowed}.popover-trigger{display:inline-flex}.popover-anchor{display:inline-flex;position:relative}.popover-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);z-index:var(--wui-layer-inline-overlay,1);box-sizing:border-box;border-radius:var(--wui-radius-menu,18px);width:max-content;max-width:min(90vw,400px);font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#fefefec2);padding:8px 12px;line-height:1.5;position:absolute;top:-9999px;left:-9999px}.popover-panel:where([hidden]){display:none}.popover-panel:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}.popover-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}:host([portal]) .popover-panel{display:none}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-flex}:host([disabled]){cursor:not-allowed}.popover-trigger{display:inline-flex}.popover-anchor{display:inline-flex;position:relative}.popover-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);--wui-color-glass-ring:transparent;z-index:var(--wui-layer-inline-overlay,1);box-sizing:border-box;width:max-content;max-width:min(90vw,400px);padding:var(--wui-space-2,8px) var(--wui-space-3,12px);border-radius:var(--wui-radius-menu,18px);font-size:var(--wui-font-size,14px);line-height:var(--wui-line-height-normal,1.5);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#fafafac2);position:absolute;top:-9999px;left:-9999px}.popover-panel:where([hidden]){display:none}.popover-panel:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#08f) 40%, transparent));outline-offset:2px}.popover-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}:host([portal]) .popover-panel{display:none}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/popover/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-flex;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n.popover-trigger {\n display: inline-flex;\n}\n\n.popover-anchor {\n position: relative;\n display: inline-flex;\n}\n\n.popover-panel {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 1);\n top: -9999px;\n left: -9999px;\n\n box-sizing: border-box;\n width: max-content;\n max-width: min(90vw, 400px);\n padding: 8px 12px;\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n\n /* 玻璃背景:wui-glass 在面板自身,这里覆盖其默认玻璃底为菜单表面色 */\n background-color: var(--wui-color-surface-menu, rgb(254 254 254 / 0.76));\n\n &:where([hidden]) {\n display: none;\n }\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n.popover-panel.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n}\n\n:host([portal]) .popover-panel {\n display: none;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/popover/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-flex;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n.popover-trigger {\n display: inline-flex;\n}\n\n.popover-anchor {\n position: relative;\n display: inline-flex;\n}\n\n.popover-panel {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n\n /* 面板宽远大于角半径,环底色铺出的整圈铺底会在长边中段读成一条比四角更重的\n 直边描边;转 transparent 后只剩四段角弧,见 menu-portal.css 同处注释。 */\n --wui-color-glass-ring: transparent;\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 1);\n top: -9999px;\n left: -9999px;\n\n box-sizing: border-box;\n width: max-content;\n max-width: min(90vw, 400px);\n padding: var(--wui-space-2, 8px) var(--wui-space-3, 12px);\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: var(--wui-line-height-normal, 1.5);\n color: var(--wui-color-text, #1b1b1b);\n\n /* 玻璃背景:wui-glass 在面板自身,这里覆盖其默认玻璃底为菜单表面色 */\n background-color: var(--wui-color-surface-menu, rgb(250 250 250 / 0.76));\n\n &:where([hidden]) {\n display: none;\n }\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #08f) 40%, transparent));\n outline-offset: 2px;\n }\n}\n\n.popover-panel.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n}\n\n:host([portal]) .popover-panel {\n display: none;\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/radio/style.css?inline
2
- var e = ".wui-radio-circle{border-radius:var(--wui-radius-control,calc(infinity * 1px))}.is-checked .wui-radio-circle{background-color:var(--wui-color-accent,#08f)}.wui-radio-dot{border-radius:var(--wui-radius-control,calc(infinity * 1px));opacity:0;background-color:var(--wui-color-on-control,#fff);width:6px;height:6px;transition:opacity var(--wui-duration-trigger,.16s) ease, transform var(--wui-duration-trigger,.16s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));transform:scale(0);box-shadow:inset 0 -1px 2px #0000001f,inset 0 1px 2px #ffffff80,0 0 4px #0088ff4d}.is-checked .wui-radio-dot{opacity:1;transform:scale(1)}@media (prefers-reduced-motion:reduce){.wui-radio-dot,.is-checked .wui-radio-dot{transform:none}}";
2
+ var e = ".wui-radio-circle{border-radius:var(--wui-radius-control,calc(infinity * 1px))}.is-checked .wui-radio-circle{background-color:var(--wui-color-accent,#08f)}.wui-radio-dot{border-radius:var(--wui-radius-control,calc(infinity * 1px));opacity:0;background-color:var(--wui-color-on-control,#fff);width:6px;height:6px;box-shadow:inset 0 -1px 2px #0000001f, inset 0 1px 2px #ffffff80, 0 0 4px color-mix(in srgb, var(--wui-color-accent,#08f) 30%, transparent);transition:opacity var(--wui-duration-trigger,.16s) ease, transform var(--wui-duration-trigger,.16s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));transform:scale(0)}.is-checked .wui-radio-dot{opacity:1;transform:scale(1)}@media (prefers-reduced-motion:reduce){.wui-radio-dot,.is-checked .wui-radio-dot{transform:none}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/radio/style.css?inline"],"sourcesContent":[".wui-radio-circle {\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.is-checked .wui-radio-circle {\n background-color: var(--wui-color-accent, #08f);\n}\n\n.wui-radio-dot {\n transform: scale(0);\n\n width: 6px;\n height: 6px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n opacity: 0;\n background-color: var(--wui-color-on-control, #fff);\n box-shadow:\n inset 0 -1px 2px rgb(0 0 0 / 0.12),\n inset 0 1px 2px rgb(255 255 255 / 0.5),\n 0 0 4px rgb(0 136 255 / 0.3);\n\n transition:\n opacity var(--wui-duration-trigger, 160ms) ease,\n transform var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.is-checked .wui-radio-dot {\n transform: scale(1);\n opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-radio-dot,\n .is-checked .wui-radio-dot {\n transform: none;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/radio/style.css?inline"],"sourcesContent":[".wui-radio-circle {\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.is-checked .wui-radio-circle {\n background-color: var(--wui-color-accent, #08f);\n}\n\n.wui-radio-dot {\n transform: scale(0);\n\n width: 6px;\n height: 6px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n opacity: 0;\n background-color: var(--wui-color-on-control, #fff);\n box-shadow:\n inset 0 -1px 2px rgb(0 0 0 / 0.12),\n inset 0 1px 2px rgb(255 255 255 / 0.5),\n /*\n * 外发光跟着 accent,而不是 --wui-color-focus-ring:这是选中态的装饰性辉光,\n * 与键盘焦点环是两种东西(alpha 也不同:0.3 vs 0.4/0.62)。默认值下与原值等价。\n */\n 0 0 4px color-mix(in srgb, var(--wui-color-accent, #08f) 30%, transparent);\n\n transition:\n opacity var(--wui-duration-trigger, 160ms) ease,\n transform var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.is-checked .wui-radio-dot {\n transform: scale(1);\n opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-radio-dot,\n .is-checked .wui-radio-dot {\n transform: none;\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/radio-group/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{-webkit-user-select:none;user-select:none;gap:var(--wui-radio-group-gap,8px);flex-direction:column;display:inline-flex}.wui-radio-group{flex-direction:inherit;gap:inherit;display:flex}:host([direction=horizontal]){flex-direction:row}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{-webkit-user-select:none;user-select:none;gap:var(--wui-radio-group-gap,var(--wui-space-2,8px));flex-direction:column;display:inline-flex}.wui-radio-group{flex-direction:inherit;gap:inherit;display:flex}:host([direction=horizontal]){flex-direction:row}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/radio-group/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n user-select: none;\n display: inline-flex;\n flex-direction: column;\n gap: var(--wui-radio-group-gap, 8px);\n}\n\n.wui-radio-group {\n display: flex;\n flex-direction: inherit;\n gap: inherit;\n}\n\n:host([direction='horizontal']) {\n flex-direction: row;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/radio-group/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n user-select: none;\n display: inline-flex;\n flex-direction: column;\n gap: var(--wui-radio-group-gap, var(--wui-space-2, 8px));\n}\n\n.wui-radio-group {\n display: flex;\n flex-direction: inherit;\n gap: inherit;\n}\n\n:host([direction='horizontal']) {\n flex-direction: row;\n}\n"],"mappings":""}