fix: 本地 patch MDUI 以解决 tabindex = 0 导致的一系列玄学问题

This commit is contained in:
CrescentLeaf
2025-10-04 11:07:03 +08:00
parent af694f6f6c
commit 6e164cbdfb
480 changed files with 94389 additions and 0 deletions

View File

@@ -0,0 +1 @@
export declare const topAppBarStyle: import("lit").CSSResult;

View File

@@ -0,0 +1,2 @@
import { css } from 'lit';
export const topAppBarStyle = css `:host{--shape-corner:var(--mdui-shape-corner-none);--z-index:2000;position:fixed;top:0;right:0;left:0;display:flex;flex:0 0 auto;align-items:flex-start;justify-content:flex-start;border-bottom-left-radius:var(--shape-corner);border-bottom-right-radius:var(--shape-corner);z-index:var(--z-index);transition:top var(--mdui-motion-duration-long2) var(--mdui-motion-easing-standard),height var(--mdui-motion-duration-long2) var(--mdui-motion-easing-standard),box-shadow var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear),background-color var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear);padding:.75rem .5rem;height:4rem;background-color:rgb(var(--mdui-color-surface))}:host([scroll-target]:not([scroll-target=''])){position:absolute}:host([scroll-behavior~=shrink]){transition-duration:var(--mdui-motion-duration-short4)}:host([scrolling]){background-color:rgb(var(--mdui-color-surface-container));box-shadow:var(--mdui-elevation-level2)}::slotted(mdui-button-icon){color:rgb(var(--mdui-color-on-surface-variant));font-size:1.5rem}::slotted(mdui-button-icon:first-child){color:rgb(var(--mdui-color-on-surface))}::slotted(mdui-avatar){width:1.875rem;height:1.875rem;margin-top:.3125rem;margin-bottom:.3125rem}::slotted(*){flex-shrink:0}::slotted(:not(:last-child)){margin-right:.5rem}:host([variant=medium]){height:7rem}:host([variant=large]){height:9.5rem}:host([hide]:not([hide=false i])){transition-duration:var(--mdui-motion-duration-short4);top:-4.625rem}:host([hide][variant=medium]:not([hide=false i])){top:-7.625rem}:host([hide][variant=large]:not([hide=false i])){top:-10.125rem}:host([shrink][variant=large]:not([shrink=false i])),:host([shrink][variant=medium]:not([shrink=false i])){transition-duration:var(--mdui-motion-duration-short4);height:4rem}`;

View File

@@ -0,0 +1 @@
export declare const topAppBarTitleStyle: import("lit").CSSResult;

View File

@@ -0,0 +1,2 @@
import { css } from 'lit';
export const topAppBarTitleStyle = css `:host{display:block;width:100%;flex-shrink:initial!important;overflow:hidden;color:rgb(var(--mdui-color-on-surface));font-size:var(--mdui-typescale-title-large-size);font-weight:var(--mdui-typescale-title-large-weight);letter-spacing:var(--mdui-typescale-title-large-tracking);line-height:var(--mdui-typescale-title-large-line-height);line-height:2.5rem}.label{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:1;transition:opacity var(--mdui-motion-duration-short2) var(--mdui-motion-easing-linear)}.label.variant-center-aligned{text-align:center}.label.variant-large:not(.shrink),.label.variant-medium:not(.shrink){opacity:0}.label.variant-large.shrink,.label.variant-medium.shrink{transition-delay:var(--mdui-motion-duration-short2)}.label-large{display:none;position:absolute;width:100%;left:0;margin-right:0;padding:0 1rem;transition:opacity var(--mdui-motion-duration-short2) var(--mdui-motion-easing-linear)}.label-large.variant-large,.label-large.variant-medium{display:block}.label-large.variant-medium{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;bottom:.75rem;font-size:var(--mdui-typescale-headline-small-size);font-weight:var(--mdui-typescale-headline-small-weight);letter-spacing:var(--mdui-typescale-headline-small-tracking);line-height:var(--mdui-typescale-headline-small-line-height)}.label-large.variant-large{display:-webkit-box;overflow:hidden;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2;bottom:1.25rem;font-size:var(--mdui-typescale-headline-medium-size);font-weight:var(--mdui-typescale-headline-medium-weight);letter-spacing:var(--mdui-typescale-headline-medium-tracking);line-height:var(--mdui-typescale-headline-medium-line-height)}.label-large.variant-large:not(.shrink),.label-large.variant-medium:not(.shrink){opacity:1;transition-delay:var(--mdui-motion-duration-short2)}.label-large.variant-large.shrink,.label-large.variant-medium.shrink{opacity:0;z-index:-1}`;

View File

@@ -0,0 +1,48 @@
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
import type { CSSResultGroup, TemplateResult } from 'lit';
/**
* @summary 顶部应用栏标题组件。需配合 `<mdui-top-app-bar>` 组件使用
*
* ```html
* <mdui-top-app-bar>
* ..<mdui-button-icon icon="menu"></mdui-button-icon>
* ..<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
* ..<div style="flex-grow: 1"></div>
* ..<mdui-button-icon icon="more_vert"></mdui-button-icon>
* </mdui-top-app-bar>
* ```
*
* @slot - 顶部应用栏的标题文本
* @slot label-large - 展开状态下的标题文本
*
* @csspart label 标题文本
* @csspart label-large 展开状态下的标题文本
*/
export declare class TopAppBarTitle extends MduiElement<TopAppBarTitleEventMap> {
static styles: CSSResultGroup;
/**
* 顶部应用栏形状。由 mdui-top-app-bar 组件控制该参数
*/
private variant;
/**
* 是否缩小成 `variant="small"` 的样式,仅在 `variant="medium"` 或 `variant="large"` 时生效。由 mdui-top-app-bar 组件控制该参数
*/
private shrink;
private readonly hasSlotController;
private readonly labelLargeRef;
private readonly defaultSlotRef;
protected render(): TemplateResult;
/**
* default slot 变化时,同步到 label-large 中
* @param hasLabelLargeSlot
* @private
*/
private onSlotChange;
}
export interface TopAppBarTitleEventMap {
}
declare global {
interface HTMLElementTagNameMap {
'mdui-top-app-bar-title': TopAppBarTitle;
}
}

View File

@@ -0,0 +1,81 @@
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
import { getInnerHtmlFromSlot } from '@mdui/shared/helpers/slot.js';
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
import { topAppBarTitleStyle } from './top-app-bar-title-style.js';
/**
* @summary 顶部应用栏标题组件。需配合 `<mdui-top-app-bar>` 组件使用
*
* ```html
* <mdui-top-app-bar>
* ..<mdui-button-icon icon="menu"></mdui-button-icon>
* ..<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
* ..<div style="flex-grow: 1"></div>
* ..<mdui-button-icon icon="more_vert"></mdui-button-icon>
* </mdui-top-app-bar>
* ```
*
* @slot - 顶部应用栏的标题文本
* @slot label-large - 展开状态下的标题文本
*
* @csspart label 标题文本
* @csspart label-large 展开状态下的标题文本
*/
let TopAppBarTitle = class TopAppBarTitle extends MduiElement {
constructor() {
super(...arguments);
/**
* 顶部应用栏形状。由 mdui-top-app-bar 组件控制该参数
*/
this.variant = 'small';
/**
* 是否缩小成 `variant="small"` 的样式,仅在 `variant="medium"` 或 `variant="large"` 时生效。由 mdui-top-app-bar 组件控制该参数
*/
this.shrink = false;
this.hasSlotController = new HasSlotController(this, 'label-large');
this.labelLargeRef = createRef();
this.defaultSlotRef = createRef();
}
render() {
const hasLabelLargeSlot = this.hasSlotController.test('label-large');
const className = classMap({
shrink: this.shrink,
'variant-center-aligned': this.variant === 'center-aligned',
'variant-small': this.variant === 'small',
'variant-medium': this.variant === 'medium',
'variant-large': this.variant === 'large',
});
return html `<slot part="label" class="label ${className}" ${ref(this.defaultSlotRef)} @slotchange="${() => this.onSlotChange(hasLabelLargeSlot)}"></slot>${hasLabelLargeSlot
? html `<slot name="label-large" part="label-large" class="label-large ${className}"></slot>`
: html `<div ${ref(this.labelLargeRef)} part="label-large" class="label-large ${className}"></div>`}`;
}
/**
* default slot 变化时,同步到 label-large 中
* @param hasLabelLargeSlot
* @private
*/
onSlotChange(hasLabelLargeSlot) {
if (!hasLabelLargeSlot) {
this.labelLargeRef.value.innerHTML = getInnerHtmlFromSlot(this.defaultSlotRef.value);
}
}
};
TopAppBarTitle.styles = [
componentStyle,
topAppBarTitleStyle,
];
__decorate([
state()
], TopAppBarTitle.prototype, "variant", void 0);
__decorate([
state()
], TopAppBarTitle.prototype, "shrink", void 0);
TopAppBarTitle = __decorate([
customElement('mdui-top-app-bar-title')
], TopAppBarTitle);
export { TopAppBarTitle };

View File

@@ -0,0 +1,81 @@
import { LayoutItemBase } from '../layout/layout-item-base.js';
import type { LayoutPlacement } from '../layout/helper.js';
import type { ScrollPaddingPosition } from '@mdui/shared/mixins/scrollBehavior.js';
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
declare const TopAppBar_base: import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/scrollBehavior.js").ScrollBehaviorMixinInterface> & typeof LayoutItemBase;
/**
* @summary 顶部应用栏组件
*
* ```html
* <mdui-top-app-bar>
* ..<mdui-button-icon icon="menu"></mdui-button-icon>
* ..<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
* ..<div style="flex-grow: 1"></div>
* ..<mdui-button-icon icon="more_vert"></mdui-button-icon>
* </mdui-top-app-bar>
* ```
*
* @event show - 开始显示时,事件被触发。可以通过调用 `event.preventDefault()` 阻止显示
* @event shown - 显示动画完成时,事件被触发
* @event hide - 开始隐藏时,事件被触发。可以通过调用 `event.preventDefault()` 阻止隐藏
* @event hidden - 隐藏动画完成时,事件被触发
*
* @slot - 顶部应用栏内部的元素
*
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
* @cssprop --z-index - 组件的 CSS `z-index` 值
*/
export declare class TopAppBar extends TopAppBar_base<TopAppBarEventMap> {
static styles: CSSResultGroup;
/**
* 顶部应用栏的形状。默认为 `small`。可选值包括:
*
* * `center-aligned`:小型应用栏,标题居中
* * `small`:小型应用栏
* * `medium`:中型应用栏
* * `large`:大型应用栏
*/
variant: /*小型应用栏,标题居中*/ 'center-aligned' | /*小型应用栏*/ 'small' | /*中型应用栏*/ 'medium' | /*大型应用栏*/ 'large';
/**
* 是否隐藏
*/
hide: boolean;
/**
* 是否缩小为 `variant="small"` 的样式,仅在 `variant="medium"` 或 `variant="large"` 时生效
*/
shrink: boolean;
/**
* 滚动行为。可同时使用多个值,用空格分隔。可选值包括:
*
* * `hide`:滚动时隐藏
* * `shrink`:在中型、大型应用栏中可使用,滚动时缩小成小型应用栏的样式
* * `elevate`:滚动时添加阴影
*/
scrollBehavior?: /*滚动时隐藏*/ 'hide' | /*在中型、大型应用栏中可使用,滚动时缩小成小型应用栏的样式*/ 'shrink' | /*滚动时添加阴影*/ 'elevate';
/**
* 滚动条是否不位于顶部
*/
private scrolling;
private readonly titleElements;
private definedController;
protected get scrollPaddingPosition(): ScrollPaddingPosition;
protected get layoutPlacement(): LayoutPlacement;
private onVariantChange;
private onShrinkChange;
protected firstUpdated(_changedProperties: PropertyValues): void;
protected render(): TemplateResult;
protected runScrollNoThreshold(isScrollingUp: boolean, scrollTop: number): void;
protected runScrollThreshold(isScrollingUp: boolean, scrollTop: number): void;
}
export interface TopAppBarEventMap {
show: CustomEvent<void>;
shown: CustomEvent<void>;
hide: CustomEvent<void>;
hidden: CustomEvent<void>;
}
declare global {
interface HTMLElementTagNameMap {
'mdui-top-app-bar': TopAppBar;
}
}
export {};

View File

@@ -0,0 +1,185 @@
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, property, queryAssignedElements, } from 'lit/decorators.js';
import { DefinedController } from '@mdui/shared/controllers/defined.js';
import { watch } from '@mdui/shared/decorators/watch.js';
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
import { ScrollBehaviorMixin } from '@mdui/shared/mixins/scrollBehavior.js';
import { LayoutItemBase } from '../layout/layout-item-base.js';
import { topAppBarStyle } from './top-app-bar-style.js';
/**
* @summary 顶部应用栏组件
*
* ```html
* <mdui-top-app-bar>
* ..<mdui-button-icon icon="menu"></mdui-button-icon>
* ..<mdui-top-app-bar-title>Title</mdui-top-app-bar-title>
* ..<div style="flex-grow: 1"></div>
* ..<mdui-button-icon icon="more_vert"></mdui-button-icon>
* </mdui-top-app-bar>
* ```
*
* @event show - 开始显示时,事件被触发。可以通过调用 `event.preventDefault()` 阻止显示
* @event shown - 显示动画完成时,事件被触发
* @event hide - 开始隐藏时,事件被触发。可以通过调用 `event.preventDefault()` 阻止隐藏
* @event hidden - 隐藏动画完成时,事件被触发
*
* @slot - 顶部应用栏内部的元素
*
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
* @cssprop --z-index - 组件的 CSS `z-index` 值
*/
let TopAppBar = class TopAppBar extends ScrollBehaviorMixin(LayoutItemBase) {
constructor() {
super(...arguments);
/**
* 顶部应用栏的形状。默认为 `small`。可选值包括:
*
* * `center-aligned`:小型应用栏,标题居中
* * `small`:小型应用栏
* * `medium`:中型应用栏
* * `large`:大型应用栏
*/
this.variant = 'small';
/**
* 是否隐藏
*/
this.hide = false;
/**
* 是否缩小为 `variant="small"` 的样式,仅在 `variant="medium"` 或 `variant="large"` 时生效
*/
this.shrink = false;
/**
* 滚动条是否不位于顶部
*/
this.scrolling = false;
this.definedController = new DefinedController(this, {
relatedElements: ['mdui-top-app-bar-title'],
});
}
get scrollPaddingPosition() {
return 'top';
}
get layoutPlacement() {
return 'top';
}
async onVariantChange() {
if (this.hasUpdated) {
// variant 变更时,重新为 scrollTargetContainer 元素添加 padding-top。避免 top-app-bar 覆盖内容
this.addEventListener('transitionend', async () => {
await this.scrollBehaviorDefinedController.whenDefined();
this.setContainerPadding('update', this.scrollTarget);
}, { once: true });
}
else {
await this.updateComplete;
}
await this.definedController.whenDefined();
this.titleElements.forEach((titleElement) => {
titleElement.variant = this.variant;
});
}
async onShrinkChange() {
if (!this.hasUpdated) {
await this.updateComplete;
}
await this.definedController.whenDefined();
this.titleElements.forEach((titleElement) => {
titleElement.shrink = this.shrink;
});
}
firstUpdated(_changedProperties) {
super.firstUpdated(_changedProperties);
this.addEventListener('transitionend', (e) => {
if (e.target === this) {
this.emit(this.hide ? 'hidden' : 'shown');
}
});
}
render() {
return html `<slot></slot>`;
}
runScrollNoThreshold(isScrollingUp, scrollTop) {
// 向上滚动到顶部时,复原(无视 scrollThreshold 属性,否则会无法复原)
if (this.hasScrollBehavior('shrink')) {
// 到距离顶部 8px 即开始复原,显得灵敏些
if (isScrollingUp && scrollTop < 8) {
this.shrink = false;
}
}
}
runScrollThreshold(isScrollingUp, scrollTop) {
// 滚动时添加阴影
if (this.hasScrollBehavior('elevate')) {
this.scrolling = !!scrollTop;
}
// 向下滚动时,缩小
if (this.hasScrollBehavior('shrink')) {
if (!isScrollingUp) {
this.shrink = true;
}
}
// 滚动时隐藏
if (this.hasScrollBehavior('hide')) {
// 向下滚动
if (!isScrollingUp && !this.hide) {
const eventProceeded = this.emit('hide', { cancelable: true });
if (eventProceeded) {
this.hide = true;
}
}
// 向上滚动
if (isScrollingUp && this.hide) {
const eventProceeded = this.emit('show', { cancelable: true });
if (eventProceeded) {
this.hide = false;
}
}
}
}
};
TopAppBar.styles = [
componentStyle,
topAppBarStyle,
];
__decorate([
property({ reflect: true })
], TopAppBar.prototype, "variant", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TopAppBar.prototype, "hide", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TopAppBar.prototype, "shrink", void 0);
__decorate([
property({ reflect: true, attribute: 'scroll-behavior' })
], TopAppBar.prototype, "scrollBehavior", void 0);
__decorate([
property({
type: Boolean,
reflect: true,
converter: booleanConverter,
})
], TopAppBar.prototype, "scrolling", void 0);
__decorate([
queryAssignedElements({ selector: 'mdui-top-app-bar-title', flatten: true })
], TopAppBar.prototype, "titleElements", void 0);
__decorate([
watch('variant')
], TopAppBar.prototype, "onVariantChange", null);
__decorate([
watch('shrink')
], TopAppBar.prototype, "onShrinkChange", null);
TopAppBar = __decorate([
customElement('mdui-top-app-bar')
], TopAppBar);
export { TopAppBar };