@greypan/web-ui 12.0.1 → 12.2.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.
- package/README.CN.md +4 -0
- package/README.md +4 -0
- package/dist/assets/menu-portal.js +1 -1
- package/dist/assets/menu-portal.js.map +1 -1
- package/dist/assets/toast-containers.js +1 -1
- package/dist/assets/toast-containers.js.map +1 -1
- package/dist/components/autocomplete/index.d.ts +5 -0
- package/dist/components/autocomplete/index.d.ts.map +1 -1
- package/dist/components/autocomplete/index.js +18 -2
- package/dist/components/autocomplete/index.js.map +1 -1
- package/dist/components/autocomplete/style.js +1 -1
- package/dist/components/autocomplete/style.js.map +1 -1
- package/dist/components/back-top/style.js +1 -1
- package/dist/components/back-top/style.js.map +1 -1
- package/dist/components/button-group/style.js +1 -1
- package/dist/components/button-group/style.js.map +1 -1
- package/dist/components/dialog/index.d.ts +5 -1
- package/dist/components/dialog/index.d.ts.map +1 -1
- package/dist/components/dialog/index.js +16 -4
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/dialog/style.js +1 -1
- package/dist/components/dialog/style.js.map +1 -1
- package/dist/components/drawer/index.d.ts +11 -0
- package/dist/components/drawer/index.d.ts.map +1 -1
- package/dist/components/drawer/index.js +23 -1
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/page-shift.js +113 -0
- package/dist/components/drawer/page-shift.js.map +1 -0
- package/dist/components/dropdown/index.js +1 -1
- package/dist/components/grouped-text/grouping.d.ts +25 -0
- package/dist/components/grouped-text/grouping.d.ts.map +1 -0
- package/dist/components/grouped-text/grouping.js +147 -0
- package/dist/components/grouped-text/grouping.js.map +1 -0
- package/dist/components/grouped-text/index.d.ts +36 -0
- package/dist/components/grouped-text/index.d.ts.map +1 -0
- package/dist/components/grouped-text/index.js +28 -0
- package/dist/components/grouped-text/index.js.map +1 -0
- package/dist/components/grouped-text/style.js +5 -0
- package/dist/components/grouped-text/style.js.map +1 -0
- package/dist/components/icon/index.d.ts +1 -1
- package/dist/components/icon/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -1
- package/dist/components/layout/index.d.ts +8 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +24 -13
- package/dist/components/layout/index.js.map +1 -1
- package/dist/components/layout/style.js +1 -1
- package/dist/components/layout/style.js.map +1 -1
- package/dist/components/middle-ellipsis/index.js +1 -1
- package/dist/components/popover/index.d.ts +5 -2
- package/dist/components/popover/index.d.ts.map +1 -1
- package/dist/components/popover/index.js +32 -21
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/popover/style.js +1 -1
- package/dist/components/popover/style.js.map +1 -1
- package/dist/components/progress/index.d.ts +30 -0
- package/dist/components/progress/index.d.ts.map +1 -0
- package/dist/components/progress/index.js +103 -0
- package/dist/components/progress/index.js.map +1 -0
- package/dist/components/progress/style.js +5 -0
- package/dist/components/progress/style.js.map +1 -0
- package/dist/components/segmented-trigger/index.d.ts +2 -0
- package/dist/components/segmented-trigger/index.d.ts.map +1 -1
- package/dist/components/segmented-trigger/index.js +7 -0
- package/dist/components/segmented-trigger/index.js.map +1 -1
- package/dist/components/select/index.d.ts +13 -0
- package/dist/components/select/index.d.ts.map +1 -1
- package/dist/components/select/index.js +41 -3
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/style.js +1 -1
- package/dist/components/select/style.js.map +1 -1
- package/dist/components/shake/index.d.ts +43 -0
- package/dist/components/shake/index.d.ts.map +1 -0
- package/dist/components/shake/index.js +103 -0
- package/dist/components/shake/index.js.map +1 -0
- package/dist/components/spinner/index.d.ts +0 -3
- package/dist/components/spinner/index.d.ts.map +1 -1
- package/dist/components/spinner/index.js +5 -20
- package/dist/components/spinner/index.js.map +1 -1
- package/dist/components/spinner/style.js +1 -1
- package/dist/components/spinner/style.js.map +1 -1
- package/dist/components/theme/style.js +1 -1
- package/dist/components/theme/style.js.map +1 -1
- package/dist/components/tooltip/index.d.ts +8 -0
- package/dist/components/tooltip/index.d.ts.map +1 -1
- package/dist/components/tooltip/index.js +60 -10
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/components/tooltip/style.js +1 -1
- package/dist/components/tooltip/style.js.map +1 -1
- package/dist/icons/generated/ant-design-sync-outlined.d.ts +7 -0
- package/dist/icons/generated/ant-design-sync-outlined.d.ts.map +1 -0
- package/dist/icons/generated/ant-design-sync-outlined.js +9 -0
- package/dist/icons/generated/ant-design-sync-outlined.js.map +1 -0
- package/dist/icons/generated/ic-baseline-phonelink.d.ts +7 -0
- package/dist/icons/generated/ic-baseline-phonelink.d.ts.map +1 -0
- package/dist/icons/generated/ic-baseline-phonelink.js +9 -0
- package/dist/icons/generated/ic-baseline-phonelink.js.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.d.ts +7 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.d.ts.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.js +9 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.js.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.d.ts +7 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.d.ts.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.js +9 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.js.map +1 -0
- package/dist/icons/generated/ic-round-menu-open.d.ts +7 -0
- package/dist/icons/generated/ic-round-menu-open.d.ts.map +1 -0
- package/dist/icons/generated/ic-round-menu-open.js +9 -0
- package/dist/icons/generated/ic-round-menu-open.js.map +1 -0
- package/dist/icons/generated/lucide-accessibility.d.ts +7 -0
- package/dist/icons/generated/lucide-accessibility.d.ts.map +1 -0
- package/dist/icons/generated/lucide-accessibility.js +9 -0
- package/dist/icons/generated/lucide-accessibility.js.map +1 -0
- package/dist/icons/generated/lucide-boxes.d.ts +7 -0
- package/dist/icons/generated/lucide-boxes.d.ts.map +1 -0
- package/dist/icons/generated/lucide-boxes.js +9 -0
- package/dist/icons/generated/lucide-boxes.js.map +1 -0
- package/dist/icons/generated/lucide-contrast.d.ts +7 -0
- package/dist/icons/generated/lucide-contrast.d.ts.map +1 -0
- package/dist/icons/generated/lucide-contrast.js +9 -0
- package/dist/icons/generated/lucide-contrast.js.map +1 -0
- package/dist/icons/generated/lucide-keyboard.d.ts +7 -0
- package/dist/icons/generated/lucide-keyboard.d.ts.map +1 -0
- package/dist/icons/generated/lucide-keyboard.js +9 -0
- package/dist/icons/generated/lucide-keyboard.js.map +1 -0
- package/dist/icons/generated/lucide-languages.d.ts +7 -0
- package/dist/icons/generated/lucide-languages.d.ts.map +1 -0
- package/dist/icons/generated/lucide-languages.js +9 -0
- package/dist/icons/generated/lucide-languages.js.map +1 -0
- package/dist/icons/generated/lucide-list.d.ts +7 -0
- package/dist/icons/generated/lucide-list.d.ts.map +1 -0
- package/dist/icons/generated/lucide-list.js +9 -0
- package/dist/icons/generated/lucide-list.js.map +1 -0
- package/dist/icons/generated/lucide-moon.d.ts +7 -0
- package/dist/icons/generated/lucide-moon.d.ts.map +1 -0
- package/dist/icons/generated/lucide-moon.js +9 -0
- package/dist/icons/generated/lucide-moon.js.map +1 -0
- package/dist/icons/generated/lucide-sparkles.d.ts +7 -0
- package/dist/icons/generated/lucide-sparkles.d.ts.map +1 -0
- package/dist/icons/generated/lucide-sparkles.js +9 -0
- package/dist/icons/generated/lucide-sparkles.js.map +1 -0
- package/dist/icons/generated/lucide-sun.d.ts +7 -0
- package/dist/icons/generated/lucide-sun.d.ts.map +1 -0
- package/dist/icons/generated/lucide-sun.js +9 -0
- package/dist/icons/generated/lucide-sun.js.map +1 -0
- package/dist/icons/generated/tabler-brand-typescript.d.ts +7 -0
- package/dist/icons/generated/tabler-brand-typescript.d.ts.map +1 -0
- package/dist/icons/generated/tabler-brand-typescript.js +9 -0
- package/dist/icons/generated/tabler-brand-typescript.js.map +1 -0
- package/dist/icons/index.d.ts +87 -72
- package/dist/icons/index.js +16 -1
- package/dist/shared/locale/builtin-labels.js +2 -1
- package/dist/shared/locale/builtin-labels.js.map +1 -1
- package/dist/shared/overlay/anchored-panel.js +2 -2
- package/dist/shared/overlay/anchored-panel.js.map +1 -1
- package/dist/shared/overlay/presence.js +2 -2
- package/dist/shared/overlay/presence.js.map +1 -1
- package/dist/shared/overlay/trigger-props.d.ts +10 -0
- package/dist/shared/overlay/trigger-props.d.ts.map +1 -0
- package/dist/shared/overlay/trigger-props.js +42 -0
- package/dist/shared/overlay/trigger-props.js.map +1 -0
- package/package.json +4 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/layout/style.css?inline
|
|
2
|
-
var style_default = "*,:before,:after{box-sizing:border-box}:host{--wui-layout-visible-banner-height:0px;display:block}.layout-page{flex-direction:column;
|
|
2
|
+
var style_default = "*,:before,:after{box-sizing:border-box}:host{--wui-layout-visible-banner-height:0px;--wui-internal-layout-viewport-height:var(--wui-layout-viewport-height,100vh);display:block}.layout-page{min-height:var(--wui-internal-layout-viewport-height);flex-direction:column;display:flex}.layout-banner{z-index:var(--wui-layer-banner,300);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,500);max-width:50vw;height:calc(var(--wui-internal-layout-viewport-height) - var(--wui-layout-visible-banner-height));max-height:calc(var(--wui-internal-layout-viewport-height) - 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,36px);margin:var(--wui-space-2,8px)}aside.collapsed .sidebar-viewport{overflow:hidden}@supports (height:100dvh){:host{--wui-internal-layout-viewport-height:var(--wui-layout-viewport-height,100dvh)}}.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,#0071e3);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,#0071e3) 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,100);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)}main{flex:1}footer{z-index:var(--wui-layer-tabbar,400);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}}\n";
|
|
3
3
|
export { style_default as default };
|
|
4
4
|
|
|
5
5
|
//# sourceMappingURL=style.js.map
|
|
@@ -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\n display: block;\n}\n\n/* 页面级滚动容器。Banner 位于正文前,随页面一起滚动。 */\n.layout-page {\n display: flex;\n flex-direction: column;\n min-height:
|
|
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-internal-layout-viewport-height: var(--wui-layout-viewport-height, 100vh);\n\n display: block;\n}\n\n/* 页面级滚动容器。Banner 位于正文前,随页面一起滚动。 */\n.layout-page {\n display: flex;\n flex-direction: column;\n min-height: var(--wui-internal-layout-viewport-height);\n}\n\n.layout-banner {\n position: relative;\n z-index: var(--wui-layer-banner, 300);\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, 500);\n top: 0;\n\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n\n max-width: 50vw;\n height: calc(var(--wui-internal-layout-viewport-height) - var(--wui-layout-visible-banner-height));\n max-height: calc(var(--wui-internal-layout-viewport-height) - 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 侧无法直接改写它。要让 collapsed state 的 toggle 跟着 collapsed width\n * 一起变,只能由这里显式接一个出口。取值由 app 决定,本组件不假设 collapsed width。\n * 默认值 36px;app 侧不覆盖时就是这个宽度。\n */\n --wui-button-width: var(--wui-layout-sidebar-toggle-width, 36px);\n\n margin: var(--wui-space-2, 8px);\n }\n\n &.collapsed {\n .sidebar-viewport {\n overflow: hidden;\n }\n }\n}\n\n@supports (height: 100dvh) {\n :host {\n --wui-internal-layout-viewport-height: var(--wui-layout-viewport-height, 100dvh);\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, #0071e3);\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, #0071e3) 40%, transparent));\n outline-offset: 2px;\n}\n\n/* 拖拽中禁用宽度过渡,保证实时跟手。 */\naside.is-resizing {\n transition: none;\n}\n\n.layout-content {\n /*\n * 内容列的横向溢出由本层裁掉,避免撑出页面横向 scrollbar;它有 min-width: 0,\n * 是容纳横向溢出的位置。glow 伪元素已收在 header 盒内(见 header 的注释),\n * 不再依赖这层裁剪。\n *\n * clip 不创建滚动容器,因此不影响 header / footer 自身的 sticky;也不用 hidden——\n * 那会把本层变成滚动容器,sticky 随即失效。\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 把负层级的 .wui-glow 伪元素限定在本 Header 的局部 stacking\n * context,slot 内容自然位于其上。晕染本身来自共享样式(src/classes/glow.css),\n * header-glow 属性负责挂 class。\n *\n * 「纵向必须 visible 才留得住模糊尾巴与下拉 overlay 的溢出空间」仍然成立——\n * overflow-* 一旦生效就会裁剪该轴,visible 是这些内容的唯一溢出出口。\n */\n isolation: isolate;\n position: sticky;\n z-index: var(--wui-layer-header, 100);\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\nmain {\n flex: 1;\n}\n\nfooter {\n position: sticky;\n z-index: var(--wui-layer-tabbar, 400);\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":";AAAA,IAAA,gBAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import __decorate from "../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
|
|
2
2
|
import { normalizeNumber } from "../../shared/normalize/index.js";
|
|
3
|
+
import { truncateMiddle } from "./truncate.js";
|
|
3
4
|
import { ElementWidthController } from "../../shared/element-width/index.js";
|
|
4
5
|
import style_default from "./style.js";
|
|
5
|
-
import { truncateMiddle } from "./truncate.js";
|
|
6
6
|
import { LitElement, html, unsafeCSS } from "lit";
|
|
7
7
|
import { customElement, property, query } from "lit/decorators.js";
|
|
8
8
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OverlayContainer } from "../../shared/overlay/portal.js";
|
|
2
|
+
import { OverlayTriggerMode } from "../../shared/overlay/trigger-props.js";
|
|
2
3
|
import { LitElement } from "lit";
|
|
3
4
|
import { Placement } from "@floating-ui/dom";
|
|
4
5
|
export declare class WebUiPopover extends LitElement {
|
|
@@ -11,8 +12,8 @@ export declare class WebUiPopover extends LitElement {
|
|
|
11
12
|
get offset(): number;
|
|
12
13
|
set offset(v: number);
|
|
13
14
|
private _offset;
|
|
14
|
-
get trigger():
|
|
15
|
-
set trigger(v: string);
|
|
15
|
+
get trigger(): string;
|
|
16
|
+
set trigger(v: string | readonly OverlayTriggerMode[]);
|
|
16
17
|
private _trigger;
|
|
17
18
|
portal: boolean;
|
|
18
19
|
overlayContainer?: OverlayContainer;
|
|
@@ -40,6 +41,7 @@ export declare class WebUiPopover extends LitElement {
|
|
|
40
41
|
toggle(): void;
|
|
41
42
|
private _isInsideShadowRoot;
|
|
42
43
|
private _syncTriggerListeners;
|
|
44
|
+
private _clearGestureListeners;
|
|
43
45
|
private _syncOverlayInert;
|
|
44
46
|
private _openOverlay;
|
|
45
47
|
private _migratableContentNodes;
|
|
@@ -53,6 +55,7 @@ export declare class WebUiPopover extends LitElement {
|
|
|
53
55
|
private _queryTrigger;
|
|
54
56
|
private _onTriggerClick;
|
|
55
57
|
private _onClickOutside;
|
|
58
|
+
private _onFocusIn;
|
|
56
59
|
private _onFocusOut;
|
|
57
60
|
private _onPointerEnter;
|
|
58
61
|
private _onPointerLeave;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/popover/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/popover/index.ts"],"mappings":";;;;qBAuBa,qBAAqB;SAChB,sBAAM;EAEsB;EACA;MAGxC,aAAa;MAGb,UAAU;UAKN;MAGJ;MAGA,OAAO;UAKH;MAGJ;MAGA,QAAQ,qBAAqB;UAKzB;EAEoC;EACZ,mBAAmB;UAE3C;UACA;mBACS;UACT;UAEA;UACA;;;;;;;mBAOS;mBAOA;MAab;EAIK;EAQA;EAiBA;YAYU,QAAQ,SAAS;EAqCpC;EAKA;EAKA;UAKQ;UAOA;UAQA;UAWA;UAIA;UAWA;UAMA;UAmBM;UAIN;UAaA;UASA;UAOA;UAQA;UAMA;UAMA;UAWA;UAUA;UAYA;UAYA;UAYA;UAWA;UAMA;EAUC,wBAAM;WA0BE;IACf,eAAe;MAAc;;;;QAIzB;YACI;IACR,kBAAkB"}
|
|
@@ -5,18 +5,16 @@ import overlay_motion_default from "../../assets/overlay-motion.js";
|
|
|
5
5
|
import { dispatchOpenChangeEvent } from "../../shared/open-state/index.js";
|
|
6
6
|
import { defineAnchoredPanel } from "../../shared/overlay/anchored-panel.js";
|
|
7
7
|
import { defineOpenOverlay } from "../../shared/overlay/open-overlay.js";
|
|
8
|
+
import { FLOATING_PLACEMENTS } from "../../shared/overlay/placement-props.js";
|
|
8
9
|
import { defineOverlayPortal } from "../../shared/overlay/portal.js";
|
|
9
10
|
import { UserChangeController } from "../../shared/events/user-change.js";
|
|
10
|
-
import {
|
|
11
|
+
import { hasTriggerMode, normalizeTriggerSet } from "../../shared/overlay/trigger-props.js";
|
|
11
12
|
import style_default from "./style.js";
|
|
12
13
|
import { LitElement, html, unsafeCSS } from "lit";
|
|
13
14
|
import { customElement, property } from "lit/decorators.js";
|
|
14
15
|
// src/components/popover/index.ts
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"hover",
|
|
18
|
-
"manual"
|
|
19
|
-
];
|
|
16
|
+
/** 点击 trigger 开合,点 panel 外、失焦与 Escape 都能收。 */
|
|
17
|
+
const DEFAULT_TRIGGERS = ["click"];
|
|
20
18
|
let popoverIdCounter = 0;
|
|
21
19
|
let WebUiPopover = class WebUiPopover extends LitElement {
|
|
22
20
|
constructor(..._args) {
|
|
@@ -25,7 +23,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
25
23
|
this.disabled = false;
|
|
26
24
|
this._placement = "bottom";
|
|
27
25
|
this._offset = 8;
|
|
28
|
-
this._trigger = "
|
|
26
|
+
this._trigger = DEFAULT_TRIGGERS.join(" ");
|
|
29
27
|
this.portal = false;
|
|
30
28
|
this._userOpenChange = new UserChangeController();
|
|
31
29
|
this._shouldOpenInstantly = true;
|
|
@@ -53,21 +51,30 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
53
51
|
if (this.disabled) return;
|
|
54
52
|
clearTimeout(this._showTimer);
|
|
55
53
|
clearTimeout(this._hideTimer);
|
|
56
|
-
if (this.trigger
|
|
54
|
+
if (!hasTriggerMode(this.trigger, "click") && !hasTriggerMode(this.trigger, "manual")) return;
|
|
57
55
|
if (!this.open) this._shouldOpenInstantly = event.detail === 0;
|
|
58
56
|
this._userOpenChange.mark();
|
|
59
57
|
this.toggle();
|
|
60
58
|
};
|
|
61
59
|
this._onClickOutside = (e) => {
|
|
62
60
|
if (!this.open) return;
|
|
63
|
-
if (this.trigger
|
|
61
|
+
if (!hasTriggerMode(this.trigger, "click")) return;
|
|
64
62
|
if (this._panel.getHandle()?.containsEvent(e)) return;
|
|
65
63
|
if (this._isInsideShadowRoot(e)) return;
|
|
66
64
|
this._userOpenChange.mark();
|
|
67
65
|
this.open = false;
|
|
68
66
|
};
|
|
67
|
+
this._onFocusIn = (event) => {
|
|
68
|
+
if (this.disabled) return;
|
|
69
|
+
if (this.open) return;
|
|
70
|
+
const focusedElement = event.composedPath()[0] ?? event.target;
|
|
71
|
+
if (!(focusedElement instanceof Element) || !focusedElement.matches(":focus-visible")) return;
|
|
72
|
+
this._shouldOpenInstantly = true;
|
|
73
|
+
this._userOpenChange.mark();
|
|
74
|
+
this.show();
|
|
75
|
+
};
|
|
69
76
|
this._onFocusOut = () => {
|
|
70
|
-
if (this.trigger
|
|
77
|
+
if (!hasTriggerMode(this.trigger, "click") && !hasTriggerMode(this.trigger, "focus")) return;
|
|
71
78
|
this._overlay.scheduleFrame(() => {
|
|
72
79
|
if (!this.matches(":focus-within") && !this._panel.getHandle()?.hasFocusWithin()) {
|
|
73
80
|
this._userOpenChange.mark();
|
|
@@ -77,7 +84,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
77
84
|
};
|
|
78
85
|
this._onPointerEnter = (e) => {
|
|
79
86
|
if (e.pointerType === "touch") return;
|
|
80
|
-
if (this.disabled || this.trigger
|
|
87
|
+
if (this.disabled || !hasTriggerMode(this.trigger, "hover")) return;
|
|
81
88
|
clearTimeout(this._hideTimer);
|
|
82
89
|
this._showTimer = setTimeout(() => {
|
|
83
90
|
this._shouldOpenInstantly = false;
|
|
@@ -88,7 +95,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
88
95
|
};
|
|
89
96
|
this._onPointerLeave = (e) => {
|
|
90
97
|
if (e.pointerType === "touch") return;
|
|
91
|
-
if (this.disabled || this.trigger
|
|
98
|
+
if (this.disabled || !hasTriggerMode(this.trigger, "hover")) return;
|
|
92
99
|
clearTimeout(this._showTimer);
|
|
93
100
|
this._hideTimer = setTimeout(() => {
|
|
94
101
|
if (!this.open) return;
|
|
@@ -98,12 +105,12 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
98
105
|
};
|
|
99
106
|
this._onPanelPointerEnter = (e) => {
|
|
100
107
|
if (e.pointerType === "touch") return;
|
|
101
|
-
if (this.trigger
|
|
108
|
+
if (!hasTriggerMode(this.trigger, "hover")) return;
|
|
102
109
|
clearTimeout(this._hideTimer);
|
|
103
110
|
};
|
|
104
111
|
this._onPanelPointerLeave = (e) => {
|
|
105
112
|
if (e.pointerType === "touch") return;
|
|
106
|
-
if (this.trigger
|
|
113
|
+
if (!hasTriggerMode(this.trigger, "hover")) return;
|
|
107
114
|
this._hideTimer = setTimeout(() => {
|
|
108
115
|
if (!this.open) return;
|
|
109
116
|
this._userOpenChange.mark();
|
|
@@ -139,7 +146,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
139
146
|
}
|
|
140
147
|
set trigger(v) {
|
|
141
148
|
const old = this._trigger;
|
|
142
|
-
this._trigger =
|
|
149
|
+
this._trigger = normalizeTriggerSet(v, DEFAULT_TRIGGERS);
|
|
143
150
|
this.requestUpdate("trigger", old);
|
|
144
151
|
}
|
|
145
152
|
get isOpen() {
|
|
@@ -165,8 +172,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
165
172
|
super.disconnectedCallback();
|
|
166
173
|
document.removeEventListener("click", this._onClickOutside);
|
|
167
174
|
this.removeEventListener("focusout", this._onFocusOut);
|
|
168
|
-
this.
|
|
169
|
-
this.removeEventListener("pointerleave", this._onPointerLeave);
|
|
175
|
+
this._clearGestureListeners();
|
|
170
176
|
this._overlay.suspend();
|
|
171
177
|
clearTimeout(this._showTimer);
|
|
172
178
|
clearTimeout(this._hideTimer);
|
|
@@ -195,8 +201,7 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
if (changed.has("trigger")) {
|
|
198
|
-
this.
|
|
199
|
-
this.removeEventListener("pointerleave", this._onPointerLeave);
|
|
204
|
+
this._clearGestureListeners();
|
|
200
205
|
clearTimeout(this._showTimer);
|
|
201
206
|
clearTimeout(this._hideTimer);
|
|
202
207
|
this._syncTriggerListeners();
|
|
@@ -220,13 +225,19 @@ let WebUiPopover = class WebUiPopover extends LitElement {
|
|
|
220
225
|
return false;
|
|
221
226
|
}
|
|
222
227
|
_syncTriggerListeners() {
|
|
223
|
-
if (this.trigger
|
|
228
|
+
if (hasTriggerMode(this.trigger, "hover")) {
|
|
224
229
|
this.addEventListener("pointerenter", this._onPointerEnter);
|
|
225
230
|
this.addEventListener("pointerleave", this._onPointerLeave);
|
|
226
231
|
}
|
|
232
|
+
if (hasTriggerMode(this.trigger, "focus")) this.addEventListener("focusin", this._onFocusIn);
|
|
233
|
+
}
|
|
234
|
+
_clearGestureListeners() {
|
|
235
|
+
this.removeEventListener("pointerenter", this._onPointerEnter);
|
|
236
|
+
this.removeEventListener("pointerleave", this._onPointerLeave);
|
|
237
|
+
this.removeEventListener("focusin", this._onFocusIn);
|
|
227
238
|
}
|
|
228
239
|
_syncOverlayInert() {
|
|
229
|
-
this._panel.getHandle()?.setInert(this.trigger
|
|
240
|
+
this._panel.getHandle()?.setInert(hasTriggerMode(this.trigger, "manual"));
|
|
230
241
|
}
|
|
231
242
|
_openOverlay(isInstant = false) {
|
|
232
243
|
this._panel.open(isInstant);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["glass","overlayMotion","style"],"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 overlayMotion from '@/assets/overlay-motion.css?inline'\nimport glass from '@/classes/glass.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 * 开启态 overlay(issue #120 Block 1):本组件不自行监听 keydown,只声明「我开着」,\n * 由唯一仲裁者决定一次 Escape 关谁。实例作用域的帧事务入口也在这里\n * —— 它的 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 // 建立会话的那一帧没有 handle 可作 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() 完成(handle 归它持有)。\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` trigger 的 popover 不由用户关闭,但仍是候选:Escape 被它吞掉(同时压掉\n * 原生 cancel),只是不走关闭入口:Escape 不落到下层 overlay,不会把外层一起关掉。\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 * 首个已开启 overlay 与从宿主上溯结果一致,多出的那次登记是冗余的。\n */\n this._panel.open(isInstant)\n this._syncOverlayInert()\n }\n\n private _migratableContentNodes(nodes: Node[]): Node[] {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:panel 内容是实时渲染契约,\n // 框架后续 patch 以宿主内锚点为插入基准,锚点进 panel 会让插入落空。\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 重建 panel。\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":["glass","overlayMotion","style"],"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 overlayMotion from '@/assets/overlay-motion.css?inline'\nimport glass from '@/classes/glass.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'\nimport { hasTriggerMode, normalizeTriggerSet, type OverlayTriggerMode } from '@/shared/overlay/trigger-props'\n\nimport style from './style.css?inline'\n\n/** 点击 trigger 开合,点 panel 外、失焦与 Escape 都能收。 */\nconst DEFAULT_TRIGGERS = ['click'] 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(): string {\n return this._trigger\n }\n set trigger(v: string | readonly OverlayTriggerMode[]) {\n const old = this._trigger\n this._trigger = normalizeTriggerSet(v, DEFAULT_TRIGGERS)\n this.requestUpdate('trigger', old)\n }\n private _trigger: string = DEFAULT_TRIGGERS.join(' ')\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 * 开启态 overlay(issue #120 Block 1):本组件不自行监听 keydown,只声明「我开着」,\n * 由唯一仲裁者决定一次 Escape 关谁。实例作用域的帧事务入口也在这里\n * —— 它的 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 // 建立会话的那一帧没有 handle 可作 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._clearGestureListeners()\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(handle 归它持有)。\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._clearGestureListeners()\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 (hasTriggerMode(this.trigger, 'hover')) {\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n }\n if (hasTriggerMode(this.trigger, 'focus')) this.addEventListener('focusin', this._onFocusIn)\n }\n\n private _clearGestureListeners() {\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this.removeEventListener('focusin', this._onFocusIn)\n }\n\n /*\n * `manual` trigger 的 popover 不由用户关闭,但仍是候选:Escape 被它吞掉(同时压掉\n * 原生 cancel),只是不走关闭入口:Escape 不落到下层 overlay,不会把外层一起关掉。\n * trigger 可在开启期间改写,所以走动态通道同步。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(hasTriggerMode(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 * 首个已开启 overlay 与从宿主上溯结果一致,多出的那次登记是冗余的。\n */\n this._panel.open(isInstant)\n this._syncOverlayInert()\n }\n\n private _migratableContentNodes(nodes: Node[]): Node[] {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:panel 内容是实时渲染契约,\n // 框架后续 patch 以宿主内锚点为插入基准,锚点进 panel 会让插入落空。\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 重建 panel。\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 this._queryTrigger()?.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 // manual 保留点击切换:它的语义是「不接受任何自动收起」,不是「不接受用户打开」。\n if (!hasTriggerMode(this.trigger, 'click') && !hasTriggerMode(this.trigger, 'manual')) 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 (!hasTriggerMode(this.trigger, 'click')) 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 _onFocusIn = (event: FocusEvent) => {\n if (this.disabled) return\n if (this.open) return\n\n const focusedElement = event.composedPath()[0] ?? event.target\n if (!(focusedElement instanceof Element) || !focusedElement.matches(':focus-visible')) return\n\n this._shouldOpenInstantly = true\n this._userOpenChange.mark()\n this.show()\n }\n\n private _onFocusOut = () => {\n // click 与 focus 都随焦点离开收起;hover 与 manual 不收起(后者不接受自动开合)。\n if (!hasTriggerMode(this.trigger, 'click') && !hasTriggerMode(this.trigger, 'focus')) 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 || !hasTriggerMode(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 || !hasTriggerMode(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 (!hasTriggerMode(this.trigger, 'hover')) return\n clearTimeout(this._hideTimer)\n }\n\n private _onPanelPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!hasTriggerMode(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
|
// src/components/popover/style.css?inline
|
|
2
|
-
var style_default = "*,: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,
|
|
2
|
+
var style_default = "*,: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,10);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,#0071e3) 40%, transparent));outline-offset:2px}.popover-panel.portal{z-index:var(--wui-layer-menu,1000);position:fixed}:host([portal]) .popover-panel{display:none}\n";
|
|
3
3
|
export { style_default as default };
|
|
4
4
|
|
|
5
5
|
//# sourceMappingURL=style.js.map
|
|
@@ -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\n /* panel 宽远大于角半径,环底色铺出的整圈铺底会在长边中段读成一条比四角更重的\n 直边描边;转 transparent 后只剩四段角弧,见 menu-portal.css 同处注释。 */\n --wui-color-glass-ring: transparent;\n position: absolute;\n z-index: var(--wui-layer-inline-overlay,
|
|
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 /* panel 宽远大于角半径,环底色铺出的整圈铺底会在长边中段读成一条比四角更重的\n 直边描边;转 transparent 后只剩四段角弧,见 menu-portal.css 同处注释。 */\n --wui-color-glass-ring: transparent;\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 10);\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 在 panel 自身,这里覆盖其默认玻璃底为 menu surface 色 */\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, #0071e3) 40%, transparent));\n outline-offset: 2px;\n }\n}\n\n.popover-panel.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 1000);\n}\n\n:host([portal]) .popover-panel {\n display: none;\n}\n"],"mappings":";AAAA,IAAA,gBAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* 线性进度指示。宿主本身承担 `progressbar` 语义,numeric props 写入后始终按 `0..max` 暴露。
|
|
4
|
+
*
|
|
5
|
+
* @csspart base - 轨道与可选数值组成的网格
|
|
6
|
+
* @csspart track - 进度槽
|
|
7
|
+
* @csspart indicator - 已完成部分
|
|
8
|
+
* @csspart value - `show-value` 时的可见百分比文本
|
|
9
|
+
*/
|
|
10
|
+
export declare class WebUiProgress extends LitElement {
|
|
11
|
+
static styles: import("lit").CSSResult;
|
|
12
|
+
set value(value: number);
|
|
13
|
+
get value(): number;
|
|
14
|
+
private _value;
|
|
15
|
+
set max(value: number);
|
|
16
|
+
get max(): number;
|
|
17
|
+
private _max;
|
|
18
|
+
indeterminate: boolean;
|
|
19
|
+
showValue: boolean;
|
|
20
|
+
connectedCallback(): void;
|
|
21
|
+
protected updated(): void;
|
|
22
|
+
private _syncAria;
|
|
23
|
+
render(): import("lit").TemplateResult<1>;
|
|
24
|
+
}
|
|
25
|
+
declare global {
|
|
26
|
+
interface HTMLElementTagNameMap {
|
|
27
|
+
'web-ui-progress': WebUiProgress;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/progress/index.ts"],"mappings":";;;;;;;;;qBAoBa,sBAAsB;SACjB,sBAAM;MAGlB,MAAM;MAWN;UAII;MAGJ,IAAI;MAYJ;UAII;EAEoC;EACyB;EAE5D;YAKU;UAUX;EAgBC,wBAAM;;QAqBT;YACI;IACR,mBAAmB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
|
|
2
|
+
import { normalizeNumber } from "../../shared/normalize/index.js";
|
|
3
|
+
import { resolveBuiltinLabel } from "../../shared/locale/builtin-labels.js";
|
|
4
|
+
import style_default from "./style.js";
|
|
5
|
+
import { LitElement, html, unsafeCSS } from "lit";
|
|
6
|
+
import { customElement, property } from "lit/decorators.js";
|
|
7
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
8
|
+
// src/components/progress/index.ts
|
|
9
|
+
const MAX_SAFE = Number.MAX_SAFE_INTEGER;
|
|
10
|
+
let WebUiProgress = class WebUiProgress extends LitElement {
|
|
11
|
+
constructor(..._args) {
|
|
12
|
+
super(..._args);
|
|
13
|
+
this._value = 0;
|
|
14
|
+
this._max = 100;
|
|
15
|
+
this.indeterminate = false;
|
|
16
|
+
this.showValue = false;
|
|
17
|
+
}
|
|
18
|
+
static {
|
|
19
|
+
this.styles = unsafeCSS(style_default);
|
|
20
|
+
}
|
|
21
|
+
set value(value) {
|
|
22
|
+
const normalized = normalizeNumber(value, 0, MAX_SAFE, 0);
|
|
23
|
+
if (this._value === normalized) return;
|
|
24
|
+
const old = this.value;
|
|
25
|
+
this._value = normalized;
|
|
26
|
+
this.requestUpdate("value", old);
|
|
27
|
+
if (this.getAttribute("value") !== String(normalized)) this.setAttribute("value", String(normalized));
|
|
28
|
+
}
|
|
29
|
+
get value() {
|
|
30
|
+
return Math.min(this._value, this._max);
|
|
31
|
+
}
|
|
32
|
+
set max(value) {
|
|
33
|
+
const normalized = typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(MAX_SAFE, value) : 100;
|
|
34
|
+
if (this._max === normalized) return;
|
|
35
|
+
const old = this._max;
|
|
36
|
+
this._max = normalized;
|
|
37
|
+
this.requestUpdate("max", old);
|
|
38
|
+
if (this.getAttribute("max") !== String(normalized)) this.setAttribute("max", String(normalized));
|
|
39
|
+
}
|
|
40
|
+
get max() {
|
|
41
|
+
return this._max;
|
|
42
|
+
}
|
|
43
|
+
connectedCallback() {
|
|
44
|
+
super.connectedCallback();
|
|
45
|
+
this._syncAria();
|
|
46
|
+
}
|
|
47
|
+
updated() {
|
|
48
|
+
if (this._value > this._max) {
|
|
49
|
+
const old = this._value;
|
|
50
|
+
this._value = this._max;
|
|
51
|
+
this.requestUpdate("value", old);
|
|
52
|
+
this.setAttribute("value", String(this._max));
|
|
53
|
+
}
|
|
54
|
+
this._syncAria();
|
|
55
|
+
}
|
|
56
|
+
_syncAria() {
|
|
57
|
+
this.setAttribute("role", "progressbar");
|
|
58
|
+
this.setAttribute("aria-valuemin", "0");
|
|
59
|
+
this.setAttribute("aria-valuemax", String(this.max));
|
|
60
|
+
if (this.indeterminate) this.removeAttribute("aria-valuenow");
|
|
61
|
+
else this.setAttribute("aria-valuenow", String(this.value));
|
|
62
|
+
if (!this.getAttribute("aria-label")?.trim() && !this.getAttribute("aria-labelledby")?.trim()) this.setAttribute("aria-label", resolveBuiltinLabel("progress"));
|
|
63
|
+
}
|
|
64
|
+
render() {
|
|
65
|
+
const percent = this.value / this.max * 100;
|
|
66
|
+
const valueText = this.indeterminate ? "…" : `${Math.round(percent)}%`;
|
|
67
|
+
return html`
|
|
68
|
+
<div class="wui-progress" part="base">
|
|
69
|
+
<div class="wui-progress-track" part="track">
|
|
70
|
+
<div
|
|
71
|
+
class="wui-progress-indicator"
|
|
72
|
+
part="indicator"
|
|
73
|
+
style=${styleMap({ "--wui-progress-percent": `${percent}%` })}
|
|
74
|
+
></div>
|
|
75
|
+
</div>
|
|
76
|
+
<span class="wui-progress-value" part="value" aria-hidden="true" ?hidden=${!this.showValue}>
|
|
77
|
+
${valueText}
|
|
78
|
+
</span>
|
|
79
|
+
</div>
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
__decorate([property({
|
|
84
|
+
type: Number,
|
|
85
|
+
reflect: true
|
|
86
|
+
})], WebUiProgress.prototype, "value", null);
|
|
87
|
+
__decorate([property({
|
|
88
|
+
type: Number,
|
|
89
|
+
reflect: true
|
|
90
|
+
})], WebUiProgress.prototype, "max", null);
|
|
91
|
+
__decorate([property({
|
|
92
|
+
type: Boolean,
|
|
93
|
+
reflect: true
|
|
94
|
+
})], WebUiProgress.prototype, "indeterminate", void 0);
|
|
95
|
+
__decorate([property({
|
|
96
|
+
type: Boolean,
|
|
97
|
+
reflect: true,
|
|
98
|
+
attribute: "show-value"
|
|
99
|
+
})], WebUiProgress.prototype, "showValue", void 0);
|
|
100
|
+
WebUiProgress = __decorate([customElement("web-ui-progress")], WebUiProgress);
|
|
101
|
+
export { WebUiProgress };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["style"],"sources":["../../../src/components/progress/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport { resolveBuiltinLabel } from '@/shared/locale/builtin-labels'\nimport { normalizeNumber } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst MAX_SAFE = Number.MAX_SAFE_INTEGER\n\n/**\n * 线性进度指示。宿主本身承担 `progressbar` 语义,numeric props 写入后始终按 `0..max` 暴露。\n *\n * @csspart base - 轨道与可选数值组成的网格\n * @csspart track - 进度槽\n * @csspart indicator - 已完成部分\n * @csspart value - `show-value` 时的可见百分比文本\n */\n@customElement('web-ui-progress')\nexport class WebUiProgress extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Number, reflect: true })\n set value(value: number) {\n const normalized = normalizeNumber(value, 0, MAX_SAFE, 0)\n if (this._value === normalized) return\n const old = this.value\n this._value = normalized\n this.requestUpdate('value', old)\n if (this.getAttribute('value') !== String(normalized)) {\n this.setAttribute('value', String(normalized))\n }\n }\n\n get value(): number {\n return Math.min(this._value, this._max)\n }\n\n private _value = 0\n\n @property({ type: Number, reflect: true })\n set max(value: number) {\n const normalized =\n typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.min(MAX_SAFE, value) : 100\n if (this._max === normalized) return\n const old = this._max\n this._max = normalized\n this.requestUpdate('max', old)\n if (this.getAttribute('max') !== String(normalized)) {\n this.setAttribute('max', String(normalized))\n }\n }\n\n get max(): number {\n return this._max\n }\n\n private _max = 100\n\n @property({ type: Boolean, reflect: true }) indeterminate = false\n @property({ type: Boolean, reflect: true, attribute: 'show-value' }) showValue = false\n\n override connectedCallback() {\n super.connectedCallback()\n this._syncAria()\n }\n\n protected override updated() {\n if (this._value > this._max) {\n const old = this._value\n this._value = this._max\n this.requestUpdate('value', old)\n this.setAttribute('value', String(this._max))\n }\n this._syncAria()\n }\n\n private _syncAria() {\n this.setAttribute('role', 'progressbar')\n this.setAttribute('aria-valuemin', '0')\n this.setAttribute('aria-valuemax', String(this.max))\n\n if (this.indeterminate) {\n this.removeAttribute('aria-valuenow')\n } else {\n this.setAttribute('aria-valuenow', String(this.value))\n }\n\n if (!this.getAttribute('aria-label')?.trim() && !this.getAttribute('aria-labelledby')?.trim()) {\n this.setAttribute('aria-label', resolveBuiltinLabel('progress'))\n }\n }\n\n override render() {\n const percent = (this.value / this.max) * 100\n const valueText = this.indeterminate ? '…' : `${Math.round(percent)}%`\n\n return html`\n <div class=\"wui-progress\" part=\"base\">\n <div class=\"wui-progress-track\" part=\"track\">\n <div\n class=\"wui-progress-indicator\"\n part=\"indicator\"\n style=${styleMap({ '--wui-progress-percent': `${percent}%` })}\n ></div>\n </div>\n <span class=\"wui-progress-value\" part=\"value\" aria-hidden=\"true\" ?hidden=${!this.showValue}>\n ${valueText}\n </span>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-progress': WebUiProgress\n }\n}\n"],"mappings":";;;;;;;;AASA,MAAM,WAAW,OAAO;AAWjB,IAAM,gBAAN,MAAM,sBAAsB,WAAW;;;EAmB3B,KAAA,SAAA;EAmBF,KAAA,OAAA;EAE6C,KAAA,gBAAA;EACqB,KAAA,YAAA;;;EAxCxD,KAAA,SAAA,UAAUA,aAAK;;CAExC,IACI,MAAM,OAAe;EACvB,MAAM,aAAa,gBAAgB,OAAO,GAAG,UAAU,CAAC;EACxD,IAAI,KAAK,WAAW,YAAY;EAChC,MAAM,MAAM,KAAK;EACjB,KAAK,SAAS;EACd,KAAK,cAAc,SAAS,GAAG;EAC/B,IAAI,KAAK,aAAa,OAAO,MAAM,OAAO,UAAU,GAClD,KAAK,aAAa,SAAS,OAAO,UAAU,CAAC;CAEjD;CAEA,IAAI,QAAgB;EAClB,OAAO,KAAK,IAAI,KAAK,QAAQ,KAAK,IAAI;CACxC;CAIA,IACI,IAAI,OAAe;EACrB,MAAM,aACJ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,UAAU,KAAK,IAAI;EACjG,IAAI,KAAK,SAAS,YAAY;EAC9B,MAAM,MAAM,KAAK;EACjB,KAAK,OAAO;EACZ,KAAK,cAAc,OAAO,GAAG;EAC7B,IAAI,KAAK,aAAa,KAAK,MAAM,OAAO,UAAU,GAChD,KAAK,aAAa,OAAO,OAAO,UAAU,CAAC;CAE/C;CAEA,IAAI,MAAc;EAChB,OAAO,KAAK;CACd;CAOA,oBAA6B;EAC3B,MAAM,kBAAkB;EACxB,KAAK,UAAU;CACjB;CAEA,UAA6B;EAC3B,IAAI,KAAK,SAAS,KAAK,MAAM;GAC3B,MAAM,MAAM,KAAK;GACjB,KAAK,SAAS,KAAK;GACnB,KAAK,cAAc,SAAS,GAAG;GAC/B,KAAK,aAAa,SAAS,OAAO,KAAK,IAAI,CAAC;EAC9C;EACA,KAAK,UAAU;CACjB;CAEA,YAAoB;EAClB,KAAK,aAAa,QAAQ,aAAa;EACvC,KAAK,aAAa,iBAAiB,GAAG;EACtC,KAAK,aAAa,iBAAiB,OAAO,KAAK,GAAG,CAAC;EAEnD,IAAI,KAAK,eACP,KAAK,gBAAgB,eAAe;OAEpC,KAAK,aAAa,iBAAiB,OAAO,KAAK,KAAK,CAAC;EAGvD,IAAI,CAAC,KAAK,aAAa,YAAY,CAAC,EAAE,KAAK,KAAK,CAAC,KAAK,aAAa,iBAAiB,CAAC,EAAE,KAAK,GAC1F,KAAK,aAAa,cAAc,oBAAoB,UAAU,CAAC;CAEnE;CAEA,SAAkB;EAChB,MAAM,UAAW,KAAK,QAAQ,KAAK,MAAO;EAC1C,MAAM,YAAY,KAAK,gBAAgB,MAAM,GAAG,KAAK,MAAM,OAAO,EAAE;EAEpE,OAAO,IAAI;;;;;;oBAMK,SAAS,EAAE,0BAA0B,GAAG,QAAQ,GAAG,CAAC,EAAE;;;mFAGS,CAAC,KAAK,UAAU;YACvF,UAAU;;;;CAIpB;AACF;AA1FG,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,cAAA,WAAA,SAAA,IAAA;AAkBxC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,cAAA,WAAA,OAAA,IAAA;AAmBxC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,cAAA,WAAA,iBAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAa,CAAC,CAAA,GAAA,cAAA,WAAA,aAAA,KAAA,CAAA;AA1CpE,gBAAA,WAAA,CAAA,cAAc,iBAAiB,CAAA,GAAA,aAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// src/components/progress/style.css?inline
|
|
2
|
+
var style_default = "*,:before,:after{box-sizing:border-box}:host{width:100%;min-width:0;display:block}.wui-progress{gap:var(--wui-space-2,8px);grid-template-columns:minmax(0,1fr) auto;align-items:center;display:grid}.wui-progress-track{width:100%;height:var(--wui-progress-height,8px);border-radius:var(--wui-progress-radius,var(--wui-radius-control,calc(infinity * 1px)));background-color:var(--wui-progress-track-color,var(--wui-color-surface-track,#e5e5ea));overflow:hidden}.wui-progress-indicator{width:var(--wui-progress-percent,0%);border-radius:inherit;background-color:var(--wui-progress-fill-color,var(--wui-color-accent,#0071e3));height:100%;transition:width var(--wui-duration-trigger,.16s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}:host([indeterminate]) .wui-progress-indicator{width:38%;animation:wui-progress-indeterminate var(--wui-progress-indeterminate-duration,var(--wui-duration-spinner,.8s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)) infinite}.wui-progress-value{min-width:3ch;font-size:var(--wui-font-size-caption,12px);font-variant-numeric:tabular-nums;color:var(--wui-color-text,#1b1b1b);text-align:end;line-height:1}@keyframes wui-progress-indeterminate{0%{transform:translate(-120%)}to{transform:translate(360%)}}\n";
|
|
3
|
+
export { style_default as default };
|
|
4
|
+
|
|
5
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/progress/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n width: 100%;\n min-width: 0;\n}\n\n.wui-progress {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n}\n\n.wui-progress-track {\n overflow: hidden;\n\n width: 100%;\n height: var(--wui-progress-height, 8px);\n border-radius: var(--wui-progress-radius, var(--wui-radius-control, calc(infinity * 1px)));\n\n background-color: var(--wui-progress-track-color, var(--wui-color-surface-track, #e5e5ea));\n}\n\n.wui-progress-indicator {\n width: var(--wui-progress-percent, 0%);\n height: 100%;\n border-radius: inherit;\n\n background-color: var(--wui-progress-fill-color, var(--wui-color-accent, #0071e3));\n\n transition: width var(--wui-duration-trigger, 160ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n:host([indeterminate]) .wui-progress-indicator {\n width: 38%;\n animation: wui-progress-indeterminate var(--wui-progress-indeterminate-duration, var(--wui-duration-spinner, 800ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)) infinite;\n}\n\n.wui-progress-value {\n min-width: 3ch;\n\n font-size: var(--wui-font-size-caption, 12px);\n font-variant-numeric: tabular-nums;\n line-height: 1;\n color: var(--wui-color-text, #1b1b1b);\n text-align: end;\n}\n\n@keyframes wui-progress-indeterminate {\n from {\n transform: translate3d(-120%, 0, 0);\n }\n\n to {\n transform: translate3d(360%, 0, 0);\n }\n}\n"],"mappings":";AAAA,IAAA,gBAAA"}
|
|
@@ -4,6 +4,8 @@ export declare class WebUiSegmentedTrigger extends LitElement {
|
|
|
4
4
|
value: string;
|
|
5
5
|
checked: boolean;
|
|
6
6
|
disabled: boolean;
|
|
7
|
+
/** 纯图标 trigger 的可访问名;会转发到内部 `role="option"`。 */
|
|
8
|
+
ariaLabel: string | null;
|
|
7
9
|
private readonly _groupManagement;
|
|
8
10
|
private get _isDisabled();
|
|
9
11
|
private get _isManagedByGroup();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/segmented-trigger/index.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/segmented-trigger/index.ts"],"mappings":";qBAaa,8BAA8B;SACzB,sBAAM;EAEM;EACgB;EACA;;EAEkB;mBAE7C;cAML;cAIA;UAIJ;UAUA;EAOC,wBAAM;WAuBE;IACf,QAAQ;;;QAIJ;YACI;IACR,4BAA4B"}
|
|
@@ -5,6 +5,7 @@ import style_default from "./style.js";
|
|
|
5
5
|
import { LitElement, html, unsafeCSS } from "lit";
|
|
6
6
|
import { customElement, property } from "lit/decorators.js";
|
|
7
7
|
import { classMap } from "lit/directives/class-map.js";
|
|
8
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
8
9
|
// src/components/segmented-trigger/index.ts
|
|
9
10
|
installPointerFocusSuppression();
|
|
10
11
|
let WebUiSegmentedTrigger = class WebUiSegmentedTrigger extends LitElement {
|
|
@@ -13,6 +14,7 @@ let WebUiSegmentedTrigger = class WebUiSegmentedTrigger extends LitElement {
|
|
|
13
14
|
this.value = "";
|
|
14
15
|
this.checked = false;
|
|
15
16
|
this.disabled = false;
|
|
17
|
+
this.ariaLabel = null;
|
|
16
18
|
this._groupManagement = defineGroupManaged(this, {
|
|
17
19
|
context: selectionGroupContextKey,
|
|
18
20
|
requestUpdate: () => this.requestUpdate(),
|
|
@@ -57,6 +59,7 @@ let WebUiSegmentedTrigger = class WebUiSegmentedTrigger extends LitElement {
|
|
|
57
59
|
class=${classMap(cls)}
|
|
58
60
|
tabindex=${this._isDisabled || this._groupManagement.getContext()?.tabStop === false ? "-1" : "0"}
|
|
59
61
|
role="option"
|
|
62
|
+
aria-label=${ifDefined(this.ariaLabel ?? void 0)}
|
|
60
63
|
aria-selected=${String(this.checked)}
|
|
61
64
|
aria-disabled=${String(this._isDisabled)}
|
|
62
65
|
@click=${this.handleClick}
|
|
@@ -76,6 +79,10 @@ __decorate([property({
|
|
|
76
79
|
type: Boolean,
|
|
77
80
|
reflect: true
|
|
78
81
|
})], WebUiSegmentedTrigger.prototype, "disabled", void 0);
|
|
82
|
+
__decorate([property({
|
|
83
|
+
type: String,
|
|
84
|
+
attribute: "aria-label"
|
|
85
|
+
})], WebUiSegmentedTrigger.prototype, "ariaLabel", void 0);
|
|
79
86
|
WebUiSegmentedTrigger = __decorate([customElement("web-ui-segmented-trigger")], WebUiSegmentedTrigger);
|
|
80
87
|
export { WebUiSegmentedTrigger };
|
|
81
88
|
|