移动目录
This commit is contained in:
147
mdui_patched/components/tooltip/index.d.ts
vendored
Normal file
147
mdui_patched/components/tooltip/index.d.ts
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
import '@mdui/jq/methods/css.js';
|
||||
import '@mdui/jq/methods/filter.js';
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import '@mdui/jq/methods/prop.js';
|
||||
import '@mdui/jq/methods/width.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, TemplateResult, PropertyValues } from 'lit';
|
||||
/**
|
||||
* @summary 工具提示组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-tooltip content="tooltip content">
|
||||
* ..<mdui-button>button</mdui-button>
|
||||
* </mdui-tooltip>
|
||||
* ```
|
||||
*
|
||||
* @event open - tooltip 开始显示时,事件被触发。可以通过调用 `event.preventDefault()` 阻止 tooltip 打开
|
||||
* @event opened - tooltip 显示动画完成时,事件被触发
|
||||
* @event close - tooltip 开始隐藏时,事件被触发。可以通过调用 `event.preventDefault()` 阻止 tooltip 关闭
|
||||
* @event closed - tooltip 隐藏动画完成时,事件被触发
|
||||
*
|
||||
* @slot - tooltip 触发的目标元素,只有 `default` slot 中的第一个元素会作为目标元素
|
||||
* @slot headline - tooltip 的标题,只有当 `variant="rich"` 时,此 slot 才有效
|
||||
* @slot content - tooltip 的内容,可以包含 HTML。若只包含纯文本,可以使用 `content` 属性代替
|
||||
* @slot action - tooltip 底部的按钮,只有当 `variant="rich"` 时,此 slot 才有效
|
||||
*
|
||||
* @csspart popup - tooltip 的容器
|
||||
* @csspart headline - 标题
|
||||
* @csspart content - 正文
|
||||
* @csspart action - 操作按钮
|
||||
*
|
||||
* @cssprop --shape-corner-plain - 当 variant="plain" 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-rich - 当 variant="rich" 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
export declare class Tooltip extends MduiElement<TooltipEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* tooltip 的形状。默认为 `plain`。可选值包括:
|
||||
*
|
||||
* * `plain`:纯文本,适用于简单的单行文本
|
||||
* * `rich`:富文本,可以包含标题、正文和操作按钮
|
||||
*/
|
||||
variant: /*纯文本,适用于简单的单行文本*/ 'plain' | /*富文本,可以包含标题、正文和操作按钮*/ 'rich';
|
||||
/**
|
||||
* tooltip 的位置。默认为 `auto`。可选值包括:
|
||||
*
|
||||
* * `auto`:自动判断位置。`variant="plain"` 时,优先使用 `top`;`variant="rich"` 时,优先使用 `bottom-right`
|
||||
* * `top-left`:位于左上方
|
||||
* * `top-start`:位于上方,左对齐
|
||||
* * `top`:位于上方,居中对齐
|
||||
* * `top-end`:位于上方,右对齐
|
||||
* * `top-right`:位于右上方
|
||||
* * `bottom-left`:位于左下方
|
||||
* * `bottom-start`:位于下方,左对齐
|
||||
* * `bottom`:位于下方,居中对齐
|
||||
* * `bottom-end`:位于下方,右对齐
|
||||
* * `bottom-right`:位于右下方
|
||||
* * `left-start`:位于左侧,顶部对齐
|
||||
* * `left`:位于左侧,居中对齐
|
||||
* * `left-end`:位于左侧,底部对齐
|
||||
* * `right-start`:位于右侧,顶部对齐
|
||||
* * `right`:位于右侧,居中对齐
|
||||
* * `right-end`:位于右侧,底部对齐
|
||||
*/
|
||||
placement: /*自动判断位置*/ 'auto' | /*位于左上方*/ 'top-left' | /*位于上方,左对齐*/ 'top-start' | /*位于上方,居中对齐*/ 'top' | /*位于上方,右对齐*/ 'top-end' | /*位于右上方*/ 'top-right' | /*位于左下方*/ 'bottom-left' | /*位于下方,左对齐*/ 'bottom-start' | /*位于下方,居中对齐*/ 'bottom' | /*位于下方,右对齐*/ 'bottom-end' | /*位于右下方*/ 'bottom-right' | /*位于左侧,顶部对齐*/ 'left-start' | /*位于左侧,居中对齐*/ 'left' | /*位于左侧,底部对齐*/ 'left-end' | /*位于右侧,顶部对齐*/ 'right-start' | /*位于右侧,居中对齐*/ 'right' | /*位于右侧,底部对齐*/ 'right-end';
|
||||
/**
|
||||
* 鼠标悬浮触发显示的延时,单位为毫秒
|
||||
*/
|
||||
openDelay: number;
|
||||
/**
|
||||
* 鼠标悬浮触发隐藏的延时,单位为毫秒
|
||||
*/
|
||||
closeDelay: number;
|
||||
/**
|
||||
* tooltip 的标题。仅 `variant="rich"` 时可使用。也可以通过 `slot="headline"` 设置
|
||||
*/
|
||||
headline?: string;
|
||||
/**
|
||||
* tooltip 的内容。也可以通过 `slot="content"` 设置
|
||||
*/
|
||||
content?: string;
|
||||
/**
|
||||
* 触发方式,支持多个值,用空格分隔。可选值包括:
|
||||
*
|
||||
* * `click`:点击时触发
|
||||
* * `hover`:鼠标悬浮时触发
|
||||
* * `focus`:聚焦时触发
|
||||
* * `manual`:只能通过编程方式打开和关闭 tooltip,不能再指定其他触发方式
|
||||
*/
|
||||
trigger: /*点击时触发*/ 'click' | /*鼠标悬浮时触发*/ 'hover' | /*聚焦时触发*/ 'focus' | /*只能通过编程方式打开和关闭 tooltip,不能再指定其他触发方式*/ 'manual' | string;
|
||||
/**
|
||||
* 是否禁用 tooltip
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 是否显示 tooltip
|
||||
*/
|
||||
open: boolean;
|
||||
private observeResize?;
|
||||
private overflowAncestors?;
|
||||
private hoverTimeout;
|
||||
private readonly popupRef;
|
||||
private readonly hasSlotController;
|
||||
private readonly hoverController;
|
||||
private readonly definedController;
|
||||
constructor();
|
||||
/**
|
||||
* 获取第一个非 <style> 和 content slot 的子元素,作为 tooltip 的目标元素
|
||||
*/
|
||||
private get target();
|
||||
private onPositionChange;
|
||||
private onOpenChange;
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
protected firstUpdated(changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
private isRich;
|
||||
/**
|
||||
* 请求关闭 tooltip。鼠标未悬浮在 tooltip 上时,直接关闭;否则等鼠标移走再关闭
|
||||
*/
|
||||
private requestClose;
|
||||
private hasTrigger;
|
||||
private onFocus;
|
||||
private onBlur;
|
||||
private onClick;
|
||||
private onKeydown;
|
||||
private onMouseEnter;
|
||||
private onMouseLeave;
|
||||
/**
|
||||
* 在 document 上点击时,根据条件判断是否关闭 tooltip
|
||||
*/
|
||||
private onDocumentClick;
|
||||
private onWindowScroll;
|
||||
private updatePositioner;
|
||||
}
|
||||
export interface TooltipEventMap {
|
||||
open: CustomEvent<void>;
|
||||
opened: CustomEvent<void>;
|
||||
close: CustomEvent<void>;
|
||||
closed: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-tooltip': Tooltip;
|
||||
}
|
||||
}
|
||||
506
mdui_patched/components/tooltip/index.js
Normal file
506
mdui_patched/components/tooltip/index.js
Normal file
@@ -0,0 +1,506 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
import { getOverflowAncestors } from '@floating-ui/utils/dom';
|
||||
import { $ } from '@mdui/jq/$.js';
|
||||
import '@mdui/jq/methods/css.js';
|
||||
import '@mdui/jq/methods/filter.js';
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import '@mdui/jq/methods/prop.js';
|
||||
import '@mdui/jq/methods/width.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { DefinedController } from '@mdui/shared/controllers/defined.js';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { HoverController } from '@mdui/shared/controllers/hover.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { animateTo, stopAnimations } from '@mdui/shared/helpers/animate.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { getDuration, getEasing } from '@mdui/shared/helpers/motion.js';
|
||||
import { observeResize } from '@mdui/shared/helpers/observeResize.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 工具提示组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-tooltip content="tooltip content">
|
||||
* ..<mdui-button>button</mdui-button>
|
||||
* </mdui-tooltip>
|
||||
* ```
|
||||
*
|
||||
* @event open - tooltip 开始显示时,事件被触发。可以通过调用 `event.preventDefault()` 阻止 tooltip 打开
|
||||
* @event opened - tooltip 显示动画完成时,事件被触发
|
||||
* @event close - tooltip 开始隐藏时,事件被触发。可以通过调用 `event.preventDefault()` 阻止 tooltip 关闭
|
||||
* @event closed - tooltip 隐藏动画完成时,事件被触发
|
||||
*
|
||||
* @slot - tooltip 触发的目标元素,只有 `default` slot 中的第一个元素会作为目标元素
|
||||
* @slot headline - tooltip 的标题,只有当 `variant="rich"` 时,此 slot 才有效
|
||||
* @slot content - tooltip 的内容,可以包含 HTML。若只包含纯文本,可以使用 `content` 属性代替
|
||||
* @slot action - tooltip 底部的按钮,只有当 `variant="rich"` 时,此 slot 才有效
|
||||
*
|
||||
* @csspart popup - tooltip 的容器
|
||||
* @csspart headline - 标题
|
||||
* @csspart content - 正文
|
||||
* @csspart action - 操作按钮
|
||||
*
|
||||
* @cssprop --shape-corner-plain - 当 variant="plain" 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-rich - 当 variant="rich" 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
let Tooltip = class Tooltip extends MduiElement {
|
||||
constructor() {
|
||||
super();
|
||||
/**
|
||||
* tooltip 的形状。默认为 `plain`。可选值包括:
|
||||
*
|
||||
* * `plain`:纯文本,适用于简单的单行文本
|
||||
* * `rich`:富文本,可以包含标题、正文和操作按钮
|
||||
*/
|
||||
this.variant = 'plain';
|
||||
/**
|
||||
* tooltip 的位置。默认为 `auto`。可选值包括:
|
||||
*
|
||||
* * `auto`:自动判断位置。`variant="plain"` 时,优先使用 `top`;`variant="rich"` 时,优先使用 `bottom-right`
|
||||
* * `top-left`:位于左上方
|
||||
* * `top-start`:位于上方,左对齐
|
||||
* * `top`:位于上方,居中对齐
|
||||
* * `top-end`:位于上方,右对齐
|
||||
* * `top-right`:位于右上方
|
||||
* * `bottom-left`:位于左下方
|
||||
* * `bottom-start`:位于下方,左对齐
|
||||
* * `bottom`:位于下方,居中对齐
|
||||
* * `bottom-end`:位于下方,右对齐
|
||||
* * `bottom-right`:位于右下方
|
||||
* * `left-start`:位于左侧,顶部对齐
|
||||
* * `left`:位于左侧,居中对齐
|
||||
* * `left-end`:位于左侧,底部对齐
|
||||
* * `right-start`:位于右侧,顶部对齐
|
||||
* * `right`:位于右侧,居中对齐
|
||||
* * `right-end`:位于右侧,底部对齐
|
||||
*/
|
||||
this.placement = 'auto';
|
||||
/**
|
||||
* 鼠标悬浮触发显示的延时,单位为毫秒
|
||||
*/
|
||||
this.openDelay = 150;
|
||||
/**
|
||||
* 鼠标悬浮触发隐藏的延时,单位为毫秒
|
||||
*/
|
||||
this.closeDelay = 150;
|
||||
/**
|
||||
* 触发方式,支持多个值,用空格分隔。可选值包括:
|
||||
*
|
||||
* * `click`:点击时触发
|
||||
* * `hover`:鼠标悬浮时触发
|
||||
* * `focus`:聚焦时触发
|
||||
* * `manual`:只能通过编程方式打开和关闭 tooltip,不能再指定其他触发方式
|
||||
*/
|
||||
this.trigger = 'hover focus';
|
||||
/**
|
||||
* 是否禁用 tooltip
|
||||
*/
|
||||
this.disabled = false;
|
||||
/**
|
||||
* 是否显示 tooltip
|
||||
*/
|
||||
this.open = false;
|
||||
this.popupRef = createRef();
|
||||
this.hasSlotController = new HasSlotController(this, 'headline', 'action');
|
||||
this.hoverController = new HoverController(this, this.popupRef);
|
||||
this.definedController = new DefinedController(this, {
|
||||
needDomReady: true,
|
||||
});
|
||||
this.onDocumentClick = this.onDocumentClick.bind(this);
|
||||
this.onWindowScroll = this.onWindowScroll.bind(this);
|
||||
this.onFocus = this.onFocus.bind(this);
|
||||
this.onBlur = this.onBlur.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onKeydown = this.onKeydown.bind(this);
|
||||
this.onMouseEnter = this.onMouseEnter.bind(this);
|
||||
this.onMouseLeave = this.onMouseLeave.bind(this);
|
||||
}
|
||||
/**
|
||||
* 获取第一个非 <style> 和 content slot 的子元素,作为 tooltip 的目标元素
|
||||
*/
|
||||
get target() {
|
||||
return [...this.children].find((el) => el.tagName.toLowerCase() !== 'style' &&
|
||||
el.getAttribute('slot') !== 'content');
|
||||
}
|
||||
async onPositionChange() {
|
||||
if (this.open) {
|
||||
await this.definedController.whenDefined();
|
||||
this.updatePositioner();
|
||||
}
|
||||
}
|
||||
async onOpenChange() {
|
||||
const hasUpdated = this.hasUpdated;
|
||||
const duration = getDuration(this, 'short4');
|
||||
const easing = getEasing(this, 'standard');
|
||||
// 打开
|
||||
// 要区分是否首次渲染,首次渲染时不触发事件,不执行动画;非首次渲染,触发事件,执行动画
|
||||
if (this.open) {
|
||||
await this.definedController.whenDefined();
|
||||
// 先关闭页面中所有其他相同 variant 的 tooltip
|
||||
$(`mdui-tooltip[variant="${this.variant}"]`)
|
||||
.filter((_, element) => element !== this)
|
||||
.prop('open', false);
|
||||
if (!hasUpdated) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
if (hasUpdated) {
|
||||
const eventProceeded = this.emit('open', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await stopAnimations(this.popupRef.value);
|
||||
this.popupRef.value.hidden = false;
|
||||
this.updatePositioner();
|
||||
await animateTo(this.popupRef.value, [{ transform: 'scale(0)' }, { transform: 'scale(1)' }], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing,
|
||||
});
|
||||
if (hasUpdated) {
|
||||
this.emit('opened');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 关闭
|
||||
if (!this.open && hasUpdated) {
|
||||
const eventProceeded = this.emit('close', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
await stopAnimations(this.popupRef.value);
|
||||
await animateTo(this.popupRef.value, [{ transform: 'scale(1)' }, { transform: 'scale(0)' }], { duration, easing });
|
||||
this.popupRef.value.hidden = true;
|
||||
this.emit('closed');
|
||||
}
|
||||
}
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener('pointerdown', this.onDocumentClick);
|
||||
this.definedController.whenDefined().then(() => {
|
||||
this.overflowAncestors = getOverflowAncestors(this.target);
|
||||
this.overflowAncestors.forEach((ancestor) => {
|
||||
ancestor.addEventListener('scroll', this.onWindowScroll);
|
||||
});
|
||||
// trigger 尺寸变化时,重新调整 tooltip 的位置
|
||||
this.observeResize = observeResize(this.target, () => {
|
||||
this.updatePositioner();
|
||||
});
|
||||
});
|
||||
}
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('pointerdown', this.onDocumentClick);
|
||||
this.overflowAncestors?.forEach((ancestor) => {
|
||||
ancestor.removeEventListener('scroll', this.onWindowScroll);
|
||||
});
|
||||
this.observeResize?.unobserve();
|
||||
}
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.definedController.whenDefined().then(() => {
|
||||
const target = this.target;
|
||||
target.addEventListener('focus', this.onFocus);
|
||||
target.addEventListener('blur', this.onBlur);
|
||||
target.addEventListener('pointerdown', this.onClick);
|
||||
target.addEventListener('keydown', this.onKeydown);
|
||||
target.addEventListener('mouseenter', this.onMouseEnter);
|
||||
target.addEventListener('mouseleave', this.onMouseLeave);
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const hasHeadline = this.isRich() &&
|
||||
(this.headline || this.hasSlotController.test('headline'));
|
||||
const hasAction = this.isRich() && this.hasSlotController.test('action');
|
||||
return html `<slot></slot><div ${ref(this.popupRef)} part="popup" class="popup" hidden>${when(hasHeadline, () => html `<slot name="headline" part="headline" class="headline">${this.headline}</slot>`)}<slot name="content" part="content" class="content">${this.content}</slot>${when(hasAction, () => html `<slot name="action" part="action" class="action"></slot>`)}</div>`;
|
||||
}
|
||||
isRich() {
|
||||
return this.variant === 'rich';
|
||||
}
|
||||
/**
|
||||
* 请求关闭 tooltip。鼠标未悬浮在 tooltip 上时,直接关闭;否则等鼠标移走再关闭
|
||||
*/
|
||||
requestClose() {
|
||||
if (!this.hoverController.isHover) {
|
||||
this.open = false;
|
||||
return;
|
||||
}
|
||||
this.hoverController.onMouseLeave(() => {
|
||||
if (this.hasTrigger('hover')) {
|
||||
// 同时使用 hover focus 时,leave 比 focus 先触发,导致 leave 后触发 focus,而显示 tooltip
|
||||
// 所以延迟执行 leave
|
||||
this.hoverTimeout = window.setTimeout(() => {
|
||||
this.open = false;
|
||||
}, this.closeDelay || 50);
|
||||
}
|
||||
else {
|
||||
this.open = false;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
hasTrigger(trigger) {
|
||||
const triggers = this.trigger.split(' ');
|
||||
return triggers.includes(trigger);
|
||||
}
|
||||
onFocus() {
|
||||
if (this.disabled || this.open || !this.hasTrigger('focus')) {
|
||||
return;
|
||||
}
|
||||
this.open = true;
|
||||
}
|
||||
onBlur() {
|
||||
if (this.disabled || !this.open || !this.hasTrigger('focus')) {
|
||||
return;
|
||||
}
|
||||
this.requestClose();
|
||||
}
|
||||
onClick(e) {
|
||||
// e.button 为 0 时,为鼠标左键点击。忽略鼠标中间和右键
|
||||
if (this.disabled || e.button || !this.hasTrigger('click')) {
|
||||
return;
|
||||
}
|
||||
// 支持 hover 和 focus 触发时,点击时,不关闭 tooltip
|
||||
if (this.open && (this.hasTrigger('hover') || this.hasTrigger('focus'))) {
|
||||
return;
|
||||
}
|
||||
this.open = !this.open;
|
||||
}
|
||||
onKeydown(e) {
|
||||
if (this.disabled || !this.open || e.key !== 'Escape') {
|
||||
return;
|
||||
}
|
||||
e.stopPropagation();
|
||||
this.requestClose();
|
||||
}
|
||||
onMouseEnter() {
|
||||
if (this.disabled || this.open || !this.hasTrigger('hover')) {
|
||||
return;
|
||||
}
|
||||
if (this.openDelay) {
|
||||
window.clearTimeout(this.hoverTimeout);
|
||||
this.hoverTimeout = window.setTimeout(() => {
|
||||
this.open = true;
|
||||
}, this.openDelay);
|
||||
}
|
||||
else {
|
||||
this.open = true;
|
||||
}
|
||||
}
|
||||
onMouseLeave() {
|
||||
window.clearTimeout(this.hoverTimeout);
|
||||
if (this.disabled || !this.open || !this.hasTrigger('hover')) {
|
||||
return;
|
||||
}
|
||||
// 同时使用 hover focus 时,leave 比 focus 先触发,导致 leave 后触发 focus,而显示 tooltip
|
||||
// 所以延迟执行 leave
|
||||
this.hoverTimeout = window.setTimeout(() => {
|
||||
this.requestClose();
|
||||
}, this.closeDelay || 50);
|
||||
}
|
||||
/**
|
||||
* 在 document 上点击时,根据条件判断是否关闭 tooltip
|
||||
*/
|
||||
onDocumentClick(e) {
|
||||
if (this.disabled || !this.open) {
|
||||
return;
|
||||
}
|
||||
const path = e.composedPath();
|
||||
// 点击 tooltip 外部区域,直接关闭
|
||||
if (!path.includes(this)) {
|
||||
this.requestClose();
|
||||
}
|
||||
}
|
||||
onWindowScroll() {
|
||||
window.requestAnimationFrame(() => this.updatePositioner());
|
||||
}
|
||||
updatePositioner() {
|
||||
const $popup = $(this.popupRef.value);
|
||||
const targetMargin = this.isRich() ? 0 : 4; // 触发目标和 popup 之间的间距
|
||||
const popupMargin = 4; // popup 和视口之间的间距
|
||||
// 触发目标的位置和宽高
|
||||
const targetRect = this.target.getBoundingClientRect();
|
||||
const targetTop = targetRect.top;
|
||||
const targetLeft = targetRect.left;
|
||||
const targetHeight = targetRect.height;
|
||||
const targetWidth = targetRect.width;
|
||||
// popup 的宽高
|
||||
const popupHeight = this.popupRef.value.offsetHeight;
|
||||
const popupWidth = this.popupRef.value.offsetWidth;
|
||||
// popup 在 x 轴和 y 轴占据的空间
|
||||
const popupXSpace = popupWidth + targetMargin + popupMargin;
|
||||
const popupYSpace = popupHeight + targetMargin + popupMargin;
|
||||
let transformOriginX;
|
||||
let transformOriginY;
|
||||
let top;
|
||||
let left;
|
||||
let placement = this.placement;
|
||||
// 自动判断 popup 方位
|
||||
if (placement === 'auto') {
|
||||
const $window = $(window);
|
||||
const hasTopSpace = targetTop > popupYSpace;
|
||||
const hasBottomSpace = $window.height() - targetTop - targetHeight > popupYSpace;
|
||||
const hasLeftSpace = targetLeft > popupXSpace;
|
||||
const hasRightSpace = $window.width() - targetLeft - targetWidth > popupXSpace;
|
||||
// rich 优先级为 bottom-right > bottom-left > top-right > top-left >
|
||||
// bottom > top > right > left
|
||||
if (this.isRich()) {
|
||||
placement = 'bottom-right';
|
||||
if (hasBottomSpace && hasRightSpace) {
|
||||
placement = 'bottom-right';
|
||||
}
|
||||
else if (hasBottomSpace && hasLeftSpace) {
|
||||
placement = 'bottom-left';
|
||||
}
|
||||
else if (hasTopSpace && hasRightSpace) {
|
||||
placement = 'top-right';
|
||||
}
|
||||
else if (hasTopSpace && hasLeftSpace) {
|
||||
placement = 'top-left';
|
||||
}
|
||||
else if (hasBottomSpace) {
|
||||
placement = 'bottom';
|
||||
}
|
||||
else if (hasTopSpace) {
|
||||
placement = 'top';
|
||||
}
|
||||
else if (hasRightSpace) {
|
||||
placement = 'right';
|
||||
}
|
||||
else if (hasLeftSpace) {
|
||||
placement = 'left';
|
||||
}
|
||||
}
|
||||
// plain 优先级为 top > bottom > left > right
|
||||
else {
|
||||
placement = 'top';
|
||||
if (hasTopSpace) {
|
||||
placement = 'top';
|
||||
}
|
||||
else if (hasBottomSpace) {
|
||||
placement = 'bottom';
|
||||
}
|
||||
else if (hasLeftSpace) {
|
||||
placement = 'left';
|
||||
}
|
||||
else if (hasRightSpace) {
|
||||
placement = 'right';
|
||||
}
|
||||
}
|
||||
}
|
||||
// 根据 placement 计算 popup 的位置和方向
|
||||
const [position, alignment] = placement.split('-');
|
||||
switch (position) {
|
||||
case 'top':
|
||||
transformOriginY = 'bottom';
|
||||
top = targetTop - popupHeight - targetMargin;
|
||||
break;
|
||||
case 'bottom':
|
||||
transformOriginY = 'top';
|
||||
top = targetTop + targetHeight + targetMargin;
|
||||
break;
|
||||
default:
|
||||
transformOriginY = 'center';
|
||||
switch (alignment) {
|
||||
case 'start':
|
||||
top = targetTop;
|
||||
break;
|
||||
case 'end':
|
||||
top = targetTop + targetHeight - popupHeight;
|
||||
break;
|
||||
default:
|
||||
top = targetTop + targetHeight / 2 - popupHeight / 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (position) {
|
||||
case 'left':
|
||||
transformOriginX = 'right';
|
||||
left = targetLeft - popupWidth - targetMargin;
|
||||
break;
|
||||
case 'right':
|
||||
transformOriginX = 'left';
|
||||
left = targetLeft + targetWidth + targetMargin;
|
||||
break;
|
||||
default:
|
||||
transformOriginX = 'center';
|
||||
switch (alignment) {
|
||||
case 'start':
|
||||
left = targetLeft;
|
||||
break;
|
||||
case 'end':
|
||||
left = targetLeft + targetWidth - popupWidth;
|
||||
break;
|
||||
case 'left':
|
||||
transformOriginX = 'right';
|
||||
left = targetLeft - popupWidth - targetMargin;
|
||||
break;
|
||||
case 'right':
|
||||
transformOriginX = 'left';
|
||||
left = targetLeft + targetWidth + targetMargin;
|
||||
break;
|
||||
default:
|
||||
left = targetLeft + targetWidth / 2 - popupWidth / 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$popup.css({
|
||||
top,
|
||||
left,
|
||||
transformOrigin: [transformOriginX, transformOriginY].join(' '),
|
||||
});
|
||||
}
|
||||
};
|
||||
Tooltip.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Tooltip.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Tooltip.prototype, "placement", void 0);
|
||||
__decorate([
|
||||
property({ type: Number, reflect: true, attribute: 'open-delay' })
|
||||
], Tooltip.prototype, "openDelay", void 0);
|
||||
__decorate([
|
||||
property({ type: Number, reflect: true, attribute: 'close-delay' })
|
||||
], Tooltip.prototype, "closeDelay", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Tooltip.prototype, "headline", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Tooltip.prototype, "content", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Tooltip.prototype, "trigger", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Tooltip.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Tooltip.prototype, "open", void 0);
|
||||
__decorate([
|
||||
watch('placement', true),
|
||||
watch('content', true)
|
||||
], Tooltip.prototype, "onPositionChange", null);
|
||||
__decorate([
|
||||
watch('open')
|
||||
], Tooltip.prototype, "onOpenChange", null);
|
||||
Tooltip = __decorate([
|
||||
customElement('mdui-tooltip')
|
||||
], Tooltip);
|
||||
export { Tooltip };
|
||||
1
mdui_patched/components/tooltip/style.d.ts
vendored
Normal file
1
mdui_patched/components/tooltip/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/tooltip/style.js
Normal file
2
mdui_patched/components/tooltip/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner-plain:var(--mdui-shape-corner-extra-small);--shape-corner-rich:var(--mdui-shape-corner-medium);--z-index:2500;display:contents}.popup{position:fixed;display:flex;flex-direction:column;z-index:var(--z-index);border-radius:var(--shape-corner-plain);background-color:rgb(var(--mdui-color-inverse-surface));padding:0 .5rem;min-width:1.75rem;max-width:20rem}:host([variant=rich]) .popup{border-radius:var(--shape-corner-rich);background-color:rgb(var(--mdui-color-surface-container));box-shadow:var(--mdui-elevation-level2);padding:.75rem 1rem .5rem 1rem}.headline{display:flex;color:rgb(var(--mdui-color-on-surface-variant));font-size:var(--mdui-typescale-title-small-size);font-weight:var(--mdui-typescale-title-small-weight);letter-spacing:var(--mdui-typescale-title-small-tracking);line-height:var(--mdui-typescale-title-small-line-height)}.content{display:flex;padding:.25rem 0;color:rgb(var(--mdui-color-inverse-on-surface));font-size:var(--mdui-typescale-body-small-size);font-weight:var(--mdui-typescale-body-small-weight);letter-spacing:var(--mdui-typescale-body-small-tracking);line-height:var(--mdui-typescale-body-small-line-height)}:host([variant=rich]) .content{color:rgb(var(--mdui-color-on-surface-variant));font-size:var(--mdui-typescale-body-medium-size);font-weight:var(--mdui-typescale-body-medium-weight);letter-spacing:var(--mdui-typescale-body-medium-tracking);line-height:var(--mdui-typescale-body-medium-line-height)}.action{display:flex;justify-content:flex-start;padding-top:.5rem}.action ::slotted(:not(:last-child)){margin-right:.5rem}`;
|
||||
Reference in New Issue
Block a user