移动目录
This commit is contained in:
21
mdui_patched/LICENSE
Normal file
21
mdui_patched/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-present zdhxiong@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
49
mdui_patched/README.md
Normal file
49
mdui_patched/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# mdui
|
||||
|
||||
[](https://badge.fury.io/gh/zdhxiong%2Fmdui)
|
||||
[](https://www.npmjs.com/package/mdui)
|
||||
[](https://cdnjs.com/libraries/mdui)
|
||||
|
||||
[官网](https://www.mdui.org) | [文档](https://www.mdui.org/docs/2/)
|
||||
|
||||
使用 Web Components 实现,遵循 Material You 设计规范的 Web 前端组件库。
|
||||
|
||||
* **Web Components**:mdui 组件全部使用 Web Components 开发,使用组件就像使用 `<div>` 标签一样简单。
|
||||
* **Material You**:遵循最新的 Material Design 3(Material You)设计规范,使你的产品美观、易用。
|
||||
* **动态配色**:支持根据给定颜色值,或给定一张图片,mdui 能自动计算出颜色值,生成整套配色方案,并在所有 mdui 组件中生效。
|
||||
* **暗色模式**:所有组件都支持暗色模式、及支持根据操作系统设置自动切换亮色模式和暗色模式。
|
||||
* **轻量级**:gzip 后的 CSS + JavaScript 仅 85KB,使用按需导入可进一步减小体积,使加载更迅速。
|
||||
* **IDE 支持**:在 VSCode 和 WebStorm 中能获得完美的代码提示。且提供了 VSCode 扩展和 WebStorm 插件,使开发更便捷。
|
||||
* **兼容所有框架**:mdui 能兼容 Vue、React、Angular 等框架,只要在浏览器上运行的应用,都能使用 mdui。
|
||||
* **TypeScript 支持**:mdui 完全使用 TypeScript 开发,拥有完美的类型提示。
|
||||
* **无依赖**:不需要依赖任何第三方库,节约网络流量,使加载更迅速。
|
||||
* **组件丰富**:mdui 包含 30 多个组件,及十余个工具函数,常用组件都有。
|
||||
* **Material Icons 图标库**:提供了超过 1 万个图标组件,可按需导入所需图标。
|
||||
* **低学习成本**:只需懂一点 HTML、CSS、JavaScript 的基础知识,就能使用 mdui。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install mdui --save
|
||||
```
|
||||
|
||||
### 导入 CSS 及 JS 文件
|
||||
|
||||
```js
|
||||
import 'mdui/mdui.css';
|
||||
import 'mdui';
|
||||
```
|
||||
|
||||
### 使用组件
|
||||
|
||||
```html
|
||||
<mdui-button>Button</mdui-button>
|
||||
```
|
||||
|
||||
## 赞助
|
||||
|
||||
赞助以帮助 mdui 持续更新
|
||||
|
||||

|
||||

|
||||
[](https://www.paypal.me/zdhxiong/5)
|
||||
1
mdui_patched/components/avatar.d.ts
vendored
Normal file
1
mdui_patched/components/avatar.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './avatar/index.js';
|
||||
1
mdui_patched/components/avatar.js
Normal file
1
mdui_patched/components/avatar.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './avatar/index.js';
|
||||
51
mdui_patched/components/avatar/index.d.ts
vendored
Normal file
51
mdui_patched/components/avatar/index.d.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import '../icon.js';
|
||||
import type { CSSResultGroup, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 头像组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-avatar src="https://avatars.githubusercontent.com/u/3030330?s=40&v=4"></mdui-avatar>
|
||||
* ```
|
||||
*
|
||||
* @slot - 自定义头像内容,可以为字母、汉字、`<img>` 元素、图标等
|
||||
*
|
||||
* @csspart image - 使用图片作为头像时,组件内部的 `<img>` 元素
|
||||
* @csspart icon - 使用图标作为头像时,组件内部的 `<mdui-icon>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Avatar extends MduiElement<AvatarEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 头像图片的 URL 地址
|
||||
*/
|
||||
src?: string;
|
||||
/**
|
||||
* 图片如何适应容器框,与原生的 [`object-fit`](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) 属性相同。可选值包括:
|
||||
*
|
||||
* * `contain`:保持图片原有尺寸比例,内容会被等比例缩放
|
||||
* * `cover`:保持图片原有尺寸比例,但部分内容可能被剪切
|
||||
* * `fill`:默认值,不保持图片原有尺寸比例,内容会被拉伸以填充整个容器
|
||||
* * `none`:保留图片原有尺寸,内容不会被缩放或拉伸
|
||||
* * `scale-down`:保持图片原有尺寸比例,内容尺寸与 `none` 或 `contain` 中较小的一个相同
|
||||
*/
|
||||
fit?: /*保持图片原有尺寸比例,内容会被等比例缩放*/ 'contain' | /*保持图片原有尺寸比例,但部分内容可能被剪切*/ 'cover' | /*默认值,不保持图片原有尺寸比例,内容会被拉伸以填充整个容器*/ 'fill' | /*保留图片原有尺寸,内容不会被缩放或拉伸*/ 'none' | /*保持图片原有尺寸比例,内容尺寸与 `none` 或 `contain` 中较小的一个相同*/ 'scale-down';
|
||||
/**
|
||||
* 头像的 Material Icons 图标名
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 头像的替代文本描述
|
||||
*/
|
||||
label?: string;
|
||||
private readonly hasSlotController;
|
||||
protected render(): TemplateResult;
|
||||
}
|
||||
export interface AvatarEventMap {
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-avatar': Avatar;
|
||||
}
|
||||
}
|
||||
57
mdui_patched/components/avatar/index.js
Normal file
57
mdui_patched/components/avatar/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import '../icon.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 头像组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-avatar src="https://avatars.githubusercontent.com/u/3030330?s=40&v=4"></mdui-avatar>
|
||||
* ```
|
||||
*
|
||||
* @slot - 自定义头像内容,可以为字母、汉字、`<img>` 元素、图标等
|
||||
*
|
||||
* @csspart image - 使用图片作为头像时,组件内部的 `<img>` 元素
|
||||
* @csspart icon - 使用图标作为头像时,组件内部的 `<mdui-icon>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Avatar = class Avatar extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.hasSlotController = new HasSlotController(this, '[default]');
|
||||
}
|
||||
render() {
|
||||
return this.hasSlotController.test('[default]')
|
||||
? html `<slot></slot>`
|
||||
: this.src
|
||||
? html `<img part="image" alt="${ifDefined(this.label)}" src="${this.src}" style="${styleMap({ objectFit: this.fit })}">`
|
||||
: this.icon
|
||||
? html `<mdui-icon part="icon" name="${this.icon}"></mdui-icon>`
|
||||
: nothingTemplate;
|
||||
}
|
||||
};
|
||||
Avatar.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Avatar.prototype, "src", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Avatar.prototype, "fit", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Avatar.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Avatar.prototype, "label", void 0);
|
||||
Avatar = __decorate([
|
||||
customElement('mdui-avatar')
|
||||
], Avatar);
|
||||
export { Avatar };
|
||||
1
mdui_patched/components/avatar/style.d.ts
vendored
Normal file
1
mdui_patched/components/avatar/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/avatar/style.js
Normal file
2
mdui_patched/components/avatar/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-full);position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;white-space:nowrap;vertical-align:middle;border-radius:var(--shape-corner);-webkit-user-select:none;user-select:none;width:2.5rem;height:2.5rem;background-color:rgb(var(--mdui-color-primary-container));color:rgb(var(--mdui-color-on-primary-container));font-size:var(--mdui-typescale-title-medium-size);font-weight:var(--mdui-typescale-title-medium-weight);letter-spacing:var(--mdui-typescale-title-medium-tracking);line-height:var(--mdui-typescale-title-medium-line-height)}img{width:100%;height:100%}::slotted(mdui-icon),mdui-icon{font-size:1.5em}`;
|
||||
1
mdui_patched/components/badge.d.ts
vendored
Normal file
1
mdui_patched/components/badge.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './badge/index.js';
|
||||
1
mdui_patched/components/badge.js
Normal file
1
mdui_patched/components/badge.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './badge/index.js';
|
||||
31
mdui_patched/components/badge/index.d.ts
vendored
Normal file
31
mdui_patched/components/badge/index.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 徽标组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-badge>12</mdui-badge>
|
||||
* ```
|
||||
*
|
||||
* @slot - 徽标中显示的文本
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Badge extends MduiElement<BadgeEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 徽标的形状。可选值包括:
|
||||
*
|
||||
* * `small`:小型徽标,不显示文本
|
||||
* * `large`:大型徽标,会显示文本
|
||||
*/
|
||||
variant: /*小型徽标,不显示文本*/ 'small' | /*大型徽标,会显示文本*/ 'large';
|
||||
protected render(): TemplateResult;
|
||||
}
|
||||
export interface BadgeEventMap {
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-badge': Badge;
|
||||
}
|
||||
}
|
||||
44
mdui_patched/components/badge/index.js
Normal file
44
mdui_patched/components/badge/index.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 徽标组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-badge>12</mdui-badge>
|
||||
* ```
|
||||
*
|
||||
* @slot - 徽标中显示的文本
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Badge = class Badge extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 徽标的形状。可选值包括:
|
||||
*
|
||||
* * `small`:小型徽标,不显示文本
|
||||
* * `large`:大型徽标,会显示文本
|
||||
*/
|
||||
this.variant = 'large';
|
||||
}
|
||||
render() {
|
||||
if (this.variant === 'small') {
|
||||
return nothingTemplate;
|
||||
}
|
||||
return html `<slot></slot>`;
|
||||
}
|
||||
};
|
||||
Badge.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Badge.prototype, "variant", void 0);
|
||||
Badge = __decorate([
|
||||
customElement('mdui-badge')
|
||||
], Badge);
|
||||
export { Badge };
|
||||
1
mdui_patched/components/badge/style.d.ts
vendored
Normal file
1
mdui_patched/components/badge/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/badge/style.js
Normal file
2
mdui_patched/components/badge/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-full);display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:var(--shape-corner);padding-left:.25rem;padding-right:.25rem;color:rgb(var(--mdui-color-on-error));background-color:rgb(var(--mdui-color-error));height:1rem;min-width:1rem;font-size:var(--mdui-typescale-label-small-size);font-weight:var(--mdui-typescale-label-small-weight);letter-spacing:var(--mdui-typescale-label-small-tracking);line-height:var(--mdui-typescale-label-small-line-height)}:host([variant=small]){min-width:0;padding:0;width:.375rem;height:.375rem}`;
|
||||
1
mdui_patched/components/bottom-app-bar.d.ts
vendored
Normal file
1
mdui_patched/components/bottom-app-bar.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './bottom-app-bar/index.js';
|
||||
1
mdui_patched/components/bottom-app-bar.js
Normal file
1
mdui_patched/components/bottom-app-bar.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './bottom-app-bar/index.js';
|
||||
67
mdui_patched/components/bottom-app-bar/index.d.ts
vendored
Normal file
67
mdui_patched/components/bottom-app-bar/index.d.ts
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
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 BottomAppBar_base: import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/scrollBehavior.js").ScrollBehaviorMixinInterface> & typeof LayoutItemBase;
|
||||
/**
|
||||
* @summary 底部应用栏组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-bottom-app-bar>
|
||||
* ..<mdui-button-icon icon="check_box--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="edit--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="mic_none--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="image--outlined"></mdui-button-icon>
|
||||
* ..<div style="flex-grow: 1"></div>
|
||||
* ..<mdui-fab icon="add"></mdui-fab>
|
||||
* </mdui-bottom-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 BottomAppBar extends BottomAppBar_base<BottomAppBarEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否隐藏
|
||||
*/
|
||||
hide: boolean;
|
||||
/**
|
||||
* 是否让底部应用栏中的 [`<mdui-fab>`](/docs/2/components/fab) 组件脱离应用栏。如果为 `true`,则当应用栏隐藏后,[`<mdui-fab>`](/docs/2/components/fab) 仍会停留在页面上
|
||||
*/
|
||||
fabDetach: boolean;
|
||||
/**
|
||||
* 滚动行为。可选值为:
|
||||
*
|
||||
* * `hide`:滚动时隐藏
|
||||
*/
|
||||
scrollBehavior?: 'hide';
|
||||
protected get scrollPaddingPosition(): ScrollPaddingPosition;
|
||||
protected get layoutPlacement(): LayoutPlacement;
|
||||
protected firstUpdated(_changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
/**
|
||||
* 滚动行为
|
||||
* 当前仅支持 hide 这一个行为,所以不做行为类型判断
|
||||
*/
|
||||
protected runScrollThreshold(isScrollingUp: boolean): void;
|
||||
}
|
||||
export interface BottomAppBarEventMap {
|
||||
show: CustomEvent<void>;
|
||||
shown: CustomEvent<void>;
|
||||
hide: CustomEvent<void>;
|
||||
hidden: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-bottom-app-bar': BottomAppBar;
|
||||
}
|
||||
}
|
||||
export {};
|
||||
105
mdui_patched/components/bottom-app-bar/index.js
Normal file
105
mdui_patched/components/bottom-app-bar/index.js
Normal file
@@ -0,0 +1,105 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.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 { style } from './style.js';
|
||||
/**
|
||||
* @summary 底部应用栏组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-bottom-app-bar>
|
||||
* ..<mdui-button-icon icon="check_box--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="edit--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="mic_none--outlined"></mdui-button-icon>
|
||||
* ..<mdui-button-icon icon="image--outlined"></mdui-button-icon>
|
||||
* ..<div style="flex-grow: 1"></div>
|
||||
* ..<mdui-fab icon="add"></mdui-fab>
|
||||
* </mdui-bottom-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 BottomAppBar = class BottomAppBar extends ScrollBehaviorMixin(LayoutItemBase) {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否隐藏
|
||||
*/
|
||||
this.hide = false;
|
||||
/**
|
||||
* 是否让底部应用栏中的 [`<mdui-fab>`](/docs/2/components/fab) 组件脱离应用栏。如果为 `true`,则当应用栏隐藏后,[`<mdui-fab>`](/docs/2/components/fab) 仍会停留在页面上
|
||||
*/
|
||||
this.fabDetach = false;
|
||||
}
|
||||
get scrollPaddingPosition() {
|
||||
return 'bottom';
|
||||
}
|
||||
get layoutPlacement() {
|
||||
return 'bottom';
|
||||
}
|
||||
firstUpdated(_changedProperties) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
this.addEventListener('transitionend', (event) => {
|
||||
if (event.target === this) {
|
||||
this.emit(this.hide ? 'hidden' : 'shown');
|
||||
}
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return html `<slot></slot>`;
|
||||
}
|
||||
/**
|
||||
* 滚动行为
|
||||
* 当前仅支持 hide 这一个行为,所以不做行为类型判断
|
||||
*/
|
||||
runScrollThreshold(isScrollingUp) {
|
||||
// 向下滚动
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
BottomAppBar.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], BottomAppBar.prototype, "hide", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'fab-detach',
|
||||
})
|
||||
], BottomAppBar.prototype, "fabDetach", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'scroll-behavior' })
|
||||
], BottomAppBar.prototype, "scrollBehavior", void 0);
|
||||
BottomAppBar = __decorate([
|
||||
customElement('mdui-bottom-app-bar')
|
||||
], BottomAppBar);
|
||||
export { BottomAppBar };
|
||||
1
mdui_patched/components/bottom-app-bar/style.d.ts
vendored
Normal file
1
mdui_patched/components/bottom-app-bar/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/bottom-app-bar/style.js
Normal file
2
mdui_patched/components/bottom-app-bar/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-none);--z-index:2000;position:fixed;right:0;bottom:0;left:0;display:flex;flex:0 0 auto;align-items:center;justify-content:flex-start;border-radius:var(--shape-corner) var(--shape-corner) 0 0;z-index:var(--z-index);transition:bottom var(--mdui-motion-duration-long2) var(--mdui-motion-easing-emphasized);padding:0 1rem;height:5rem;background-color:rgb(var(--mdui-color-surface-container));box-shadow:var(--mdui-elevation-level2)}:host([scroll-target]:not([scroll-target=''])){position:absolute}:host([hide]:not([hide=false i])){transition-duration:var(--mdui-motion-duration-short4);bottom:-5.625rem}::slotted(:not(:first-child)){margin-left:.5rem}::slotted(mdui-fab){box-shadow:var(--mdui-elevation-level0)}:host([fab-detach]:not([fab-detach=false i])) ::slotted(mdui-fab){position:absolute;transition:bottom var(--mdui-motion-duration-long2) var(--mdui-motion-easing-standard);right:1rem;bottom:.75rem}:host([fab-detach][hide][scroll-behavior~=hide]:not([hide=false i],[fab-detach=false i])) ::slotted(mdui-fab){transition-duration:var(--mdui-motion-duration-short4);bottom:1rem;box-shadow:var(--mdui-elevation-level2)}:host([fab-detach][hide][scroll-behavior~=hide][scroll-target]:not([fab-detach=false i],[hide=false i],[scroll-target=''])) ::slotted(mdui-fab){bottom:6.625rem}:host([hide]:not([hide=false i])) ::slotted(:not(mdui-fab)),:host([hide]:not([hide=false i],[fab-detach])) ::slotted(mdui-fab),:host([hide][fab-detach=false i]:not([hide=false i])) ::slotted(mdui-fab){transform:translateY(8.75rem);transition:transform var(--mdui-motion-duration-0) var(--mdui-motion-easing-emphasized-accelerate) var(--mdui-motion-duration-short4)}::slotted(:first-child){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-short1)}::slotted(:nth-child(2)){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-short3)}::slotted(:nth-child(3)){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-short4)}::slotted(:nth-child(4)){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-medium1)}::slotted(:nth-child(5)){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-medium2)}::slotted(:nth-child(6)){transition:transform var(--mdui-motion-duration-short3) var(--mdui-motion-easing-emphasized-decelerate) var(--mdui-motion-duration-medium3)}`;
|
||||
1
mdui_patched/components/button-icon.d.ts
vendored
Normal file
1
mdui_patched/components/button-icon.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './button-icon/index.js';
|
||||
1
mdui_patched/components/button-icon.js
Normal file
1
mdui_patched/components/button-icon.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './button-icon/index.js';
|
||||
72
mdui_patched/components/button-icon/index.d.ts
vendored
Normal file
72
mdui_patched/components/button-icon/index.d.ts
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 图标按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-button-icon icon="search"></mdui-button-icon>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 图标组件
|
||||
* @slot selected-icon 选中状态显示的图标元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart icon - 未选中状态的图标
|
||||
* @csspart selected-icon 选中状态的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class ButtonIcon extends ButtonBase<ButtonIconEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 图标按钮的形状。可选值包括:
|
||||
*
|
||||
* * `standard`:适用于最低优先级的操作
|
||||
* * `filled`:视觉效果强烈,适用于高优先级的操作
|
||||
* * `tonal`:视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作
|
||||
* * `outlined`:适用于中等优先级的操作
|
||||
*/
|
||||
variant: /*适用于最低优先级的操作*/ 'standard' | /*视觉效果强烈,适用于高优先级的操作*/ 'filled' | /*视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作*/ 'tonal' | /*适用于中等优先级的操作*/ 'outlined';
|
||||
/**
|
||||
* Material Icons 图标名。也可以通过 default slot 设置
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 选中状态的 Material Icons 图标名。也可以通过 `slot="selected-icon"` 设置
|
||||
*/
|
||||
selectedIcon?: string;
|
||||
/**
|
||||
* 是否可选中
|
||||
*/
|
||||
selectable: boolean;
|
||||
/**
|
||||
* 是否已被选中
|
||||
*/
|
||||
selected: boolean;
|
||||
private readonly rippleRef;
|
||||
private readonly hasSlotController;
|
||||
protected get rippleElement(): Ripple;
|
||||
private onSelectedChange;
|
||||
protected firstUpdated(changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
private renderIcon;
|
||||
}
|
||||
export interface ButtonIconEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
change: CustomEvent<void>;
|
||||
invalid: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-button-icon': ButtonIcon;
|
||||
}
|
||||
}
|
||||
129
mdui_patched/components/button-icon/index.js
Normal file
129
mdui_patched/components/button-icon/index.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 图标按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-button-icon icon="search"></mdui-button-icon>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 图标组件
|
||||
* @slot selected-icon 选中状态显示的图标元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart icon - 未选中状态的图标
|
||||
* @csspart selected-icon 选中状态的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let ButtonIcon = class ButtonIcon extends ButtonBase {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 图标按钮的形状。可选值包括:
|
||||
*
|
||||
* * `standard`:适用于最低优先级的操作
|
||||
* * `filled`:视觉效果强烈,适用于高优先级的操作
|
||||
* * `tonal`:视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作
|
||||
* * `outlined`:适用于中等优先级的操作
|
||||
*/
|
||||
this.variant = 'standard';
|
||||
/**
|
||||
* 是否可选中
|
||||
*/
|
||||
this.selectable = false;
|
||||
/**
|
||||
* 是否已被选中
|
||||
*/
|
||||
this.selected = false;
|
||||
this.rippleRef = createRef();
|
||||
this.hasSlotController = new HasSlotController(this, '[default]', 'selected-icon');
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
onSelectedChange() {
|
||||
this.emit('change');
|
||||
}
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener('click', () => {
|
||||
if (!this.selectable || this.disabled) {
|
||||
return;
|
||||
}
|
||||
this.selected = !this.selected;
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return html `<mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple>${this.isButton()
|
||||
? this.renderButton({
|
||||
className: 'button',
|
||||
part: 'button',
|
||||
content: this.renderIcon(),
|
||||
})
|
||||
: this.disabled || this.loading
|
||||
? html `<span part="button" class="button _a">${this.renderIcon()}</span>`
|
||||
: this.renderAnchor({
|
||||
className: 'button',
|
||||
part: 'button',
|
||||
content: this.renderIcon(),
|
||||
})} ${this.renderLoading()}`;
|
||||
}
|
||||
renderIcon() {
|
||||
const icon = () => this.hasSlotController.test('[default]')
|
||||
? html `<slot></slot>`
|
||||
: this.icon
|
||||
? html `<mdui-icon part="icon" class="icon" name="${this.icon}"></mdui-icon>`
|
||||
: nothingTemplate;
|
||||
const selectedIcon = () => this.hasSlotController.test('selected-icon') || this.selectedIcon
|
||||
? html `<slot name="selected-icon" part="selected-icon" class="selected-icon"><mdui-icon name="${this.selectedIcon}"></mdui-icon></slot>`
|
||||
: icon();
|
||||
return this.selected ? selectedIcon() : icon();
|
||||
}
|
||||
};
|
||||
ButtonIcon.styles = [ButtonBase.styles, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonIcon.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonIcon.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'selected-icon' })
|
||||
], ButtonIcon.prototype, "selectedIcon", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], ButtonIcon.prototype, "selectable", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], ButtonIcon.prototype, "selected", void 0);
|
||||
__decorate([
|
||||
watch('selected', true)
|
||||
], ButtonIcon.prototype, "onSelectedChange", null);
|
||||
ButtonIcon = __decorate([
|
||||
customElement('mdui-button-icon')
|
||||
], ButtonIcon);
|
||||
export { ButtonIcon };
|
||||
1
mdui_patched/components/button-icon/style.d.ts
vendored
Normal file
1
mdui_patched/components/button-icon/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
4
mdui_patched/components/button-icon/style.js
Normal file
4
mdui_patched/components/button-icon/style.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-full);position:relative;display:inline-block;flex-shrink:0;overflow:hidden;text-align:center;border-radius:var(--shape-corner);cursor:pointer;-webkit-tap-highlight-color:transparent;font-size:1.5rem;width:2.5rem;height:2.5rem}:host([variant=standard]){color:rgb(var(--mdui-color-on-surface-variant));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface-variant)}:host([variant=filled]){color:rgb(var(--mdui-color-primary));background-color:rgb(var(--mdui-color-surface-container-highest));--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=tonal]){color:rgb(var(--mdui-color-on-surface-variant));background-color:rgb(var(--mdui-color-surface-container-highest));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface-variant)}:host([variant=outlined]){border:.0625rem solid rgb(var(--mdui-color-outline));color:rgb(var(--mdui-color-on-surface-variant));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface-variant)}:host([variant=outlined][pressed]){color:rgb(var(--mdui-color-on-surface));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface)}:host([variant=standard][selected]:not([selected=false i])){color:rgb(var(--mdui-color-primary));--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=filled]:not([selectable])),:host([variant=filled][selectable=false i]),:host([variant=filled][selected]:not([selected=false i])){color:rgb(var(--mdui-color-on-primary));background-color:rgb(var(--mdui-color-primary));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-primary)}:host([variant=tonal]:not([selectable])),:host([variant=tonal][selectable=false i]),:host([variant=tonal][selected]:not([selected=false i])){color:rgb(var(--mdui-color-on-secondary-container));background-color:rgb(var(--mdui-color-secondary-container));--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-secondary-container
|
||||
)}:host([variant=outlined][selected]:not([selected=false i])){border:none;color:rgb(var(--mdui-color-inverse-on-surface));background-color:rgb(var(--mdui-color-inverse-surface));--mdui-comp-ripple-state-layer-color:var(--mdui-color-inverse-on-surface)}:host([variant=filled][disabled]:not([disabled=false i])),:host([variant=outlined][disabled]:not([disabled=false i])),:host([variant=tonal][disabled]:not([disabled=false i])){background-color:rgba(var(--mdui-color-on-surface),.12);border-color:rgba(var(--mdui-color-on-surface),.12)}:host([disabled]:not([disabled=false i])),:host([loading]:not([loading=false i])){cursor:default;pointer-events:none}:host([disabled]:not([disabled=false i])){color:rgba(var(--mdui-color-on-surface),.38)!important}.button{float:left;width:100%}:host([loading]:not([loading=false i])) .button,:host([loading]:not([loading=false i])) mdui-ripple{opacity:0}.icon,.selected-icon mdui-icon,::slotted(*){font-size:inherit}mdui-circular-progress{display:flex;position:absolute;top:calc(50% - 1.5rem / 2);left:calc(50% - 1.5rem / 2);width:1.5rem;height:1.5rem}:host([variant=filled]:not([disabled])) mdui-circular-progress,:host([variant=filled][disabled=false i]) mdui-circular-progress{stroke:rgb(var(--mdui-color-on-primary))}:host([disabled]:not([disabled=false i])) mdui-circular-progress{stroke:rgba(var(--mdui-color-on-surface),38%)}`;
|
||||
1
mdui_patched/components/button.d.ts
vendored
Normal file
1
mdui_patched/components/button.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './button/index.js';
|
||||
1
mdui_patched/components/button.js
Normal file
1
mdui_patched/components/button.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './button/index.js';
|
||||
1
mdui_patched/components/button/button-base-style.d.ts
vendored
Normal file
1
mdui_patched/components/button/button-base-style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const buttonBaseStyle: import("lit").CSSResult;
|
||||
2
mdui_patched/components/button/button-base-style.js
Normal file
2
mdui_patched/components/button/button-base-style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const buttonBaseStyle = css `.button{position:relative;display:inline-flex;align-items:center;justify-content:center;height:100%;padding:0;overflow:hidden;color:inherit;font-size:inherit;font-family:inherit;font-weight:inherit;letter-spacing:inherit;white-space:nowrap;text-align:center;text-decoration:none;vertical-align:middle;background:0 0;border:none;outline:0;cursor:inherit;-webkit-user-select:none;user-select:none;touch-action:manipulation;zoom:1;-webkit-user-drag:none}`;
|
||||
137
mdui_patched/components/button/button-base.d.ts
vendored
Normal file
137
mdui_patched/components/button/button-base.d.ts
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import '../circular-progress.js';
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
||||
type RenderButtonOptions = {
|
||||
id?: string;
|
||||
className?: string;
|
||||
part?: string;
|
||||
content?: TemplateResult | TemplateResult[];
|
||||
tabindex?: number;
|
||||
};
|
||||
declare const ButtonBase_base: import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/anchor.js").AnchorMixinInterface> & import("@lit/reactive-element/decorators/base.js").Constructor<import("../ripple/ripple-mixin.js").RippleMixinInterface> & import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/focusable.js").FocusableMixinInterface> & typeof MduiElement;
|
||||
export declare class ButtonBase<E> extends ButtonBase_base<E> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否禁用
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 是否处于加载中状态
|
||||
*/
|
||||
loading: boolean;
|
||||
/**
|
||||
* 按钮的名称,将与表单数据一起提交。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 按钮的初始值,将与表单数据一起提交。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
value: string;
|
||||
/**
|
||||
* 按钮的类型。默认类型为 `button`。可选类型包括:
|
||||
*
|
||||
* * `submit`:点击按钮会提交表单数据到服务器
|
||||
* * `reset`:点击按钮会将表单中的所有字段重置为初始值
|
||||
* * `button`:此类型的按钮没有默认行为
|
||||
*
|
||||
* **Note**:仅在未指定 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
type: /*此按钮将表单数据提交给服务器*/ 'submit' | /*此按钮重置所有组件为初始值*/ 'reset' | /*此按钮没有默认行为*/ 'button';
|
||||
/**
|
||||
* 关联的 `<form>` 元素。此属性值应为同一页面中的一个 `<form>` 元素的 `id`。
|
||||
*
|
||||
* 如果未指定此属性,则该元素必须是 `<form>` 元素的子元素。通过此属性,你可以将元素放置在页面的任何位置,而不仅仅是 `<form>` 元素的子元素。
|
||||
*
|
||||
* **Note**:仅在未指定 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
form?: string;
|
||||
/**
|
||||
* 指定提交表单的 URL。
|
||||
*
|
||||
* 如果指定了此属性,将覆盖 `<form>` 元素的 `action` 属性。
|
||||
*
|
||||
* **Note**:仅在未指定 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
formAction?: string;
|
||||
/**
|
||||
* 指定提交表单到服务器的内容类型。可选值包括:
|
||||
*
|
||||
* * `application/x-www-form-urlencoded`:未指定该属性时的默认值
|
||||
* * `multipart/form-data`:当表单包含 `<input type="file">` 元素时使用
|
||||
* * `text/plain`:HTML5 新增,用于调试
|
||||
*
|
||||
* 如果指定了此属性,将覆盖 `<form>` 元素的 `enctype` 属性。
|
||||
*
|
||||
* **Note**:仅在未指定 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
formEnctype?: /*未指定该属性时的默认值*/ 'application/x-www-form-urlencoded' | /*当表单包含 `<input type="file">` 元素时使用*/ 'multipart/form-data' | /*HTML5 新增,用于调试*/ 'text/plain';
|
||||
/**
|
||||
* 指定提交表单时使用的 HTTP 方法。可选值包括:
|
||||
*
|
||||
* * `post`:表单数据包含在表单内容中,发送到服务器
|
||||
* * `get`:表单数据以 `?` 作为分隔符附加到表单的 URI 属性中,生成的 URI 发送到服务器。当表单没有副作用,并且仅包含 ASCII 字符时,使用此方法
|
||||
*
|
||||
* 如果设置了此属性,将覆盖 `<form>` 元素的 `method` 属性。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
formMethod?: /*表单数据包含在表单内容中,发送到服务器*/ 'post' | /*表单数据以 `?` 作为分隔符附加到表单的 URI 属性中,生成的 URI 发送到服务器。当表单没有副作用,并且仅包含 ASCII 字符时,使用此方法*/ 'get';
|
||||
/**
|
||||
* 如果设置了此属性,表单提交时将不执行表单验证。
|
||||
*
|
||||
* 如果设置了此属性,将覆盖 `<form>` 元素的 `novalidate` 属性。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
formNoValidate: boolean;
|
||||
/**
|
||||
* 提交表单后接收到的响应应显示在何处。可选值包括:
|
||||
*
|
||||
* * `_self`:默认选项,在当前框架中打开
|
||||
* * `_blank`:在新窗口中打开
|
||||
* * `_parent`:在父框架中打开
|
||||
* * `_top`:在整个窗口中打开
|
||||
*
|
||||
* 如果设置了此属性,将覆盖 `<form>` 元素的 `target` 属性。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
formTarget?: /*默认选项,在当前框架中打开*/ '_self' | /*在新窗口中打开*/ '_blank' | /*在父框架中打开*/ '_parent' | /*在整个窗口中打开*/ '_top';
|
||||
private readonly formController;
|
||||
/**
|
||||
* 表单验证状态对象,具体参见 [`ValidityState`](https://developer.mozilla.org/zh-CN/docs/Web/API/ValidityState)
|
||||
*/
|
||||
get validity(): ValidityState | undefined;
|
||||
/**
|
||||
* 如果表单验证未通过,此属性将包含提示信息。如果验证通过,此属性将为空字符串
|
||||
*/
|
||||
get validationMessage(): string | undefined;
|
||||
protected get rippleDisabled(): boolean;
|
||||
protected get focusElement(): HTMLElement | null;
|
||||
protected get focusDisabled(): boolean;
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`
|
||||
*/
|
||||
checkValidity(): boolean;
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`。
|
||||
*
|
||||
* 如果验证未通过,还会在组件上显示验证失败的提示。
|
||||
*/
|
||||
reportValidity(): boolean;
|
||||
/**
|
||||
* 设置自定义的错误提示文本。只要这个文本不为空,就表示字段未通过验证
|
||||
*
|
||||
* @param message 自定义的错误提示文本
|
||||
*/
|
||||
setCustomValidity(message: string): void;
|
||||
protected firstUpdated(_changedProperties: PropertyValues): void;
|
||||
protected renderLoading(): TemplateResult;
|
||||
protected renderButton({ id, className, part, content, }: RenderButtonOptions): TemplateResult;
|
||||
protected isButton(): boolean;
|
||||
}
|
||||
export {};
|
||||
209
mdui_patched/components/button/button-base.js
Normal file
209
mdui_patched/components/button/button-base.js
Normal file
@@ -0,0 +1,209 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import cc from 'classcat';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { FormController } from '@mdui/shared/controllers/form.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { AnchorMixin } from '@mdui/shared/mixins/anchor.js';
|
||||
import { FocusableMixin } from '@mdui/shared/mixins/focusable.js';
|
||||
import '../circular-progress.js';
|
||||
import { RippleMixin } from '../ripple/ripple-mixin.js';
|
||||
import { buttonBaseStyle } from './button-base-style.js';
|
||||
export class ButtonBase extends AnchorMixin(RippleMixin(FocusableMixin(MduiElement))) {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否禁用
|
||||
*/
|
||||
this.disabled = false;
|
||||
/**
|
||||
* 是否处于加载中状态
|
||||
*/
|
||||
this.loading = false;
|
||||
/**
|
||||
* 按钮的名称,将与表单数据一起提交。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
this.name = '';
|
||||
/**
|
||||
* 按钮的初始值,将与表单数据一起提交。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
this.value = '';
|
||||
/**
|
||||
* 按钮的类型。默认类型为 `button`。可选类型包括:
|
||||
*
|
||||
* * `submit`:点击按钮会提交表单数据到服务器
|
||||
* * `reset`:点击按钮会将表单中的所有字段重置为初始值
|
||||
* * `button`:此类型的按钮没有默认行为
|
||||
*
|
||||
* **Note**:仅在未指定 `href` 属性时,此属性才有效。
|
||||
*/
|
||||
this.type = 'button';
|
||||
/**
|
||||
* 如果设置了此属性,表单提交时将不执行表单验证。
|
||||
*
|
||||
* 如果设置了此属性,将覆盖 `<form>` 元素的 `novalidate` 属性。
|
||||
*
|
||||
* **Note**:仅在未设置 `href` 属性且 `type="submit"` 时,此属性才有效。
|
||||
*/
|
||||
this.formNoValidate = false;
|
||||
this.formController = new FormController(this);
|
||||
}
|
||||
/**
|
||||
* 表单验证状态对象,具体参见 [`ValidityState`](https://developer.mozilla.org/zh-CN/docs/Web/API/ValidityState)
|
||||
*/
|
||||
get validity() {
|
||||
if (this.isButton()) {
|
||||
return this.focusElement.validity;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 如果表单验证未通过,此属性将包含提示信息。如果验证通过,此属性将为空字符串
|
||||
*/
|
||||
get validationMessage() {
|
||||
if (this.isButton()) {
|
||||
return this.focusElement.validationMessage;
|
||||
}
|
||||
}
|
||||
get rippleDisabled() {
|
||||
return this.disabled || this.loading;
|
||||
}
|
||||
get focusElement() {
|
||||
return this.isButton()
|
||||
? this.renderRoot?.querySelector('._button')
|
||||
: !this.focusDisabled
|
||||
? this.renderRoot?.querySelector('._a')
|
||||
: this;
|
||||
}
|
||||
get focusDisabled() {
|
||||
return this.disabled || this.loading;
|
||||
}
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`
|
||||
*/
|
||||
checkValidity() {
|
||||
if (this.isButton()) {
|
||||
const valid = this.focusElement.checkValidity();
|
||||
if (!valid) {
|
||||
// @ts-ignore
|
||||
this.emit('invalid', {
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
composed: false,
|
||||
});
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`。
|
||||
*
|
||||
* 如果验证未通过,还会在组件上显示验证失败的提示。
|
||||
*/
|
||||
reportValidity() {
|
||||
if (this.isButton()) {
|
||||
const invalid = !this.focusElement.reportValidity();
|
||||
if (invalid) {
|
||||
// @ts-ignore
|
||||
this.emit('invalid', {
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
composed: false,
|
||||
});
|
||||
// todo 考虑是否要支持 preventDefault() 方法,当前 invalid 状态没有样式
|
||||
}
|
||||
return !invalid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* 设置自定义的错误提示文本。只要这个文本不为空,就表示字段未通过验证
|
||||
*
|
||||
* @param message 自定义的错误提示文本
|
||||
*/
|
||||
setCustomValidity(message) {
|
||||
if (this.isButton()) {
|
||||
this.focusElement.setCustomValidity(message);
|
||||
}
|
||||
}
|
||||
firstUpdated(_changedProperties) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
this.addEventListener('click', () => {
|
||||
if (this.type === 'submit') {
|
||||
this.formController.submit(this);
|
||||
}
|
||||
if (this.type === 'reset') {
|
||||
this.formController.reset(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
renderLoading() {
|
||||
return this.loading
|
||||
? html `<mdui-circular-progress part="loading"></mdui-circular-progress>`
|
||||
: nothingTemplate;
|
||||
}
|
||||
renderButton({ id, className, part, content = html `<slot></slot>`, }) {
|
||||
return html `<button id="${ifDefined(id)}" class="${cc(['_button', className])}" part="${ifDefined(part)}" ?disabled="${this.rippleDisabled || this.focusDisabled}">${content}</button>`;
|
||||
}
|
||||
isButton() {
|
||||
return !this.href;
|
||||
}
|
||||
}
|
||||
ButtonBase.styles = [
|
||||
componentStyle,
|
||||
buttonBaseStyle,
|
||||
];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], ButtonBase.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], ButtonBase.prototype, "loading", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonBase.prototype, "name", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonBase.prototype, "value", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonBase.prototype, "type", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], ButtonBase.prototype, "form", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'formaction' })
|
||||
], ButtonBase.prototype, "formAction", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'formenctype' })
|
||||
], ButtonBase.prototype, "formEnctype", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'formmethod' })
|
||||
], ButtonBase.prototype, "formMethod", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'formnovalidate',
|
||||
})
|
||||
], ButtonBase.prototype, "formNoValidate", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'formtarget' })
|
||||
], ButtonBase.prototype, "formTarget", void 0);
|
||||
69
mdui_patched/components/button/index.d.ts
vendored
Normal file
69
mdui_patched/components/button/index.d.ts
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import '../icon.js';
|
||||
import { ButtonBase } from './button-base.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { TemplateResult, CSSResultGroup } from 'lit';
|
||||
/**
|
||||
* @summary 按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-button>Button</mdui-button>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 按钮的文本
|
||||
* @slot icon - 按钮左侧的元素
|
||||
* @slot end-icon - 按钮右侧的元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 按钮的文本
|
||||
* @csspart icon - 按钮左侧的图标
|
||||
* @csspart end-icon - 按钮右侧的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Button extends ButtonBase<ButtonEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 按钮的形状。可选值包括:
|
||||
*
|
||||
* * `elevated`:带阴影的按钮,适用于需要将按钮与背景视觉分离的场景
|
||||
* * `filled`:视觉效果强烈,适用于重要流程的最终操作,如“保存”、“确认”等
|
||||
* * `tonal`:视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作,如流程中的“下一步”
|
||||
* * `outlined`:带边框的按钮,适用于中等优先级,且次要的操作,如“返回”
|
||||
* * `text`:文本按钮,适用于最低优先级的操作
|
||||
*/
|
||||
variant: /*带阴影的按钮,适用于需要将按钮与背景视觉分离的场景*/ 'elevated' | /*视觉效果强烈,适用于重要流程的最终操作,如“保存”、“确认”等*/ 'filled' | /*视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作,如流程中的“下一步”*/ 'tonal' | /*带边框的按钮,适用于中等优先级,且次要的操作,如“返回”*/ 'outlined' | /*文本按钮,适用于最低优先级的操作*/ 'text';
|
||||
/**
|
||||
* 是否填满父元素宽度
|
||||
*/
|
||||
fullWidth: boolean;
|
||||
/**
|
||||
* 左侧的 Material Icons 图标名。也可以通过 `slot="icon"` 设置
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 右侧的 Material Icons 图标名。也可以通过 `slot="end-icon"` 设置
|
||||
*/
|
||||
endIcon?: string;
|
||||
private readonly rippleRef;
|
||||
protected get rippleElement(): Ripple;
|
||||
protected render(): TemplateResult;
|
||||
private renderIcon;
|
||||
private renderLabel;
|
||||
private renderEndIcon;
|
||||
private renderInner;
|
||||
}
|
||||
export interface ButtonEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
invalid: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-button': Button;
|
||||
}
|
||||
}
|
||||
111
mdui_patched/components/button/index.js
Normal file
111
mdui_patched/components/button/index.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import '../icon.js';
|
||||
import { ButtonBase } from './button-base.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-button>Button</mdui-button>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 按钮的文本
|
||||
* @slot icon - 按钮左侧的元素
|
||||
* @slot end-icon - 按钮右侧的元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 按钮的文本
|
||||
* @csspart icon - 按钮左侧的图标
|
||||
* @csspart end-icon - 按钮右侧的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Button = class Button extends ButtonBase {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 按钮的形状。可选值包括:
|
||||
*
|
||||
* * `elevated`:带阴影的按钮,适用于需要将按钮与背景视觉分离的场景
|
||||
* * `filled`:视觉效果强烈,适用于重要流程的最终操作,如“保存”、“确认”等
|
||||
* * `tonal`:视觉效果介于 `filled` 和 `outlined` 之间,适用于中高优先级的操作,如流程中的“下一步”
|
||||
* * `outlined`:带边框的按钮,适用于中等优先级,且次要的操作,如“返回”
|
||||
* * `text`:文本按钮,适用于最低优先级的操作
|
||||
*/
|
||||
this.variant = 'filled';
|
||||
/**
|
||||
* 是否填满父元素宽度
|
||||
*/
|
||||
this.fullWidth = false;
|
||||
this.rippleRef = createRef();
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
render() {
|
||||
return html `<mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple>${this.isButton()
|
||||
? this.renderButton({
|
||||
className: 'button',
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})
|
||||
: this.disabled || this.loading
|
||||
? html `<span part="button" class="button _a">${this.renderInner()}</span>`
|
||||
: this.renderAnchor({
|
||||
className: 'button',
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})}`;
|
||||
}
|
||||
renderIcon() {
|
||||
if (this.loading) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
return html `<slot name="icon" part="icon" class="icon">${this.icon
|
||||
? html `<mdui-icon name="${this.icon}"></mdui-icon>`
|
||||
: nothingTemplate}</slot>`;
|
||||
}
|
||||
renderLabel() {
|
||||
return html `<slot part="label" class="label"></slot>`;
|
||||
}
|
||||
renderEndIcon() {
|
||||
return html `<slot name="end-icon" part="end-icon" class="end-icon">${this.endIcon
|
||||
? html `<mdui-icon name="${this.endIcon}"></mdui-icon>`
|
||||
: nothingTemplate}</slot>`;
|
||||
}
|
||||
renderInner() {
|
||||
return [this.renderIcon(), this.renderLabel(), this.renderEndIcon()];
|
||||
}
|
||||
};
|
||||
Button.styles = [ButtonBase.styles, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Button.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'full-width',
|
||||
})
|
||||
], Button.prototype, "fullWidth", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Button.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'end-icon' })
|
||||
], Button.prototype, "endIcon", void 0);
|
||||
Button = __decorate([
|
||||
customElement('mdui-button')
|
||||
], Button);
|
||||
export { Button };
|
||||
1
mdui_patched/components/button/style.d.ts
vendored
Normal file
1
mdui_patched/components/button/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
4
mdui_patched/components/button/style.js
Normal file
4
mdui_patched/components/button/style.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-full);position:relative;display:inline-block;flex-shrink:0;overflow:hidden;text-align:center;border-radius:var(--shape-corner);cursor:pointer;-webkit-tap-highlight-color:transparent;transition:box-shadow var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear);min-width:3rem;height:2.5rem;color:rgb(var(--mdui-color-primary));font-size:var(--mdui-typescale-label-large-size);font-weight:var(--mdui-typescale-label-large-weight);letter-spacing:var(--mdui-typescale-label-large-tracking);line-height:var(--mdui-typescale-label-large-line-height)}.button{width:100%;padding:0 1rem}:host([full-width]:not([full-width=false i])){display:block}:host([variant=elevated]){box-shadow:var(--mdui-elevation-level1);background-color:rgb(var(--mdui-color-surface-container-low));--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=filled]){color:rgb(var(--mdui-color-on-primary));background-color:rgb(var(--mdui-color-primary));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-primary)}:host([variant=tonal]){color:rgb(var(--mdui-color-on-secondary-container));background-color:rgb(var(--mdui-color-secondary-container));--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-secondary-container
|
||||
)}:host([variant=outlined]){border:.0625rem solid rgb(var(--mdui-color-outline));--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=text]){--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=outlined][focus-visible]){border-color:rgb(var(--mdui-color-primary))}:host([variant=elevated][hover]){box-shadow:var(--mdui-elevation-level2)}:host([variant=filled][hover]),:host([variant=tonal][hover]){box-shadow:var(--mdui-elevation-level1)}:host([disabled]:not([disabled=false i])),:host([loading]:not([loading=false i])){cursor:default;pointer-events:none}:host([disabled]:not([disabled=false i])){color:rgba(var(--mdui-color-on-surface),38%);box-shadow:var(--mdui-elevation-level0)}:host([variant=elevated][disabled]:not([disabled=false i])),:host([variant=filled][disabled]:not([disabled=false i])),:host([variant=tonal][disabled]:not([disabled=false i])){background-color:rgba(var(--mdui-color-on-surface),12%)}:host([variant=outlined][disabled]:not([disabled=false i])){border-color:rgba(var(--mdui-color-on-surface),12%)}.label{display:inline-flex;padding-right:.5rem;padding-left:.5rem}.end-icon,.icon{display:inline-flex;font-size:1.28571429em}.end-icon mdui-icon,.icon mdui-icon,::slotted([slot=end-icon]),::slotted([slot=icon]){font-size:inherit}mdui-circular-progress{display:inline-flex;width:1.125rem;height:1.125rem}:host([variant=filled]) mdui-circular-progress{stroke:rgb(var(--mdui-color-on-primary))}:host([variant=tonal]) mdui-circular-progress{stroke:rgb(var(--mdui-color-on-secondary-container))}:host([disabled]:not([disabled=false i])) mdui-circular-progress{stroke:rgba(var(--mdui-color-on-surface),38%)}`;
|
||||
1
mdui_patched/components/card.d.ts
vendored
Normal file
1
mdui_patched/components/card.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './card/index.js';
|
||||
1
mdui_patched/components/card.js
Normal file
1
mdui_patched/components/card.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './card/index.js';
|
||||
53
mdui_patched/components/card/index.d.ts
vendored
Normal file
53
mdui_patched/components/card/index.d.ts
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { TemplateResult, CSSResultGroup } from 'lit';
|
||||
declare const Card_base: import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/anchor.js").AnchorMixinInterface> & import("@lit/reactive-element/decorators/base.js").Constructor<import("../ripple/ripple-mixin.js").RippleMixinInterface> & import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/focusable.js").FocusableMixinInterface> & typeof MduiElement;
|
||||
/**
|
||||
* @summary 卡片组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-card>card content</mdui-card>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
*
|
||||
* @slot - 卡片的内容
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Card extends Card_base<CardEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 卡片的形状。可选值包括:
|
||||
*
|
||||
* * `elevated`:带阴影的卡片,与背景的视觉分离度较高
|
||||
* * `filled`:带填充色的卡片,与背景的视觉分离度较低
|
||||
* * `outlined`:带边框的卡片,与背景的视觉分离度最高
|
||||
*/
|
||||
variant: /*带阴影的卡片,与背景的视觉分离度较高*/ 'elevated' | /*带填充色的卡片,与背景的视觉分离度较低*/ 'filled' | /*带边框的卡片,与背景的视觉分离度最高*/ 'outlined';
|
||||
/**
|
||||
* 是否可点击。为 `true` 时,卡片将具有鼠标悬浮效果和点击涟漪效果
|
||||
*/
|
||||
clickable: boolean;
|
||||
/**
|
||||
* 是否禁用
|
||||
*/
|
||||
disabled: boolean;
|
||||
private readonly rippleRef;
|
||||
protected get rippleElement(): Ripple;
|
||||
protected get rippleDisabled(): boolean;
|
||||
protected get focusElement(): HTMLElement | null;
|
||||
protected get focusDisabled(): boolean;
|
||||
protected render(): TemplateResult;
|
||||
}
|
||||
export interface CardEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-card': Card;
|
||||
}
|
||||
}
|
||||
export {};
|
||||
91
mdui_patched/components/card/index.js
Normal file
91
mdui_patched/components/card/index.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { AnchorMixin } from '@mdui/shared/mixins/anchor.js';
|
||||
import { FocusableMixin } from '@mdui/shared/mixins/focusable.js';
|
||||
import { RippleMixin } from '../ripple/ripple-mixin.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 卡片组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-card>card content</mdui-card>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
*
|
||||
* @slot - 卡片的内容
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Card = class Card extends AnchorMixin(RippleMixin(FocusableMixin(MduiElement))) {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 卡片的形状。可选值包括:
|
||||
*
|
||||
* * `elevated`:带阴影的卡片,与背景的视觉分离度较高
|
||||
* * `filled`:带填充色的卡片,与背景的视觉分离度较低
|
||||
* * `outlined`:带边框的卡片,与背景的视觉分离度最高
|
||||
*/
|
||||
this.variant = 'elevated';
|
||||
/**
|
||||
* 是否可点击。为 `true` 时,卡片将具有鼠标悬浮效果和点击涟漪效果
|
||||
*/
|
||||
this.clickable = false;
|
||||
/**
|
||||
* 是否禁用
|
||||
*/
|
||||
this.disabled = false;
|
||||
this.rippleRef = createRef();
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
get rippleDisabled() {
|
||||
return this.disabled || (!this.href && !this.clickable);
|
||||
}
|
||||
get focusElement() {
|
||||
return this.href && !this.disabled
|
||||
? this.renderRoot.querySelector('._a')
|
||||
: this;
|
||||
}
|
||||
get focusDisabled() {
|
||||
return this.rippleDisabled;
|
||||
}
|
||||
render() {
|
||||
return html `<mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple>${this.href && !this.disabled
|
||||
? this.renderAnchor({
|
||||
className: 'link',
|
||||
content: html `<slot></slot>`,
|
||||
})
|
||||
: html `<slot></slot>`}`;
|
||||
}
|
||||
};
|
||||
Card.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Card.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Card.prototype, "clickable", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Card.prototype, "disabled", void 0);
|
||||
Card = __decorate([
|
||||
customElement('mdui-card')
|
||||
], Card);
|
||||
export { Card };
|
||||
1
mdui_patched/components/card/style.d.ts
vendored
Normal file
1
mdui_patched/components/card/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/card/style.js
Normal file
2
mdui_patched/components/card/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-medium);position:relative;display:inline-block;overflow:hidden;border-radius:var(--shape-corner);-webkit-tap-highlight-color:transparent;transition:box-shadow var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear);--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface)}:host([clickable]:not([clickable=false i])){cursor:pointer}:host([variant=elevated]){background-color:rgb(var(--mdui-color-surface-container-low));box-shadow:var(--mdui-elevation-level1)}:host([variant=filled]){background-color:rgb(var(--mdui-color-surface-container-highest))}:host([variant=outlined]){background-color:rgb(var(--mdui-color-surface));border:.0625rem solid rgb(var(--mdui-color-outline))}:host([variant=elevated][hover]){box-shadow:var(--mdui-elevation-level2)}:host([variant=filled][hover]),:host([variant=outlined][hover]){box-shadow:var(--mdui-elevation-level1)}:host([variant=elevated][dragged]),:host([variant=filled][dragged]),:host([variant=outlined][dragged]){box-shadow:var(--mdui-elevation-level3)}:host([disabled]:not([disabled=false i])){opacity:.38;cursor:default;-webkit-user-select:none;user-select:none}:host([variant=elevated][disabled]:not([disabled=false i])){background-color:rgb(var(--mdui-color-surface-variant));box-shadow:var(--mdui-elevation-level0)}:host([variant=filled][disabled]:not([disabled=false i])){background-color:rgb(var(--mdui-color-surface));box-shadow:var(--mdui-elevation-level1)}:host([variant=outlined][disabled]:not([disabled=false i])){box-shadow:var(--mdui-elevation-level0);border-color:rgba(var(--mdui-color-outline),.32)}.link{position:relative;display:inline-block;width:100%;height:100%;color:inherit;font-size:inherit;letter-spacing:inherit;text-decoration:none;touch-action:manipulation;-webkit-user-drag:none}`;
|
||||
1
mdui_patched/components/checkbox.d.ts
vendored
Normal file
1
mdui_patched/components/checkbox.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './checkbox/index.js';
|
||||
1
mdui_patched/components/checkbox.js
Normal file
1
mdui_patched/components/checkbox.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './checkbox/index.js';
|
||||
137
mdui_patched/components/checkbox/index.d.ts
vendored
Normal file
137
mdui_patched/components/checkbox/index.d.ts
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import '@mdui/shared/icons/check-box-outline-blank.js';
|
||||
import '@mdui/shared/icons/check-box.js';
|
||||
import '@mdui/shared/icons/indeterminate-check-box.js';
|
||||
import '../icon.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { FormControl } from '@mdui/jq/shared/form.js';
|
||||
import type { TemplateResult, CSSResultGroup } from 'lit';
|
||||
declare const Checkbox_base: import("@lit/reactive-element/decorators/base.js").Constructor<import("../ripple/ripple-mixin.js").RippleMixinInterface> & import("@lit/reactive-element/decorators/base.js").Constructor<import("@mdui/shared/mixins/focusable.js").FocusableMixinInterface> & typeof MduiElement;
|
||||
/**
|
||||
* @summary 复选框组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-checkbox>Checkbox</mdui-checkbox>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event input - 选中状态变更时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 复选框文本
|
||||
* @slot unchecked-icon - 未选中状态的图标
|
||||
* @slot checked-icon - 选中状态的图标
|
||||
* @slot indeterminate-icon - 不确定状态的图标
|
||||
*
|
||||
* @csspart control - 左侧图标容器
|
||||
* @csspart unchecked-icon - 未选中状态的图标
|
||||
* @csspart checked-icon - 选中状态的图标
|
||||
* @csspart indeterminate-icon - 不确定状态的图标
|
||||
* @csspart label - 复选框文本
|
||||
*/
|
||||
export declare class Checkbox extends Checkbox_base<CheckboxEventMap> implements FormControl {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否为禁用状态
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 是否为选中状态
|
||||
*/
|
||||
checked: boolean;
|
||||
/**
|
||||
* 默认选中状态。在重置表单时,将恢复为此状态。此属性只能通过 JavaScript 属性设置
|
||||
*/
|
||||
defaultChecked: boolean;
|
||||
/**
|
||||
* 是否处于不确定状态
|
||||
*/
|
||||
indeterminate: boolean;
|
||||
/**
|
||||
* 提交表单时,是否必须选中此复选框
|
||||
*/
|
||||
required: boolean;
|
||||
/**
|
||||
* 关联的 `<form>` 元素。此属性值应为同一页面中的一个 `<form>` 元素的 `id`。
|
||||
*
|
||||
* 如果未指定此属性,则该元素必须是 `<form>` 元素的子元素。通过此属性,你可以将元素放置在页面的任何位置,而不仅仅是 `<form>` 元素的子元素。
|
||||
*/
|
||||
form?: string;
|
||||
/**
|
||||
* 复选框名称,将与表单数据一起提交
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 复选框的值,将于表单数据一起提交
|
||||
*/
|
||||
value: string;
|
||||
/**
|
||||
* 未选中状态的 Material Icons 图标名。也可以通过 `slot="unchecked-icon"` 设置
|
||||
*/
|
||||
uncheckedIcon?: string;
|
||||
/**
|
||||
* 选中状态的 Material Icons 图标名。也可以通过 `slot="checked-icon"` 设置
|
||||
*/
|
||||
checkedIcon?: string;
|
||||
/**
|
||||
* 不确定状态的 Material Icons 图标名。也可以通过 `slot="indeterminate-icon"` 设置
|
||||
*/
|
||||
indeterminateIcon?: string;
|
||||
/**
|
||||
* 是否验证未通过
|
||||
*/
|
||||
private invalid;
|
||||
private readonly inputRef;
|
||||
private readonly rippleRef;
|
||||
private readonly formController;
|
||||
/**
|
||||
* 表单验证状态对象,具体参见 [`ValidityState`](https://developer.mozilla.org/zh-CN/docs/Web/API/ValidityState)
|
||||
*/
|
||||
get validity(): ValidityState;
|
||||
/**
|
||||
* 如果表单验证未通过,此属性将包含提示信息。如果验证通过,此属性将为空字符串
|
||||
*/
|
||||
get validationMessage(): string;
|
||||
protected get rippleElement(): Ripple;
|
||||
protected get rippleDisabled(): boolean;
|
||||
protected get focusElement(): HTMLElement | undefined;
|
||||
protected get focusDisabled(): boolean;
|
||||
private onDisabledChange;
|
||||
private onCheckedChange;
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`
|
||||
*/
|
||||
checkValidity(): boolean;
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`。
|
||||
*
|
||||
* 如果验证未通过,还会在组件上显示验证失败的提示。
|
||||
*/
|
||||
reportValidity(): boolean;
|
||||
/**
|
||||
* 设置自定义的错误提示文本。只要这个文本不为空,就表示字段未通过验证
|
||||
*
|
||||
* @param message 自定义的错误提示文本
|
||||
*/
|
||||
setCustomValidity(message: string): void;
|
||||
protected render(): TemplateResult;
|
||||
/**
|
||||
* input[type="checkbox"] 的 change 事件无法冒泡越过 shadow dom
|
||||
*/
|
||||
private onChange;
|
||||
}
|
||||
export interface CheckboxEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
change: CustomEvent<void>;
|
||||
input: Event;
|
||||
invalid: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-checkbox': Checkbox;
|
||||
}
|
||||
}
|
||||
export {};
|
||||
254
mdui_patched/components/checkbox/index.js
Normal file
254
mdui_patched/components/checkbox/index.js
Normal file
@@ -0,0 +1,254 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { FormController, formResets } from '@mdui/shared/controllers/form.js';
|
||||
import { defaultValue } from '@mdui/shared/decorators/default-value.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import '@mdui/shared/icons/check-box-outline-blank.js';
|
||||
import '@mdui/shared/icons/check-box.js';
|
||||
import '@mdui/shared/icons/indeterminate-check-box.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { FocusableMixin } from '@mdui/shared/mixins/focusable.js';
|
||||
import '../icon.js';
|
||||
import { RippleMixin } from '../ripple/ripple-mixin.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 复选框组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-checkbox>Checkbox</mdui-checkbox>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event input - 选中状态变更时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 复选框文本
|
||||
* @slot unchecked-icon - 未选中状态的图标
|
||||
* @slot checked-icon - 选中状态的图标
|
||||
* @slot indeterminate-icon - 不确定状态的图标
|
||||
*
|
||||
* @csspart control - 左侧图标容器
|
||||
* @csspart unchecked-icon - 未选中状态的图标
|
||||
* @csspart checked-icon - 选中状态的图标
|
||||
* @csspart indeterminate-icon - 不确定状态的图标
|
||||
* @csspart label - 复选框文本
|
||||
*/
|
||||
let Checkbox = class Checkbox extends RippleMixin(FocusableMixin(MduiElement)) {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否为禁用状态
|
||||
*/
|
||||
this.disabled = false;
|
||||
/**
|
||||
* 是否为选中状态
|
||||
*/
|
||||
this.checked = false;
|
||||
/**
|
||||
* 默认选中状态。在重置表单时,将恢复为此状态。此属性只能通过 JavaScript 属性设置
|
||||
*/
|
||||
this.defaultChecked = false;
|
||||
/**
|
||||
* 是否处于不确定状态
|
||||
*/
|
||||
this.indeterminate = false;
|
||||
/**
|
||||
* 提交表单时,是否必须选中此复选框
|
||||
*/
|
||||
this.required = false;
|
||||
/**
|
||||
* 复选框名称,将与表单数据一起提交
|
||||
*/
|
||||
this.name = '';
|
||||
/**
|
||||
* 复选框的值,将于表单数据一起提交
|
||||
*/
|
||||
this.value = 'on';
|
||||
/**
|
||||
* 是否验证未通过
|
||||
*/
|
||||
this.invalid = false;
|
||||
this.inputRef = createRef();
|
||||
this.rippleRef = createRef();
|
||||
this.formController = new FormController(this, {
|
||||
value: (control) => (control.checked ? control.value : undefined),
|
||||
defaultValue: (control) => control.defaultChecked,
|
||||
setValue: (control, checked) => (control.checked = checked),
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 表单验证状态对象,具体参见 [`ValidityState`](https://developer.mozilla.org/zh-CN/docs/Web/API/ValidityState)
|
||||
*/
|
||||
get validity() {
|
||||
return this.inputRef.value.validity;
|
||||
}
|
||||
/**
|
||||
* 如果表单验证未通过,此属性将包含提示信息。如果验证通过,此属性将为空字符串
|
||||
*/
|
||||
get validationMessage() {
|
||||
return this.inputRef.value.validationMessage;
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
get rippleDisabled() {
|
||||
return this.disabled;
|
||||
}
|
||||
get focusElement() {
|
||||
return this.inputRef.value;
|
||||
}
|
||||
get focusDisabled() {
|
||||
return this.disabled;
|
||||
}
|
||||
async onDisabledChange() {
|
||||
await this.updateComplete;
|
||||
this.invalid = !this.inputRef.value.checkValidity();
|
||||
}
|
||||
async onCheckedChange() {
|
||||
await this.updateComplete;
|
||||
// reset 引起的值变更,不执行验证;直接修改值引起的变更,需要进行验证
|
||||
const form = this.formController.getForm();
|
||||
if (form && formResets.get(form)?.has(this)) {
|
||||
this.invalid = false;
|
||||
formResets.get(form).delete(this);
|
||||
}
|
||||
else {
|
||||
this.invalid = !this.inputRef.value.checkValidity();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`
|
||||
*/
|
||||
checkValidity() {
|
||||
const valid = this.inputRef.value.checkValidity();
|
||||
if (!valid) {
|
||||
this.emit('invalid', {
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
composed: false,
|
||||
});
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
/**
|
||||
* 检查表单字段是否通过验证。如果未通过,返回 `false` 并触发 `invalid` 事件;如果通过,返回 `true`。
|
||||
*
|
||||
* 如果验证未通过,还会在组件上显示验证失败的提示。
|
||||
*/
|
||||
reportValidity() {
|
||||
this.invalid = !this.inputRef.value.reportValidity();
|
||||
if (this.invalid) {
|
||||
const eventProceeded = this.emit('invalid', {
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
composed: false,
|
||||
});
|
||||
// 调用了 preventDefault() 时,隐藏默认的表单错误提示
|
||||
if (!eventProceeded) {
|
||||
this.blur();
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
return !this.invalid;
|
||||
}
|
||||
/**
|
||||
* 设置自定义的错误提示文本。只要这个文本不为空,就表示字段未通过验证
|
||||
*
|
||||
* @param message 自定义的错误提示文本
|
||||
*/
|
||||
setCustomValidity(message) {
|
||||
this.inputRef.value.setCustomValidity(message);
|
||||
this.invalid = !this.inputRef.value.checkValidity();
|
||||
}
|
||||
render() {
|
||||
return html `<label class="${classMap({ invalid: this.invalid })}"><input ${ref(this.inputRef)} type="checkbox" name="${ifDefined(this.name)}" value="${ifDefined(this.value)}" .indeterminate="${live(this.indeterminate)}" .disabled="${this.disabled}" .checked="${live(this.checked)}" .required="${this.required}" @change="${this.onChange}"> <i part="control"><mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple><slot name="unchecked-icon" part="unchecked-icon" class="icon unchecked-icon">${this.uncheckedIcon
|
||||
? html `<mdui-icon name="${this.uncheckedIcon}" class="i"></mdui-icon>`
|
||||
: html `<mdui-icon-check-box-outline-blank class="i"></mdui-icon-check-box-outline-blank>`}</slot><slot name="checked-icon" part="checked-icon" class="icon checked-icon">${this.checkedIcon
|
||||
? html `<mdui-icon name="${this.checkedIcon}" class="i"></mdui-icon>`
|
||||
: html `<mdui-icon-check-box class="i"></mdui-icon-check-box>`}</slot><slot name="indeterminate-icon" part="indeterminate-icon" class="icon indeterminate-icon">${this.indeterminateIcon
|
||||
? html `<mdui-icon name="${this.indeterminateIcon}" class="i"></mdui-icon>`
|
||||
: html `<mdui-icon-indeterminate-check-box class="i"></mdui-icon-indeterminate-check-box>`}</slot></i><slot part="label" class="label"></slot></label>`;
|
||||
}
|
||||
/**
|
||||
* input[type="checkbox"] 的 change 事件无法冒泡越过 shadow dom
|
||||
*/
|
||||
onChange() {
|
||||
this.checked = this.inputRef.value.checked;
|
||||
this.indeterminate = false;
|
||||
this.emit('change');
|
||||
}
|
||||
};
|
||||
Checkbox.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Checkbox.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Checkbox.prototype, "checked", void 0);
|
||||
__decorate([
|
||||
defaultValue('checked')
|
||||
], Checkbox.prototype, "defaultChecked", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Checkbox.prototype, "indeterminate", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Checkbox.prototype, "required", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Checkbox.prototype, "form", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Checkbox.prototype, "name", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Checkbox.prototype, "value", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'unchecked-icon' })
|
||||
], Checkbox.prototype, "uncheckedIcon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'checked-icon' })
|
||||
], Checkbox.prototype, "checkedIcon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'indeterminate-icon' })
|
||||
], Checkbox.prototype, "indeterminateIcon", void 0);
|
||||
__decorate([
|
||||
state()
|
||||
], Checkbox.prototype, "invalid", void 0);
|
||||
__decorate([
|
||||
watch('disabled', true),
|
||||
watch('indeterminate', true),
|
||||
watch('required', true)
|
||||
], Checkbox.prototype, "onDisabledChange", null);
|
||||
__decorate([
|
||||
watch('checked', true)
|
||||
], Checkbox.prototype, "onCheckedChange", null);
|
||||
Checkbox = __decorate([
|
||||
customElement('mdui-checkbox')
|
||||
], Checkbox);
|
||||
export { Checkbox };
|
||||
1
mdui_patched/components/checkbox/style.d.ts
vendored
Normal file
1
mdui_patched/components/checkbox/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/checkbox/style.js
Normal file
2
mdui_patched/components/checkbox/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{position:relative;display:inline-flex;cursor:pointer;-webkit-tap-highlight-color:transparent;border-radius:.125rem;font-size:var(--mdui-typescale-label-large-size);font-weight:var(--mdui-typescale-label-large-weight);letter-spacing:var(--mdui-typescale-label-large-tracking);line-height:var(--mdui-typescale-label-large-line-height)}label{display:inline-flex;align-items:center;width:100%;cursor:inherit;-webkit-user-select:none;user-select:none;touch-action:manipulation;zoom:1;-webkit-user-drag:none}input{position:absolute;padding:0;opacity:0;pointer-events:none;width:1.125rem;height:1.125rem;margin:0 0 0 .6875rem}.icon{display:flex;position:absolute;opacity:1;transform:scale(1);color:rgb(var(--mdui-color-on-surface));font-size:1.5rem;transition:color var(--mdui-motion-duration-short4) var(--mdui-motion-easing-standard)}.checked-icon,.indeterminate-icon{opacity:0;transform:scale(.5);transition-property:color,opacity,transform;transition-duration:var(--mdui-motion-duration-short4);transition-timing-function:var(--mdui-motion-easing-standard)}.icon .i,::slotted([slot=checked-icon]),::slotted([slot=indeterminate-icon]),::slotted([slot=unchecked-icon]){color:inherit;font-size:inherit}i{position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;border-radius:50%;width:2.5rem;height:2.5rem;--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface)}.label{display:flex;width:100%;padding-top:.625rem;padding-bottom:.625rem;color:rgb(var(--mdui-color-on-surface));transition:color var(--mdui-motion-duration-short4) var(--mdui-motion-easing-standard)}:host([checked]:not([checked=false i])) i{--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([checked]:not([checked=false i])) .icon{color:rgb(var(--mdui-color-primary))}:host([checked]:not([checked=false i])) .indeterminate-icon{opacity:0;transform:scale(.5)}:host([checked]:not([checked=false i])) .checked-icon{opacity:1;transform:scale(1)}:host([indeterminate]:not([indeterminate=false i])) i{--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([indeterminate]:not([indeterminate=false i])) .icon{color:rgb(var(--mdui-color-primary))}:host([indeterminate]:not([indeterminate=false i])) .checked-icon{opacity:0;transform:scale(.5)}:host([indeterminate]:not([indeterminate=false i])) .indeterminate-icon{opacity:1;transform:scale(1)}.invalid i{--mdui-comp-ripple-state-layer-color:var(--mdui-color-error)}.invalid .icon{color:rgb(var(--mdui-color-error))}.invalid .label{color:rgb(var(--mdui-color-error))}:host([disabled]:not([disabled=false i])){cursor:default;pointer-events:none}:host([disabled]:not([disabled=false i])) .icon{color:rgba(var(--mdui-color-on-surface),38%)}:host([disabled]:not([disabled=false i])) .label{color:rgba(var(--mdui-color-on-surface),38%)}:host([disabled][checked]:not([disabled=false i],[checked=false i])) .unchecked-icon,:host([disabled][indeterminate]:not([disabled=false i],[indeterminate=false i])) .unchecked-icon{opacity:0}`;
|
||||
1
mdui_patched/components/chip.d.ts
vendored
Normal file
1
mdui_patched/components/chip.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './chip/index.js';
|
||||
1
mdui_patched/components/chip.js
Normal file
1
mdui_patched/components/chip.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './chip/index.js';
|
||||
109
mdui_patched/components/chip/index.d.ts
vendored
Normal file
109
mdui_patched/components/chip/index.d.ts
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
import '@mdui/shared/icons/check.js';
|
||||
import '@mdui/shared/icons/clear.js';
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 纸片组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-chip>Chip</mdui-chip>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event delete - 点击删除图标时触发
|
||||
*
|
||||
* @slot - 纸片文本
|
||||
* @slot icon - 左侧元素
|
||||
* @slot end-icon - 右侧元素
|
||||
* @slot selected-icon - 选中状态下的左侧元素
|
||||
* @slot delete-icon - 可删除时的右侧删除元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 纸片文本
|
||||
* @csspart icon - 左侧图标
|
||||
* @csspart end-icon - 右侧图标
|
||||
* @csspart selected-icon - 选中状态下的左侧图标
|
||||
* @csspart delete-icon - 可删除时的右侧删除图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Chip extends ButtonBase<ChipEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 纸片的形状。可选值包括:
|
||||
*
|
||||
* * `assist`:用于显示与当前上下文相关的辅助操作,如在点餐页面提供分享、收藏等功能
|
||||
* * `filter`:用于对内容进行筛选,如在搜索结果页过滤搜索结果
|
||||
* * `input`:用于表示用户输入的信息片段,如在 Gmail 的“收件人”字段中的联系人
|
||||
* * `suggestion`:用于提供动态生成的推荐信息,以简化用户操作,如在聊天应用中预测用户可能想发送的信息
|
||||
*/
|
||||
variant: /*用于显示与当前上下文相关的辅助操作,如在点餐页面提供分享、收藏等功能*/ 'assist' | /*用于对内容进行筛选,如在搜索结果页过滤搜索结果*/ 'filter' | /*用于表示用户输入的信息片段,如在 Gmail 的“收件人”字段中的联系人*/ 'input' | /*用于提供动态生成的推荐信息,以简化用户操作,如在聊天应用中预测用户可能想发送的信息*/ 'suggestion';
|
||||
/**
|
||||
* 是否显示阴影
|
||||
*/
|
||||
elevated: boolean;
|
||||
/**
|
||||
* 是否可选中
|
||||
*/
|
||||
selectable: boolean;
|
||||
/**
|
||||
* 是否已选中
|
||||
*/
|
||||
selected: boolean;
|
||||
/**
|
||||
* 是否可删除。为 `true` 时,纸片右侧会显示删除图标
|
||||
*/
|
||||
deletable: boolean;
|
||||
/**
|
||||
* 左侧的 Material Icons 图标名。也可以通过 `slot="icon"` 设置
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 选中状态下左侧的 Material Icons 图标名。也可以通过 `slot="selected-icon"` 设置
|
||||
*/
|
||||
selectedIcon?: string;
|
||||
/**
|
||||
* 右侧的 Material Icons 图标名。也可以通过 `slot="end-icon"` 设置
|
||||
*/
|
||||
endIcon?: string;
|
||||
/**
|
||||
* 可删除时,右侧删除图标的 Material Icons 图标名。也可以通过 `slot="delete-icon"` 设置
|
||||
*/
|
||||
deleteIcon?: string;
|
||||
private readonly rippleRef;
|
||||
private readonly hasSlotController;
|
||||
constructor();
|
||||
protected get rippleElement(): Ripple;
|
||||
private onSelectedChange;
|
||||
protected firstUpdated(changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
private onClick;
|
||||
private onKeyDown;
|
||||
/**
|
||||
* 点击删除按钮
|
||||
*/
|
||||
private onDelete;
|
||||
private renderIcon;
|
||||
private renderLabel;
|
||||
private renderEndIcon;
|
||||
private renderDeleteIcon;
|
||||
private renderInner;
|
||||
}
|
||||
export interface ChipEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
invalid: CustomEvent<void>;
|
||||
change: CustomEvent<void>;
|
||||
delete: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-chip': Chip;
|
||||
}
|
||||
}
|
||||
243
mdui_patched/components/chip/index.js
Normal file
243
mdui_patched/components/chip/index.js
Normal file
@@ -0,0 +1,243 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import cc from 'classcat';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import '@mdui/shared/icons/check.js';
|
||||
import '@mdui/shared/icons/clear.js';
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 纸片组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-chip>Chip</mdui-chip>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
* @event change - 选中状态变更时触发
|
||||
* @event delete - 点击删除图标时触发
|
||||
*
|
||||
* @slot - 纸片文本
|
||||
* @slot icon - 左侧元素
|
||||
* @slot end-icon - 右侧元素
|
||||
* @slot selected-icon - 选中状态下的左侧元素
|
||||
* @slot delete-icon - 可删除时的右侧删除元素
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 纸片文本
|
||||
* @csspart icon - 左侧图标
|
||||
* @csspart end-icon - 右侧图标
|
||||
* @csspart selected-icon - 选中状态下的左侧图标
|
||||
* @csspart delete-icon - 可删除时的右侧删除图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Chip = class Chip extends ButtonBase {
|
||||
constructor() {
|
||||
super();
|
||||
/**
|
||||
* 纸片的形状。可选值包括:
|
||||
*
|
||||
* * `assist`:用于显示与当前上下文相关的辅助操作,如在点餐页面提供分享、收藏等功能
|
||||
* * `filter`:用于对内容进行筛选,如在搜索结果页过滤搜索结果
|
||||
* * `input`:用于表示用户输入的信息片段,如在 Gmail 的“收件人”字段中的联系人
|
||||
* * `suggestion`:用于提供动态生成的推荐信息,以简化用户操作,如在聊天应用中预测用户可能想发送的信息
|
||||
*/
|
||||
this.variant = 'assist';
|
||||
/**
|
||||
* 是否显示阴影
|
||||
*/
|
||||
this.elevated = false;
|
||||
/**
|
||||
* 是否可选中
|
||||
*/
|
||||
this.selectable = false;
|
||||
/**
|
||||
* 是否已选中
|
||||
*/
|
||||
this.selected = false;
|
||||
/**
|
||||
* 是否可删除。为 `true` 时,纸片右侧会显示删除图标
|
||||
*/
|
||||
this.deletable = false;
|
||||
this.rippleRef = createRef();
|
||||
this.hasSlotController = new HasSlotController(this, 'icon', 'selected-icon', 'end-icon');
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
onSelectedChange() {
|
||||
this.emit('change');
|
||||
}
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener('click', this.onClick);
|
||||
this.addEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
render() {
|
||||
const hasIcon = this.icon || this.hasSlotController.test('icon');
|
||||
const hasEndIcon = this.endIcon || this.hasSlotController.test('end-icon');
|
||||
const hasSelectedIcon = this.selectedIcon ||
|
||||
['assist', 'filter'].includes(this.variant) ||
|
||||
hasIcon ||
|
||||
this.hasSlotController.test('selected-icon');
|
||||
const className = cc({
|
||||
button: true,
|
||||
'has-icon': this.loading ||
|
||||
(!this.selected && hasIcon) ||
|
||||
(this.selected && hasSelectedIcon),
|
||||
'has-end-icon': hasEndIcon,
|
||||
});
|
||||
return html `<mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple>${this.isButton()
|
||||
? this.renderButton({
|
||||
className,
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})
|
||||
: this.disabled || this.loading
|
||||
? html `<span part="button" class="${className} _a">${this.renderInner()}</span>`
|
||||
: this.renderAnchor({
|
||||
className,
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})}`;
|
||||
}
|
||||
onClick() {
|
||||
if (this.disabled || this.loading) {
|
||||
return;
|
||||
}
|
||||
// 点击时,切换选中状态
|
||||
if (this.selectable) {
|
||||
this.selected = !this.selected;
|
||||
}
|
||||
}
|
||||
onKeyDown(event) {
|
||||
if (this.disabled || this.loading) {
|
||||
return;
|
||||
}
|
||||
// 按下空格键时,切换选中状态
|
||||
if (this.selectable && event.key === ' ') {
|
||||
event.preventDefault();
|
||||
this.selected = !this.selected;
|
||||
}
|
||||
// 按下 Delete 或 BackSpace 键时,触发 delete 事件
|
||||
if (this.deletable && ['Delete', 'Backspace'].includes(event.key)) {
|
||||
this.emit('delete');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 点击删除按钮
|
||||
*/
|
||||
onDelete(event) {
|
||||
event.stopPropagation();
|
||||
this.emit('delete');
|
||||
}
|
||||
renderIcon() {
|
||||
if (this.loading) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
const icon = () => {
|
||||
return this.icon
|
||||
? html `<mdui-icon name="${this.icon}" class="i"></mdui-icon>`
|
||||
: nothingTemplate;
|
||||
};
|
||||
const selectedIcon = () => {
|
||||
if (this.selectedIcon) {
|
||||
return html `<mdui-icon name="${this.selectedIcon}" class="i"></mdui-icon>`;
|
||||
}
|
||||
if (this.variant === 'assist' || this.variant === 'filter') {
|
||||
return html `<mdui-icon-check class="i"></mdui-icon-check>`;
|
||||
}
|
||||
return icon();
|
||||
};
|
||||
return !this.selected
|
||||
? html `<slot name="icon" part="icon" class="icon">${icon()}</slot>`
|
||||
: html `<slot name="selected-icon" part="selected-icon" class="selected-icon">${selectedIcon()}</slot>`;
|
||||
}
|
||||
renderLabel() {
|
||||
return html `<slot part="label" class="label"></slot>`;
|
||||
}
|
||||
renderEndIcon() {
|
||||
return html `<slot name="end-icon" part="end-icon" class="end-icon">${this.endIcon
|
||||
? html `<mdui-icon name="${this.endIcon}" class="i"></mdui-icon>`
|
||||
: nothingTemplate}</slot>`;
|
||||
}
|
||||
renderDeleteIcon() {
|
||||
if (!this.deletable) {
|
||||
return nothingTemplate;
|
||||
}
|
||||
return html `<slot name="delete-icon" part="delete-icon" class="delete-icon" @click="${this.onDelete}">${this.deleteIcon
|
||||
? html `<mdui-icon name="${this.deleteIcon}" class="i"></mdui-icon>`
|
||||
: html `<mdui-icon-clear class="i"></mdui-icon-clear>`}</slot>`;
|
||||
}
|
||||
renderInner() {
|
||||
return [
|
||||
this.renderIcon(),
|
||||
this.renderLabel(),
|
||||
this.renderEndIcon(),
|
||||
this.renderDeleteIcon(),
|
||||
];
|
||||
}
|
||||
};
|
||||
Chip.styles = [ButtonBase.styles, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Chip.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Chip.prototype, "elevated", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Chip.prototype, "selectable", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Chip.prototype, "selected", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Chip.prototype, "deletable", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Chip.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'selected-icon' })
|
||||
], Chip.prototype, "selectedIcon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'end-icon' })
|
||||
], Chip.prototype, "endIcon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true, attribute: 'delete-icon' })
|
||||
], Chip.prototype, "deleteIcon", void 0);
|
||||
__decorate([
|
||||
watch('selected', true)
|
||||
], Chip.prototype, "onSelectedChange", null);
|
||||
Chip = __decorate([
|
||||
customElement('mdui-chip')
|
||||
], Chip);
|
||||
export { Chip };
|
||||
1
mdui_patched/components/chip/style.d.ts
vendored
Normal file
1
mdui_patched/components/chip/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
4
mdui_patched/components/chip/style.js
Normal file
4
mdui_patched/components/chip/style.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-small);position:relative;display:inline-block;flex-shrink:0;overflow:hidden;border-radius:var(--shape-corner);cursor:pointer;-webkit-tap-highlight-color:transparent;transition:box-shadow var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear);height:2rem;background-color:rgb(var(--mdui-color-surface));border:.0625rem solid rgb(var(--mdui-color-outline));color:rgb(var(--mdui-color-on-surface-variant));font-size:var(--mdui-typescale-label-large-size);font-weight:var(--mdui-typescale-label-large-weight);letter-spacing:var(--mdui-typescale-label-large-tracking);line-height:var(--mdui-typescale-label-large-line-height);--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface-variant)}.button{padding-right:.4375rem;padding-left:.4375rem}:host([variant=input]) .button{padding-right:.1875rem;padding-left:.1875rem}:host([selected]:not([selected=false i])) .button{padding-right:.5rem;padding-left:.5rem}:host([selected][variant=input]:not([selected=false i])) .button{padding-right:.25rem;padding-left:.25rem}:host([elevated]:not([elevated=false i])) .button{padding-right:.5rem;padding-left:.5rem}:host([variant=assist]){color:rgb(var(--mdui-color-on-surface));--mdui-comp-ripple-state-layer-color:var(--mdui-color-on-surface)}:host([elevated]:not([elevated=false i])){border-width:0;background-color:rgb(var(--mdui-color-surface-container-low));box-shadow:var(--mdui-elevation-level1)}:host([selected]:not([selected=false i])){color:rgb(var(--mdui-color-on-secondary-container));background-color:rgb(var(--mdui-color-secondary-container));border-width:0;--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-secondary-container
|
||||
)}:host([disabled]:not([disabled=false i])),:host([loading]:not([loading=false i])){cursor:default;pointer-events:none}:host([disabled]:not([disabled=false i])){border-color:rgba(var(--mdui-color-on-surface),12%);color:rgba(var(--mdui-color-on-surface),38%);box-shadow:var(--mdui-elevation-level0)}:host([disabled][elevated]:not([disabled=false i],[elevated=false i])),:host([disabled][selected]:not([disabled=false i],[selected=false i])){background-color:rgba(var(--mdui-color-on-surface),12%)}:host([selected][hover]:not([selected=false i])){box-shadow:var(--mdui-elevation-level1)}:host([elevated][hover]:not([elevated=false i])){color:rgb(var(--mdui-color-on-secondary-container));box-shadow:var(--mdui-elevation-level2)}:host([variant=filter][hover]),:host([variant=input][hover]),:host([variant=suggestion][hover]){color:rgb(var(--mdui-color-on-surface-variant))}:host([variant=filter][focus-visible]),:host([variant=input][focus-visible]),:host([variant=suggestion][focus-visible]){border-color:rgb(var(--mdui-color-on-surface-variant))}:host([dragged]),:host([dragged][hover]){box-shadow:var(--mdui-elevation-level4)}.button{overflow:visible}.label{display:inline-flex;padding-right:.5rem;padding-left:.5rem}.end-icon,.icon,.selected-icon{display:inline-flex;font-size:1.28571429em;color:rgb(var(--mdui-color-on-surface-variant))}:host([variant=assist]) .end-icon,:host([variant=assist]) .icon,:host([variant=assist]) .selected-icon{color:rgb(var(--mdui-color-primary))}:host([selected]:not([selected=false i])) .end-icon,:host([selected]:not([selected=false i])) .icon,:host([selected]:not([selected=false i])) .selected-icon{color:rgb(var(--mdui-color-on-secondary-container))}:host([disabled]:not([disabled=false i])) .end-icon,:host([disabled]:not([disabled=false i])) .icon,:host([disabled]:not([disabled=false i])) .selected-icon{opacity:.38;color:rgb(var(--mdui-color-on-surface))}.end-icon .i,.icon .i,.selected-icon .i,::slotted([slot=end-icon]),::slotted([slot=icon]),::slotted([slot=selected-icon]){font-size:inherit}:host([variant=input]) .has-icon .icon,:host([variant=input]) .has-icon .selected-icon,:host([variant=input]) .has-icon mdui-circular-progress{margin-left:.25rem}:host([variant=input]) .has-end-icon .end-icon{margin-right:.25rem}mdui-circular-progress{display:inline-flex;width:1.125rem;height:1.125rem}:host([disabled]:not([disabled=false i])) mdui-circular-progress{stroke:rgba(var(--mdui-color-on-surface),38%)}::slotted(mdui-avatar[slot=end-icon]),::slotted(mdui-avatar[slot=icon]),::slotted(mdui-avatar[slot=selected-icon]){width:1.5rem;height:1.5rem}:host([disabled]:not([disabled=false i])) ::slotted(mdui-avatar[slot=end-icon]),:host([disabled]:not([disabled=false i])) ::slotted(mdui-avatar[slot=icon]),:host([disabled]:not([disabled=false i])) ::slotted(mdui-avatar[slot=selected-icon]){opacity:.38}::slotted(mdui-avatar[slot=icon]),::slotted(mdui-avatar[slot=selected-icon]){margin-left:-.25rem;margin-right:-.125rem}::slotted(mdui-avatar[slot=end-icon]){margin-right:-.25rem;margin-left:-.125rem}.delete-icon{display:inline-flex;font-size:1.28571429em;transition:background-color var(--mdui-motion-duration-short4) var(--mdui-motion-easing-linear);border-radius:var(--mdui-shape-corner-full);margin-right:-.25rem;margin-left:-.25rem;padding:.25rem;color:rgb(var(--mdui-color-on-surface-variant))}.delete-icon:hover{background-color:rgba(var(--mdui-color-on-surface-variant),12%)}.has-end-icon .delete-icon{margin-left:.25rem}:host([variant=assiat]) .delete-icon{color:rgb(var(--mdui-color-primary))}:host([variant=input]) .delete-icon{margin-right:.0625rem}:host([disabled]:not([disabled=false i])) .delete-icon{color:rgba(var(--mdui-color-on-surface),38%)}.delete-icon .i,::slotted([slot=delete-icon]){font-size:inherit}::slotted(mdui-avatar[slot=delete-icon]){width:1.125rem;height:1.125rem}`;
|
||||
1
mdui_patched/components/circular-progress.d.ts
vendored
Normal file
1
mdui_patched/components/circular-progress.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './circular-progress/index.js';
|
||||
1
mdui_patched/components/circular-progress.js
Normal file
1
mdui_patched/components/circular-progress.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './circular-progress/index.js';
|
||||
30
mdui_patched/components/circular-progress/index.d.ts
vendored
Normal file
30
mdui_patched/components/circular-progress/index.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 圆形进度指示器组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-circular-progress></mdui-circular-progress>
|
||||
* ```
|
||||
*/
|
||||
export declare class CircularProgress extends MduiElement<CircularProgressEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 进度指示器的最大值。默认为 `1`
|
||||
*/
|
||||
max: number;
|
||||
/**
|
||||
* 进度指示器的当前值。如果未指定该值,则显示为不确定状态
|
||||
*/
|
||||
value?: number;
|
||||
protected render(): TemplateResult;
|
||||
private renderDeterminate;
|
||||
private renderInDeterminate;
|
||||
}
|
||||
export interface CircularProgressEventMap {
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-circular-progress': CircularProgress;
|
||||
}
|
||||
}
|
||||
62
mdui_patched/components/circular-progress/index.js
Normal file
62
mdui_patched/components/circular-progress/index.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { isUndefined } from '@mdui/jq/shared/helper.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 圆形进度指示器组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-circular-progress></mdui-circular-progress>
|
||||
* ```
|
||||
*/
|
||||
let CircularProgress = class CircularProgress extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 进度指示器的最大值。默认为 `1`
|
||||
*/
|
||||
this.max = 1;
|
||||
}
|
||||
render() {
|
||||
const isDeterminate = !isUndefined(this.value);
|
||||
return html `<div class="progress ${classMap({
|
||||
determinate: isDeterminate,
|
||||
indeterminate: !isDeterminate,
|
||||
})}">${isDeterminate ? this.renderDeterminate() : this.renderInDeterminate()}</div>`;
|
||||
}
|
||||
renderDeterminate() {
|
||||
const value = this.value;
|
||||
const strokeWidth = 4; // 圆环宽度
|
||||
const circleRadius = 18; // 圆环宽度中心点的半径
|
||||
const π = 3.1415926;
|
||||
const center = circleRadius + strokeWidth / 2;
|
||||
const circumference = 2 * π * circleRadius;
|
||||
const determinateStrokeDashOffset = (1 - value / Math.max(this.max ?? value, value)) * circumference;
|
||||
return html `<svg viewBox="0 0 ${center * 2} ${center * 2}"><circle class="track" cx="${center}" cy="${center}" r="${circleRadius}" stroke-width="${strokeWidth}"></circle><circle class="circle" cx="${center}" cy="${center}" r="${circleRadius}" stroke-dasharray="${2 * π * circleRadius}" stroke-dashoffset="${determinateStrokeDashOffset}" stroke-width="${strokeWidth}"></circle></svg>`;
|
||||
}
|
||||
renderInDeterminate() {
|
||||
const strokeWidth = 4; // 圆环宽度
|
||||
const circleRadius = 18; // 圆环宽度中心点的半径
|
||||
const π = 3.1415926;
|
||||
const center = circleRadius + strokeWidth / 2;
|
||||
const circumference = 2 * π * circleRadius;
|
||||
const halfCircumference = 0.5 * circumference;
|
||||
const circle = (thisStrokeWidth) => html `<svg class="circle" viewBox="0 0 ${center * 2} ${center * 2}"><circle cx="${center}" cy="${center}" r="${circleRadius}" stroke-dasharray="${circumference}" stroke-dashoffset="${halfCircumference}" stroke-width="${thisStrokeWidth}"></circle></svg>`;
|
||||
return html `<div class="layer"><div class="clipper left">${circle(strokeWidth)}</div><div class="gap-patch">${circle(strokeWidth * 0.8)}</div><div class="clipper right">${circle(strokeWidth)}</div></div>`;
|
||||
}
|
||||
};
|
||||
CircularProgress.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ type: Number, reflect: true })
|
||||
], CircularProgress.prototype, "max", void 0);
|
||||
__decorate([
|
||||
property({ type: Number })
|
||||
], CircularProgress.prototype, "value", void 0);
|
||||
CircularProgress = __decorate([
|
||||
customElement('mdui-circular-progress')
|
||||
], CircularProgress);
|
||||
export { CircularProgress };
|
||||
1
mdui_patched/components/circular-progress/style.d.ts
vendored
Normal file
1
mdui_patched/components/circular-progress/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/circular-progress/style.js
Normal file
2
mdui_patched/components/circular-progress/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{position:relative;display:inline-block;flex-shrink:0;width:2.5rem;height:2.5rem;stroke:rgb(var(--mdui-color-primary))}.progress{position:relative;display:inline-block;width:100%;height:100%;text-align:left;transition:opacity var(--mdui-motion-duration-medium1) var(--mdui-motion-easing-linear)}.determinate svg{transform:rotate(-90deg);fill:transparent}.determinate .track{stroke:transparent}.determinate .circle{stroke:inherit;transition:stroke-dashoffset var(--mdui-motion-duration-long2) var(--mdui-motion-easing-standard)}.indeterminate{font-size:0;letter-spacing:0;white-space:nowrap;animation:mdui-comp-circular-progress-rotate 1568ms var(--mdui-motion-easing-linear) infinite}.indeterminate .circle,.indeterminate .layer{position:absolute;width:100%;height:100%}.indeterminate .layer{animation:mdui-comp-circular-progress-layer-rotate 5332ms var(--mdui-motion-easing-standard) infinite both}.indeterminate .circle{fill:transparent;stroke:inherit}.indeterminate .gap-patch{position:absolute;top:0;left:47.5%;width:5%;height:100%;overflow:hidden}.indeterminate .gap-patch .circle{left:-900%;width:2000%;transform:rotate(180deg)}.indeterminate .clipper{position:relative;display:inline-block;width:50%;height:100%;overflow:hidden}.indeterminate .clipper .circle{width:200%}.indeterminate .clipper.left .circle{animation:mdui-comp-circular-progress-left-spin 1333ms var(--mdui-motion-easing-standard) infinite both}.indeterminate .clipper.right .circle{left:-100%;animation:mdui-comp-circular-progress-right-spin 1333ms var(--mdui-motion-easing-standard) infinite both}@keyframes mdui-comp-circular-progress-rotate{to{transform:rotate(360deg)}}@keyframes mdui-comp-circular-progress-layer-rotate{12.5%{transform:rotate(135deg)}25%{transform:rotate(270deg)}37.5%{transform:rotate(405deg)}50%{transform:rotate(540deg)}62.5%{transform:rotate(675deg)}75%{transform:rotate(810deg)}87.5%{transform:rotate(945deg)}100%{transform:rotate(1080deg)}}@keyframes mdui-comp-circular-progress-left-spin{0%{transform:rotate(265deg)}50%{transform:rotate(130deg)}100%{transform:rotate(265deg)}}@keyframes mdui-comp-circular-progress-right-spin{0%{transform:rotate(-265deg)}50%{transform:rotate(-130deg)}100%{transform:rotate(-265deg)}}`;
|
||||
1
mdui_patched/components/collapse-item.d.ts
vendored
Normal file
1
mdui_patched/components/collapse-item.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './collapse/collapse-item.js';
|
||||
1
mdui_patched/components/collapse-item.js
Normal file
1
mdui_patched/components/collapse-item.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './collapse/collapse-item.js';
|
||||
1
mdui_patched/components/collapse.d.ts
vendored
Normal file
1
mdui_patched/components/collapse.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './collapse/collapse.js';
|
||||
1
mdui_patched/components/collapse.js
Normal file
1
mdui_patched/components/collapse.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './collapse/collapse.js';
|
||||
1
mdui_patched/components/collapse/collapse-item-style.d.ts
vendored
Normal file
1
mdui_patched/components/collapse/collapse-item-style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const collapseItemStyle: import("lit").CSSResult;
|
||||
2
mdui_patched/components/collapse/collapse-item-style.js
Normal file
2
mdui_patched/components/collapse/collapse-item-style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const collapseItemStyle = css `:host{display:flex;flex-direction:column}.header{display:block}.body{display:block;overflow:hidden;transition:height var(--mdui-motion-duration-short4) var(--mdui-motion-easing-emphasized)}.body.opened{overflow:visible}.body.active{transition-duration:var(--mdui-motion-duration-medium4)}`;
|
||||
68
mdui_patched/components/collapse/collapse-item.d.ts
vendored
Normal file
68
mdui_patched/components/collapse/collapse-item.d.ts
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { JQ } from '@mdui/jq/shared/core.js';
|
||||
import type { CSSResultGroup, TemplateResult, PropertyValues } from 'lit';
|
||||
/**
|
||||
* @summary 折叠面板项组件,需配合 `<mdui-collapse>` 组件使用
|
||||
*
|
||||
* ```html
|
||||
* <mdui-collapse>
|
||||
* ..<mdui-collapse-item header="header-1">content-1</mdui-collapse-item>
|
||||
* ..<mdui-collapse-item header="header-2">content-2</mdui-collapse-item>
|
||||
* </mdui-collapse>
|
||||
* ```
|
||||
*
|
||||
* @event open - 开始打开时,事件被触发
|
||||
* @event opened - 打开动画完成时,事件被触发
|
||||
* @event close - 开始关闭时,事件被触发
|
||||
* @event closed - 关闭动画完成时,事件被触发
|
||||
*
|
||||
* @slot - 折叠面板项的正文内容
|
||||
* @slot header - 折叠面板项的头部内容
|
||||
*
|
||||
* @csspart header - 折叠面板的头部内容
|
||||
* @csspart body - 折叠面板的正文内容
|
||||
*/
|
||||
export declare class CollapseItem extends MduiElement<CollapseItemEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 此折叠面板项的值
|
||||
*/
|
||||
value?: string;
|
||||
/**
|
||||
* 此折叠面板项的头部文本
|
||||
*/
|
||||
header?: string;
|
||||
/**
|
||||
* 是否禁用此折叠面板项
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 点击该元素时触发折叠,值可以是 CSS 选择器、DOM 元素、或 [JQ 对象](/docs/2/functions/jq)。默认为点击整个 header 区域触发
|
||||
*/
|
||||
trigger?: string | HTMLElement | JQ<HTMLElement>;
|
||||
/**
|
||||
* 是否为激活状态,由 `collapse` 组件控制该参数
|
||||
*/
|
||||
protected active: boolean;
|
||||
private state;
|
||||
protected isInitial: boolean;
|
||||
protected readonly key: number;
|
||||
private readonly bodyRef;
|
||||
private onActiveChange;
|
||||
protected firstUpdated(changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
private onTransitionEnd;
|
||||
private updateBodyHeight;
|
||||
}
|
||||
export interface CollapseItemEventMap {
|
||||
open: CustomEvent<void>;
|
||||
opened: CustomEvent<void>;
|
||||
close: CustomEvent<void>;
|
||||
closed: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-collapse-item': CollapseItem;
|
||||
}
|
||||
}
|
||||
130
mdui_patched/components/collapse/collapse-item.js
Normal file
130
mdui_patched/components/collapse/collapse-item.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { $ } from '@mdui/jq/$.js';
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { uniqueId } from '@mdui/shared/helpers/uniqueId.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { collapseItemStyle } from './collapse-item-style.js';
|
||||
/**
|
||||
* @summary 折叠面板项组件,需配合 `<mdui-collapse>` 组件使用
|
||||
*
|
||||
* ```html
|
||||
* <mdui-collapse>
|
||||
* ..<mdui-collapse-item header="header-1">content-1</mdui-collapse-item>
|
||||
* ..<mdui-collapse-item header="header-2">content-2</mdui-collapse-item>
|
||||
* </mdui-collapse>
|
||||
* ```
|
||||
*
|
||||
* @event open - 开始打开时,事件被触发
|
||||
* @event opened - 打开动画完成时,事件被触发
|
||||
* @event close - 开始关闭时,事件被触发
|
||||
* @event closed - 关闭动画完成时,事件被触发
|
||||
*
|
||||
* @slot - 折叠面板项的正文内容
|
||||
* @slot header - 折叠面板项的头部内容
|
||||
*
|
||||
* @csspart header - 折叠面板的头部内容
|
||||
* @csspart body - 折叠面板的正文内容
|
||||
*/
|
||||
let CollapseItem = class CollapseItem extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否禁用此折叠面板项
|
||||
*/
|
||||
this.disabled = false;
|
||||
/**
|
||||
* 是否为激活状态,由 `collapse` 组件控制该参数
|
||||
*/
|
||||
this.active = false;
|
||||
this.state = 'closed';
|
||||
// 是否是初始状态,不显示动画
|
||||
this.isInitial = true;
|
||||
// 每一个 `collapse-item` 元素都添加一个唯一的 key
|
||||
this.key = uniqueId();
|
||||
this.bodyRef = createRef();
|
||||
}
|
||||
onActiveChange() {
|
||||
if (this.isInitial) {
|
||||
this.state = this.active ? 'opened' : 'closed';
|
||||
if (this.hasUpdated) {
|
||||
this.updateBodyHeight();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.state = this.active ? 'open' : 'close';
|
||||
this.emit(this.state);
|
||||
this.updateBodyHeight();
|
||||
}
|
||||
}
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.updateBodyHeight();
|
||||
}
|
||||
render() {
|
||||
return html `<slot name="header" part="header" class="header">${this.header}</slot><slot part="body" class="body ${classMap({
|
||||
opened: this.state === 'opened',
|
||||
active: this.active,
|
||||
})}" ${ref(this.bodyRef)} @transitionend="${this.onTransitionEnd}"></slot>`;
|
||||
}
|
||||
onTransitionEnd(event) {
|
||||
if (event.target === this.bodyRef.value) {
|
||||
this.state = this.active ? 'opened' : 'closed';
|
||||
this.emit(this.state);
|
||||
this.updateBodyHeight();
|
||||
}
|
||||
}
|
||||
updateBodyHeight() {
|
||||
const scrollHeight = this.bodyRef.value.scrollHeight;
|
||||
// 如果是从 opened 状态开始关闭,则先设置高度值,并等重绘完成
|
||||
if (this.state === 'close') {
|
||||
$(this.bodyRef.value).height(scrollHeight);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
this.bodyRef.value.clientLeft;
|
||||
}
|
||||
$(this.bodyRef.value).height(this.state === 'opened'
|
||||
? 'auto'
|
||||
: this.state === 'open'
|
||||
? scrollHeight
|
||||
: 0);
|
||||
}
|
||||
};
|
||||
CollapseItem.styles = [
|
||||
componentStyle,
|
||||
collapseItemStyle,
|
||||
];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], CollapseItem.prototype, "value", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], CollapseItem.prototype, "header", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], CollapseItem.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
property()
|
||||
], CollapseItem.prototype, "trigger", void 0);
|
||||
__decorate([
|
||||
state()
|
||||
], CollapseItem.prototype, "active", void 0);
|
||||
__decorate([
|
||||
state()
|
||||
], CollapseItem.prototype, "state", void 0);
|
||||
__decorate([
|
||||
watch('active')
|
||||
], CollapseItem.prototype, "onActiveChange", null);
|
||||
CollapseItem = __decorate([
|
||||
customElement('mdui-collapse-item')
|
||||
], CollapseItem);
|
||||
export { CollapseItem };
|
||||
1
mdui_patched/components/collapse/collapse-style.d.ts
vendored
Normal file
1
mdui_patched/components/collapse/collapse-style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const collapseStyle: import("lit").CSSResult;
|
||||
2
mdui_patched/components/collapse/collapse-style.js
Normal file
2
mdui_patched/components/collapse/collapse-style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const collapseStyle = css `:host{display:block}`;
|
||||
54
mdui_patched/components/collapse/collapse.d.ts
vendored
Normal file
54
mdui_patched/components/collapse/collapse.d.ts
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import '@mdui/jq/methods/is.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 折叠面板组件,需配合 `<mdui-collapse-item>` 组件使用
|
||||
*
|
||||
* ```html
|
||||
* <mdui-collapse>
|
||||
* ..<mdui-collapse-item header="header-1">content-1</mdui-collapse-item>
|
||||
* ..<mdui-collapse-item header="header-2">content-2</mdui-collapse-item>
|
||||
* </mdui-collapse>
|
||||
* ```
|
||||
*
|
||||
* @event change - 当前展开的折叠面板项变化时触发
|
||||
*
|
||||
* @slot - `<mdui-collapse-item>` 组件
|
||||
*/
|
||||
export declare class Collapse extends MduiElement<CollapseEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否启用手风琴模式
|
||||
*/
|
||||
accordion: boolean;
|
||||
/**
|
||||
* 当前展开的 `<mdui-collapse-item>` 的值
|
||||
*
|
||||
* **Note**:该属性的 HTML 属性始终为字符串,只有在 `accordion` 为 `true` 时,才能设置初始值;该属性的 JavaScript 属性值在 `accordion` 为 `true` 时为字符串,在 `accordion` 为 `false` 时为字符串数组。因此,当 `accordion` 为 `false` 时,只能通过修改 JavaScript 属性值来改变此值。
|
||||
*/
|
||||
value?: string | string[];
|
||||
/**
|
||||
* 是否禁用此折叠面板
|
||||
*/
|
||||
disabled: boolean;
|
||||
private activeKeys;
|
||||
private readonly items;
|
||||
private isInitial;
|
||||
private definedController;
|
||||
private onActiveKeysChange;
|
||||
private onValueChange;
|
||||
protected render(): TemplateResult;
|
||||
private setActiveKeys;
|
||||
private setValue;
|
||||
private onClick;
|
||||
private onSlotChange;
|
||||
private updateItems;
|
||||
}
|
||||
export interface CollapseEventMap {
|
||||
change: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-collapse': Collapse;
|
||||
}
|
||||
}
|
||||
198
mdui_patched/components/collapse/collapse.js
Normal file
198
mdui_patched/components/collapse/collapse.js
Normal file
@@ -0,0 +1,198 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, queryAssignedElements, state, } from 'lit/decorators.js';
|
||||
import { $ } from '@mdui/jq/$.js';
|
||||
import '@mdui/jq/methods/is.js';
|
||||
import { isElement, isUndefined } from '@mdui/jq/shared/helper.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { DefinedController } from '@mdui/shared/controllers/defined.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { arraysEqualIgnoreOrder } from '@mdui/shared/helpers/array.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { collapseStyle } from './collapse-style.js';
|
||||
/**
|
||||
* @summary 折叠面板组件,需配合 `<mdui-collapse-item>` 组件使用
|
||||
*
|
||||
* ```html
|
||||
* <mdui-collapse>
|
||||
* ..<mdui-collapse-item header="header-1">content-1</mdui-collapse-item>
|
||||
* ..<mdui-collapse-item header="header-2">content-2</mdui-collapse-item>
|
||||
* </mdui-collapse>
|
||||
* ```
|
||||
*
|
||||
* @event change - 当前展开的折叠面板项变化时触发
|
||||
*
|
||||
* @slot - `<mdui-collapse-item>` 组件
|
||||
*/
|
||||
let Collapse = class Collapse extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否启用手风琴模式
|
||||
*/
|
||||
this.accordion = false;
|
||||
/**
|
||||
* 是否禁用此折叠面板
|
||||
*/
|
||||
this.disabled = false;
|
||||
// 因为 collapse-item 的 value 可能会重复,所以在每个 collapse-item 元素上都添加了一个唯一的 key,通过 activeKey 来记录激活状态的 key
|
||||
this.activeKeys = [];
|
||||
// 是否是初始状态,初始状态不触发 change 事件,没有动画
|
||||
this.isInitial = true;
|
||||
this.definedController = new DefinedController(this, {
|
||||
relatedElements: ['mdui-collapse-item'],
|
||||
});
|
||||
}
|
||||
async onActiveKeysChange() {
|
||||
await this.definedController.whenDefined();
|
||||
// 根据 activeKeys 读取对应 collapse-item 的值
|
||||
const value = this.accordion
|
||||
? this.items.find((item) => this.activeKeys.includes(item.key))?.value
|
||||
: this.items
|
||||
.filter((item) => this.activeKeys.includes(item.key))
|
||||
.map((item) => item.value);
|
||||
this.setValue(value);
|
||||
if (!this.isInitial) {
|
||||
this.emit('change');
|
||||
}
|
||||
}
|
||||
async onValueChange() {
|
||||
this.isInitial = !this.hasUpdated;
|
||||
await this.definedController.whenDefined();
|
||||
if (this.accordion) {
|
||||
const value = this.value;
|
||||
if (!value) {
|
||||
this.setActiveKeys([]);
|
||||
}
|
||||
else {
|
||||
const item = this.items.find((item) => item.value === value);
|
||||
this.setActiveKeys(item ? [item.key] : []);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const value = this.value;
|
||||
if (!value.length) {
|
||||
this.setActiveKeys([]);
|
||||
}
|
||||
else {
|
||||
const activeKeys = this.items
|
||||
.filter((item) => value.includes(item.value))
|
||||
.map((item) => item.key);
|
||||
this.setActiveKeys(activeKeys);
|
||||
}
|
||||
}
|
||||
this.updateItems();
|
||||
}
|
||||
render() {
|
||||
return html `<slot @slotchange="${this.onSlotChange}" @click="${this.onClick}"></slot>`;
|
||||
}
|
||||
setActiveKeys(activeKeys) {
|
||||
if (!arraysEqualIgnoreOrder(this.activeKeys, activeKeys)) {
|
||||
this.activeKeys = activeKeys;
|
||||
}
|
||||
}
|
||||
setValue(value) {
|
||||
if (this.accordion || isUndefined(this.value) || isUndefined(value)) {
|
||||
this.value = value;
|
||||
}
|
||||
else if (!arraysEqualIgnoreOrder(this.value, value)) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
onClick(event) {
|
||||
// 全部禁用
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
// event.button 为 0 时,为鼠标左键点击。忽略鼠标中键和右键
|
||||
if (event.button) {
|
||||
return;
|
||||
}
|
||||
const target = event.target;
|
||||
const item = target.closest('mdui-collapse-item');
|
||||
// collapse-item 被禁用,忽略
|
||||
if (!item || item.disabled) {
|
||||
return;
|
||||
}
|
||||
const path = event.composedPath();
|
||||
// 指定了 trigger 时,点击了其他地方时,忽略
|
||||
if (item.trigger &&
|
||||
!path.find((element) => isElement(element) && $(element).is(item.trigger))) {
|
||||
return;
|
||||
}
|
||||
// header 元素,忽略点击 header 以外的元素
|
||||
if (!path.find((element) => isElement(element) && element.part.contains('header'))) {
|
||||
return;
|
||||
}
|
||||
if (this.accordion) {
|
||||
if (this.activeKeys.includes(item.key)) {
|
||||
this.setActiveKeys([]);
|
||||
}
|
||||
else {
|
||||
this.setActiveKeys([item.key]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 直接修改 this.activeKeys 无法被 watch 监听到,需要先克隆一份 this.activeKeys
|
||||
const activeKeys = [...this.activeKeys];
|
||||
if (activeKeys.includes(item.key)) {
|
||||
activeKeys.splice(activeKeys.indexOf(item.key), 1);
|
||||
}
|
||||
else {
|
||||
activeKeys.push(item.key);
|
||||
}
|
||||
this.setActiveKeys(activeKeys);
|
||||
}
|
||||
this.isInitial = false;
|
||||
this.updateItems();
|
||||
}
|
||||
async onSlotChange() {
|
||||
await this.definedController.whenDefined();
|
||||
this.updateItems();
|
||||
}
|
||||
// 更新 <mdui-collapse-item> 的状态
|
||||
updateItems() {
|
||||
this.items.forEach((item) => {
|
||||
item.active = this.activeKeys.includes(item.key);
|
||||
item.isInitial = this.isInitial;
|
||||
});
|
||||
}
|
||||
};
|
||||
Collapse.styles = [
|
||||
componentStyle,
|
||||
collapseStyle,
|
||||
];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Collapse.prototype, "accordion", void 0);
|
||||
__decorate([
|
||||
property()
|
||||
], Collapse.prototype, "value", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Collapse.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
state()
|
||||
], Collapse.prototype, "activeKeys", void 0);
|
||||
__decorate([
|
||||
queryAssignedElements({ selector: 'mdui-collapse-item', flatten: true })
|
||||
], Collapse.prototype, "items", void 0);
|
||||
__decorate([
|
||||
watch('activeKeys', true)
|
||||
], Collapse.prototype, "onActiveKeysChange", null);
|
||||
__decorate([
|
||||
watch('value')
|
||||
], Collapse.prototype, "onValueChange", null);
|
||||
Collapse = __decorate([
|
||||
customElement('mdui-collapse')
|
||||
], Collapse);
|
||||
export { Collapse };
|
||||
1
mdui_patched/components/dialog.d.ts
vendored
Normal file
1
mdui_patched/components/dialog.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dialog/index.js';
|
||||
1
mdui_patched/components/dialog.js
Normal file
1
mdui_patched/components/dialog.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dialog/index.js';
|
||||
107
mdui_patched/components/dialog/index.d.ts
vendored
Normal file
107
mdui_patched/components/dialog/index.d.ts
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import '../icon.js';
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 对话框组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-dialog>content</mdui-dialog>
|
||||
* ```
|
||||
*
|
||||
* @event open - 对话框开始打开时触发。可以通过调用 `event.preventDefault()` 阻止对话框打开
|
||||
* @event opened - 对话框打开动画完成后触发
|
||||
* @event close - 对话框开始关闭时触发。可以通过调用 `event.preventDefault()` 阻止对话框关闭
|
||||
* @event closed - 对话框关闭动画完成后触发
|
||||
* @event overlay-click - 点击遮罩层时触发
|
||||
*
|
||||
* @slot header - 顶部元素,默认包含 `icon` slot 和 `headline` slot
|
||||
* @slot icon - 顶部图标
|
||||
* @slot headline - 顶部标题
|
||||
* @slot description - 标题下方的文本
|
||||
* @slot - 对话框主体内容
|
||||
* @slot action - 底部操作栏中的元素
|
||||
*
|
||||
* @csspart overlay - 遮罩层
|
||||
* @csspart panel - 对话框容器
|
||||
* @csspart header - 对话框 header 部分,包含 icon 和 headline
|
||||
* @csspart icon - 顶部图标,位于 header 中
|
||||
* @csspart headline - 顶部标题,位于 header 中
|
||||
* @csspart body - 对话框 body 部分
|
||||
* @csspart description - 副文本部分,位于 body 中
|
||||
* @csspart action - 底部操作按钮
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
export declare class Dialog extends MduiElement<DialogEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 顶部的 Material Icons 图标名。也可以通过 `slot="icon"` 设置
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 标题。也可以通过 `slot="headline"` 设置
|
||||
*/
|
||||
headline?: string;
|
||||
/**
|
||||
* 标题下方的文本。也可以通过 `slot="description"` 设置
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* 是否打开对话框
|
||||
*/
|
||||
open: boolean;
|
||||
/**
|
||||
* 是否全屏显示对话框
|
||||
*/
|
||||
fullscreen: boolean;
|
||||
/**
|
||||
* 是否允许按下 ESC 键关闭对话框
|
||||
*/
|
||||
closeOnEsc: boolean;
|
||||
/**
|
||||
* 是否允许点击遮罩层关闭对话框
|
||||
*/
|
||||
closeOnOverlayClick: boolean;
|
||||
/**
|
||||
* 是否垂直排列底部操作按钮
|
||||
*/
|
||||
stackedActions: boolean;
|
||||
/**
|
||||
* 是否可拖拽移动位置
|
||||
*/
|
||||
/**
|
||||
* 是否可拖拽改变大小
|
||||
*/
|
||||
/**
|
||||
* dialog 组件内包含的 mdui-top-app-bar 组件
|
||||
*/
|
||||
private readonly topAppBarElements;
|
||||
private originalTrigger;
|
||||
private modalHelper;
|
||||
private readonly overlayRef;
|
||||
private readonly panelRef;
|
||||
private readonly bodyRef;
|
||||
private readonly hasSlotController;
|
||||
private readonly definedController;
|
||||
private onOpenChange;
|
||||
disconnectedCallback(): void;
|
||||
protected firstUpdated(_changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
private onOverlayClick;
|
||||
private renderIcon;
|
||||
private renderHeadline;
|
||||
private renderDescription;
|
||||
}
|
||||
export interface DialogEventMap {
|
||||
open: CustomEvent<void>;
|
||||
opened: CustomEvent<void>;
|
||||
close: CustomEvent<void>;
|
||||
closed: CustomEvent<void>;
|
||||
'overlay-click': CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-dialog': Dialog;
|
||||
}
|
||||
}
|
||||
311
mdui_patched/components/dialog/index.js
Normal file
311
mdui_patched/components/dialog/index.js
Normal file
@@ -0,0 +1,311 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, queryAssignedElements, } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { when } from 'lit/directives/when.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 { 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 { Modal } from '@mdui/shared/helpers/modal.js';
|
||||
import { getDuration, getEasing } from '@mdui/shared/helpers/motion.js';
|
||||
import { lockScreen, unlockScreen } from '@mdui/shared/helpers/scroll.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { offLocaleReady } from '../../internal/localize.js';
|
||||
import '../icon.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 对话框组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-dialog>content</mdui-dialog>
|
||||
* ```
|
||||
*
|
||||
* @event open - 对话框开始打开时触发。可以通过调用 `event.preventDefault()` 阻止对话框打开
|
||||
* @event opened - 对话框打开动画完成后触发
|
||||
* @event close - 对话框开始关闭时触发。可以通过调用 `event.preventDefault()` 阻止对话框关闭
|
||||
* @event closed - 对话框关闭动画完成后触发
|
||||
* @event overlay-click - 点击遮罩层时触发
|
||||
*
|
||||
* @slot header - 顶部元素,默认包含 `icon` slot 和 `headline` slot
|
||||
* @slot icon - 顶部图标
|
||||
* @slot headline - 顶部标题
|
||||
* @slot description - 标题下方的文本
|
||||
* @slot - 对话框主体内容
|
||||
* @slot action - 底部操作栏中的元素
|
||||
*
|
||||
* @csspart overlay - 遮罩层
|
||||
* @csspart panel - 对话框容器
|
||||
* @csspart header - 对话框 header 部分,包含 icon 和 headline
|
||||
* @csspart icon - 顶部图标,位于 header 中
|
||||
* @csspart headline - 顶部标题,位于 header 中
|
||||
* @csspart body - 对话框 body 部分
|
||||
* @csspart description - 副文本部分,位于 body 中
|
||||
* @csspart action - 底部操作按钮
|
||||
*
|
||||
* @cssprop --shape-corner - 组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
let Dialog = class Dialog extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否打开对话框
|
||||
*/
|
||||
this.open = false;
|
||||
/**
|
||||
* 是否全屏显示对话框
|
||||
*/
|
||||
this.fullscreen = false;
|
||||
/**
|
||||
* 是否允许按下 ESC 键关闭对话框
|
||||
*/
|
||||
this.closeOnEsc = false;
|
||||
/**
|
||||
* 是否允许点击遮罩层关闭对话框
|
||||
*/
|
||||
this.closeOnOverlayClick = false;
|
||||
/**
|
||||
* 是否垂直排列底部操作按钮
|
||||
*/
|
||||
this.stackedActions = false;
|
||||
this.overlayRef = createRef();
|
||||
this.panelRef = createRef();
|
||||
this.bodyRef = createRef();
|
||||
this.hasSlotController = new HasSlotController(this, 'header', 'icon', 'headline', 'description', 'action', '[default]');
|
||||
this.definedController = new DefinedController(this, {
|
||||
relatedElements: ['mdui-top-app-bar'],
|
||||
});
|
||||
}
|
||||
async onOpenChange() {
|
||||
const hasUpdated = this.hasUpdated;
|
||||
// 默认为关闭状态。因此首次渲染时,且为关闭状态,不执行
|
||||
if (!this.open && !hasUpdated) {
|
||||
return;
|
||||
}
|
||||
await this.definedController.whenDefined();
|
||||
if (!hasUpdated) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
// 内部的 header, body, actions 元素
|
||||
const children = Array.from(this.panelRef.value.querySelectorAll('.header, .body, .actions'));
|
||||
const easingLinear = getEasing(this, 'linear');
|
||||
const easingEmphasizedDecelerate = getEasing(this, 'emphasized-decelerate');
|
||||
const easingEmphasizedAccelerate = getEasing(this, 'emphasized-accelerate');
|
||||
const stopAnimation = () => Promise.all([
|
||||
stopAnimations(this.overlayRef.value),
|
||||
stopAnimations(this.panelRef.value),
|
||||
...children.map((child) => stopAnimations(child)),
|
||||
]);
|
||||
// 打开
|
||||
// 要区分是否首次渲染,首次渲染不触发事件,不执行动画;非首次渲染,触发事件,执行动画
|
||||
if (this.open) {
|
||||
if (hasUpdated) {
|
||||
const eventProceeded = this.emit('open', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.style.display = 'flex';
|
||||
// 包含 <mdui-top-app-bar slot="header"> 时
|
||||
const topAppBarElements = this.topAppBarElements ?? [];
|
||||
if (topAppBarElements.length) {
|
||||
const topAppBarElement = topAppBarElements[0];
|
||||
// top-app-bar 未设置 scrollTarget 时,默认设置为 bodyRef
|
||||
if (!topAppBarElement.scrollTarget) {
|
||||
topAppBarElement.scrollTarget = this.bodyRef.value;
|
||||
}
|
||||
// 移除 header 和 body 之间的 margin
|
||||
this.bodyRef.value.style.marginTop = '0';
|
||||
}
|
||||
this.originalTrigger = document.activeElement;
|
||||
this.modalHelper.activate();
|
||||
lockScreen(this);
|
||||
await stopAnimation();
|
||||
// 设置聚焦
|
||||
requestAnimationFrame(() => {
|
||||
const autoFocusTarget = this.querySelector('[autofocus]');
|
||||
if (autoFocusTarget) {
|
||||
autoFocusTarget.focus({ preventScroll: true });
|
||||
}
|
||||
else {
|
||||
this.panelRef.value.focus({ preventScroll: true });
|
||||
}
|
||||
});
|
||||
const duration = getDuration(this, 'medium4');
|
||||
await Promise.all([
|
||||
animateTo(this.overlayRef.value, [{ opacity: 0 }, { opacity: 1, offset: 0.3 }, { opacity: 1 }], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingLinear,
|
||||
}),
|
||||
animateTo(this.panelRef.value, [
|
||||
{ transform: 'translateY(-1.875rem) scaleY(0)' },
|
||||
{ transform: 'translateY(0) scaleY(1)' },
|
||||
], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingEmphasizedDecelerate,
|
||||
}),
|
||||
animateTo(this.panelRef.value, [{ opacity: 0 }, { opacity: 1, offset: 0.1 }, { opacity: 1 }], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingLinear,
|
||||
}),
|
||||
...children.map((child) => animateTo(child, [
|
||||
{ opacity: 0 },
|
||||
{ opacity: 0, offset: 0.2 },
|
||||
{ opacity: 1, offset: 0.8 },
|
||||
{ opacity: 1 },
|
||||
], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingLinear,
|
||||
})),
|
||||
]);
|
||||
if (hasUpdated) {
|
||||
this.emit('opened');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const eventProceeded = this.emit('close', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
this.modalHelper.deactivate();
|
||||
await stopAnimation();
|
||||
const duration = getDuration(this, 'short4');
|
||||
await Promise.all([
|
||||
animateTo(this.overlayRef.value, [{ opacity: 1 }, { opacity: 0 }], {
|
||||
duration,
|
||||
easing: easingLinear,
|
||||
}),
|
||||
animateTo(this.panelRef.value, [
|
||||
{ transform: 'translateY(0) scaleY(1)' },
|
||||
{ transform: 'translateY(-1.875rem) scaleY(0.6)' },
|
||||
], { duration, easing: easingEmphasizedAccelerate }),
|
||||
animateTo(this.panelRef.value, [{ opacity: 1 }, { opacity: 1, offset: 0.75 }, { opacity: 0 }], { duration, easing: easingLinear }),
|
||||
...children.map((child) => animateTo(child, [{ opacity: 1 }, { opacity: 0, offset: 0.75 }, { opacity: 0 }], { duration, easing: easingLinear })),
|
||||
]);
|
||||
this.style.display = 'none';
|
||||
unlockScreen(this);
|
||||
// 对话框关闭后,恢复焦点到原有的元素上
|
||||
const trigger = this.originalTrigger;
|
||||
if (typeof trigger?.focus === 'function') {
|
||||
setTimeout(() => trigger.focus());
|
||||
}
|
||||
this.emit('closed');
|
||||
}
|
||||
}
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
unlockScreen(this);
|
||||
// alert, confirm, prompt 函数支持 localize。这里确保在组件销毁时,取消监听 localize ready 事件
|
||||
offLocaleReady(this);
|
||||
}
|
||||
firstUpdated(_changedProperties) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
this.modalHelper = new Modal(this);
|
||||
this.addEventListener('keydown', (event) => {
|
||||
if (this.open && this.closeOnEsc && event.key === 'Escape') {
|
||||
event.stopPropagation();
|
||||
this.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const hasActionSlot = this.hasSlotController.test('action');
|
||||
const hasDefaultSlot = this.hasSlotController.test('[default]');
|
||||
const hasIcon = !!this.icon || this.hasSlotController.test('icon');
|
||||
const hasHeadline = !!this.headline || this.hasSlotController.test('headline');
|
||||
const hasDescription = !!this.description || this.hasSlotController.test('description');
|
||||
const hasHeader = hasIcon || hasHeadline || this.hasSlotController.test('header');
|
||||
const hasBody = hasDescription || hasDefaultSlot;
|
||||
// modify: 移除了 tabindex="0", 换为 tabindex
|
||||
return html `<div ${ref(this.overlayRef)} part="overlay" class="overlay" @click="${this.onOverlayClick}" tabindex="-1"></div><div ${ref(this.panelRef)} part="panel" class="panel ${classMap({
|
||||
'has-icon': hasIcon,
|
||||
'has-description': hasDescription,
|
||||
'has-default': hasDefaultSlot,
|
||||
})}" tabindex>${when(hasHeader, () => html `<slot name="header" part="header" class="header">${when(hasIcon, () => this.renderIcon())} ${when(hasHeadline, () => this.renderHeadline())}</slot>`)} ${when(hasBody, () => html `<div ${ref(this.bodyRef)} part="body" class="body">${when(hasDescription, () => this.renderDescription())}<slot></slot></div>`)} ${when(hasActionSlot, () => html `<slot name="action" part="action" class="action"></slot>`)}</div>`;
|
||||
}
|
||||
onOverlayClick() {
|
||||
this.emit('overlay-click');
|
||||
if (!this.closeOnOverlayClick) {
|
||||
return;
|
||||
}
|
||||
this.open = false;
|
||||
}
|
||||
renderIcon() {
|
||||
return html `<slot name="icon" part="icon" class="icon">${this.icon
|
||||
? html `<mdui-icon name="${this.icon}"></mdui-icon>`
|
||||
: nothingTemplate}</slot>`;
|
||||
}
|
||||
renderHeadline() {
|
||||
return html `<slot name="headline" part="headline" class="headline">${this.headline}</slot>`;
|
||||
}
|
||||
renderDescription() {
|
||||
return html `<slot name="description" part="description" class="description">${this.description}</slot>`;
|
||||
}
|
||||
};
|
||||
Dialog.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Dialog.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Dialog.prototype, "headline", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Dialog.prototype, "description", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Dialog.prototype, "open", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Dialog.prototype, "fullscreen", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'close-on-esc',
|
||||
})
|
||||
], Dialog.prototype, "closeOnEsc", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'close-on-overlay-click',
|
||||
})
|
||||
], Dialog.prototype, "closeOnOverlayClick", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'stacked-actions',
|
||||
})
|
||||
], Dialog.prototype, "stackedActions", void 0);
|
||||
__decorate([
|
||||
queryAssignedElements({
|
||||
slot: 'header',
|
||||
selector: 'mdui-top-app-bar',
|
||||
flatten: true,
|
||||
})
|
||||
], Dialog.prototype, "topAppBarElements", void 0);
|
||||
__decorate([
|
||||
watch('open')
|
||||
], Dialog.prototype, "onOpenChange", null);
|
||||
Dialog = __decorate([
|
||||
customElement('mdui-dialog')
|
||||
], Dialog);
|
||||
export { Dialog };
|
||||
1
mdui_patched/components/dialog/style.d.ts
vendored
Normal file
1
mdui_patched/components/dialog/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/dialog/style.js
Normal file
2
mdui_patched/components/dialog/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner:var(--mdui-shape-corner-extra-large);--z-index:2300;position:fixed;z-index:var(--z-index);display:none;align-items:center;justify-content:center;inset:0;padding:3rem}::slotted(mdui-top-app-bar[slot=header]){position:absolute;border-top-left-radius:var(--mdui-shape-corner-extra-large);border-top-right-radius:var(--mdui-shape-corner-extra-large);background-color:rgb(var(--mdui-color-surface-container-high))}:host([fullscreen]:not([fullscreen=false i])){--shape-corner:var(--mdui-shape-corner-none);padding:0}:host([fullscreen]:not([fullscreen=false i])) ::slotted(mdui-top-app-bar[slot=header]){border-top-left-radius:var(--mdui-shape-corner-none);border-top-right-radius:var(--mdui-shape-corner-none)}.overlay{position:fixed;inset:0;background-color:rgba(var(--mdui-color-scrim),.4)}.panel{--mdui-color-background:var(--mdui-color-surface-container-high);position:relative;display:flex;flex-direction:column;max-height:100%;border-radius:var(--shape-corner);outline:0;transform-origin:top;min-width:17.5rem;max-width:35rem;padding:1.5rem;background-color:rgb(var(--mdui-color-surface-container-high));box-shadow:var(--mdui-elevation-level3)}:host([fullscreen]:not([fullscreen=false i])) .panel{width:100%;max-width:100%;height:100%;max-height:100%;box-shadow:var(--mdui-elevation-level0)}.header{display:flex;flex-direction:column}.has-icon .header{align-items:center}.icon{display:flex;color:rgb(var(--mdui-color-secondary));font-size:1.5rem}.icon mdui-icon,::slotted([slot=icon]){font-size:inherit}.headline{display:flex;color:rgb(var(--mdui-color-on-surface));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)}.icon+.headline{padding-top:1rem}.body{overflow:auto}.header+.body{margin-top:1rem}.description{display:flex;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)}:host([fullscreen]:not([fullscreen=false i])) .description{color:rgb(var(--mdui-color-on-surface))}.has-description.has-default .description{margin-bottom:1rem}.action{display:flex;justify-content:flex-end;padding-top:1.5rem}.action::slotted(:not(:first-child)){margin-left:.5rem}:host([stacked-actions]:not([stacked-actions=false i])) .action{flex-direction:column;align-items:end}:host([stacked-actions]:not([stacked-actions=false i])) .action::slotted(:not(:first-child)){margin-left:0;margin-top:.5rem}`;
|
||||
1
mdui_patched/components/divider.d.ts
vendored
Normal file
1
mdui_patched/components/divider.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './divider/index.js';
|
||||
1
mdui_patched/components/divider.js
Normal file
1
mdui_patched/components/divider.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './divider/index.js';
|
||||
32
mdui_patched/components/divider/index.d.ts
vendored
Normal file
32
mdui_patched/components/divider/index.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 分割线组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-divider></mdui-divider>
|
||||
* ```
|
||||
*/
|
||||
export declare class Divider extends MduiElement<DividerEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否为垂直分割线
|
||||
*/
|
||||
vertical: boolean;
|
||||
/**
|
||||
* 是否进行左侧缩进
|
||||
*/
|
||||
inset: boolean;
|
||||
/**
|
||||
* 是否进行左右两侧缩进
|
||||
*/
|
||||
middle: boolean;
|
||||
protected render(): TemplateResult;
|
||||
}
|
||||
export interface DividerEventMap {
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-divider': Divider;
|
||||
}
|
||||
}
|
||||
60
mdui_patched/components/divider/index.js
Normal file
60
mdui_patched/components/divider/index.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 分割线组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-divider></mdui-divider>
|
||||
* ```
|
||||
*/
|
||||
let Divider = class Divider extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* 是否为垂直分割线
|
||||
*/
|
||||
this.vertical = false;
|
||||
/**
|
||||
* 是否进行左侧缩进
|
||||
*/
|
||||
this.inset = false;
|
||||
/**
|
||||
* 是否进行左右两侧缩进
|
||||
*/
|
||||
this.middle = false;
|
||||
}
|
||||
render() {
|
||||
return html ``;
|
||||
}
|
||||
};
|
||||
Divider.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Divider.prototype, "vertical", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Divider.prototype, "inset", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Divider.prototype, "middle", void 0);
|
||||
Divider = __decorate([
|
||||
customElement('mdui-divider')
|
||||
], Divider);
|
||||
export { Divider };
|
||||
1
mdui_patched/components/divider/style.d.ts
vendored
Normal file
1
mdui_patched/components/divider/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/divider/style.js
Normal file
2
mdui_patched/components/divider/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{display:block;height:.0625rem;background-color:rgb(var(--mdui-color-surface-variant))}:host([inset]:not([inset=false i])){margin-left:1rem}:host([middle]:not([middle=false i])){margin-left:1rem;margin-right:1rem}:host([vertical]:not([vertical=false i])){height:100%;width:.0625rem}`;
|
||||
1
mdui_patched/components/dropdown.d.ts
vendored
Normal file
1
mdui_patched/components/dropdown.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dropdown/index.js';
|
||||
1
mdui_patched/components/dropdown.js
Normal file
1
mdui_patched/components/dropdown.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dropdown/index.js';
|
||||
137
mdui_patched/components/dropdown/index.d.ts
vendored
Normal file
137
mdui_patched/components/dropdown/index.d.ts
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import '@mdui/jq/methods/is.js';
|
||||
import '@mdui/jq/methods/width.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
||||
/**
|
||||
* @summary 下拉组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-dropdown>
|
||||
* ..<mdui-button slot="trigger">open dropdown</mdui-button>
|
||||
* ..<mdui-menu>
|
||||
* ....<mdui-menu-item>Item 1</mdui-menu-item>
|
||||
* ....<mdui-menu-item>Item 2</mdui-menu-item>
|
||||
* ..</mdui-menu>
|
||||
* </mdui-dropdown>
|
||||
* ```
|
||||
*
|
||||
* @event open - 下拉组件开始打开时,事件被触发。可以通过调用 `event.preventDefault()` 阻止下拉组件打开
|
||||
* @event opened - 下拉组件打开动画完成时,事件被触发
|
||||
* @event close - 下拉组件开始关闭时,事件被触发。可以通过调用 `event.preventDefault()` 阻止下拉组件关闭
|
||||
* @event closed - 下拉组件关闭动画完成时,事件被触发
|
||||
*
|
||||
* @slot - 下拉组件的内容
|
||||
* @slot trigger - 触发下拉组件的元素,例如 [`<mdui-button>`](/docs/2/components/button) 元素
|
||||
*
|
||||
* @csspart trigger - 触发下拉组件的元素的容器,即 `trigger` slot 的容器
|
||||
* @csspart panel - 下拉组件内容的容器
|
||||
*
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
export declare class Dropdown extends MduiElement<DropdownEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* 是否打开下拉组件
|
||||
*/
|
||||
open: boolean;
|
||||
/**
|
||||
* 是否禁用下拉组件
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 下拉组件的触发方式,支持多个值,用空格分隔。可选值包括:
|
||||
*
|
||||
* * `click`:点击触发
|
||||
* * `hover`:鼠标悬浮触发
|
||||
* * `focus`:聚焦触发
|
||||
* * `contextmenu`:鼠标右键点击、或触摸长按触发
|
||||
* * `manual`:仅能通过编程方式打开和关闭下拉组件,不能再指定其他触发方式
|
||||
*/
|
||||
trigger: /*点击触发*/ 'click' | /*鼠标悬浮触发*/ 'hover' | /*聚焦触发*/ 'focus' | /*鼠标右键点击、或触摸长按触发*/ 'contextmenu' | /*仅能通过编程方式打开和关闭下拉组件,不能再指定其他触发方式*/ 'manual' | string;
|
||||
/**
|
||||
* 下拉组件内容的位置。可选值包括:
|
||||
*
|
||||
* * `auto`:自动判断位置
|
||||
* * `top-start`:上方左对齐
|
||||
* * `top`:上方居中
|
||||
* * `top-end`:上方右对齐
|
||||
* * `bottom-start`:下方左对齐
|
||||
* * `bottom`:下方居中
|
||||
* * `bottom-end`:下方右对齐
|
||||
* * `left-start`:左侧顶部对齐
|
||||
* * `left`:左侧居中
|
||||
* * `left-end`:左侧底部对齐
|
||||
* * `right-start`:右侧顶部对齐
|
||||
* * `right`:右侧居中
|
||||
* * `right-end`:右侧底部对齐
|
||||
*/
|
||||
placement: /*自动判断位置*/ 'auto' | /*上方左对齐*/ 'top-start' | /*上方居中*/ 'top' | /*上方右对齐*/ 'top-end' | /*下方左对齐*/ 'bottom-start' | /*下方居中*/ 'bottom' | /*下方右对齐*/ 'bottom-end' | /*左侧顶部对齐*/ 'left-start' | /*左侧居中*/ 'left' | /*左侧底部对齐*/ 'left-end' | /*右侧顶部对齐*/ 'right-start' | /*右侧居中*/ 'right' | /*右侧底部对齐*/ 'right-end';
|
||||
/**
|
||||
* 点击 [`<mdui-menu-item>`](/docs/2/components/menu#menu-item-api) 后,下拉组件是否保持打开状态
|
||||
*/
|
||||
stayOpenOnClick: boolean;
|
||||
/**
|
||||
* 鼠标悬浮触发下拉组件打开的延时,单位为毫秒
|
||||
*/
|
||||
openDelay: number;
|
||||
/**
|
||||
* 鼠标悬浮触发下拉组件关闭的延时,单位为毫秒
|
||||
*/
|
||||
closeDelay: number;
|
||||
/**
|
||||
* 是否在触发下拉组件的光标位置打开下拉组件,常用于打开鼠标右键菜单
|
||||
*/
|
||||
openOnPointer: boolean;
|
||||
private readonly triggerElements;
|
||||
private readonly panelElements;
|
||||
private pointerOffsetX;
|
||||
private pointerOffsetY;
|
||||
private animateDirection;
|
||||
private openTimeout;
|
||||
private closeTimeout;
|
||||
private observeResize?;
|
||||
private overflowAncestors?;
|
||||
private readonly panelRef;
|
||||
private readonly definedController;
|
||||
constructor();
|
||||
private get triggerElement();
|
||||
private onPositionChange;
|
||||
private onOpenChange;
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
protected firstUpdated(changedProperties: PropertyValues): void;
|
||||
protected render(): TemplateResult;
|
||||
/**
|
||||
* 获取 dropdown 打开、关闭动画的 CSS scaleX 或 scaleY
|
||||
*/
|
||||
private getCssScaleName;
|
||||
/**
|
||||
* 在 document 上点击时,根据条件判断是否要关闭 dropdown
|
||||
*/
|
||||
private onDocumentClick;
|
||||
/**
|
||||
* 在 document 上按下按键时,根据条件判断是否要关闭 dropdown
|
||||
*/
|
||||
private onDocumentKeydown;
|
||||
private onWindowScroll;
|
||||
private hasTrigger;
|
||||
private onFocus;
|
||||
private onClick;
|
||||
private onPanelClick;
|
||||
private onContextMenu;
|
||||
private onMouseEnter;
|
||||
private onMouseLeave;
|
||||
private updatePositioner;
|
||||
}
|
||||
export interface DropdownEventMap {
|
||||
open: CustomEvent<void>;
|
||||
opened: CustomEvent<void>;
|
||||
close: CustomEvent<void>;
|
||||
closed: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-dropdown': Dropdown;
|
||||
}
|
||||
}
|
||||
583
mdui_patched/components/dropdown/index.js
Normal file
583
mdui_patched/components/dropdown/index.js
Normal file
@@ -0,0 +1,583 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, queryAssignedElements, } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import { getOverflowAncestors } from '@floating-ui/utils/dom';
|
||||
import { $ } from '@mdui/jq/$.js';
|
||||
import '@mdui/jq/methods/height.js';
|
||||
import '@mdui/jq/methods/is.js';
|
||||
import '@mdui/jq/methods/width.js';
|
||||
import { isFunction } from '@mdui/jq/shared/helper.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { DefinedController } from '@mdui/shared/controllers/defined.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-dropdown>
|
||||
* ..<mdui-button slot="trigger">open dropdown</mdui-button>
|
||||
* ..<mdui-menu>
|
||||
* ....<mdui-menu-item>Item 1</mdui-menu-item>
|
||||
* ....<mdui-menu-item>Item 2</mdui-menu-item>
|
||||
* ..</mdui-menu>
|
||||
* </mdui-dropdown>
|
||||
* ```
|
||||
*
|
||||
* @event open - 下拉组件开始打开时,事件被触发。可以通过调用 `event.preventDefault()` 阻止下拉组件打开
|
||||
* @event opened - 下拉组件打开动画完成时,事件被触发
|
||||
* @event close - 下拉组件开始关闭时,事件被触发。可以通过调用 `event.preventDefault()` 阻止下拉组件关闭
|
||||
* @event closed - 下拉组件关闭动画完成时,事件被触发
|
||||
*
|
||||
* @slot - 下拉组件的内容
|
||||
* @slot trigger - 触发下拉组件的元素,例如 [`<mdui-button>`](/docs/2/components/button) 元素
|
||||
*
|
||||
* @csspart trigger - 触发下拉组件的元素的容器,即 `trigger` slot 的容器
|
||||
* @csspart panel - 下拉组件内容的容器
|
||||
*
|
||||
* @cssprop --z-index - 组件的 CSS `z-index` 值
|
||||
*/
|
||||
let Dropdown = class Dropdown extends MduiElement {
|
||||
constructor() {
|
||||
super();
|
||||
/**
|
||||
* 是否打开下拉组件
|
||||
*/
|
||||
this.open = false;
|
||||
/**
|
||||
* 是否禁用下拉组件
|
||||
*/
|
||||
this.disabled = false;
|
||||
/**
|
||||
* 下拉组件的触发方式,支持多个值,用空格分隔。可选值包括:
|
||||
*
|
||||
* * `click`:点击触发
|
||||
* * `hover`:鼠标悬浮触发
|
||||
* * `focus`:聚焦触发
|
||||
* * `contextmenu`:鼠标右键点击、或触摸长按触发
|
||||
* * `manual`:仅能通过编程方式打开和关闭下拉组件,不能再指定其他触发方式
|
||||
*/
|
||||
this.trigger = 'click';
|
||||
/**
|
||||
* 下拉组件内容的位置。可选值包括:
|
||||
*
|
||||
* * `auto`:自动判断位置
|
||||
* * `top-start`:上方左对齐
|
||||
* * `top`:上方居中
|
||||
* * `top-end`:上方右对齐
|
||||
* * `bottom-start`:下方左对齐
|
||||
* * `bottom`:下方居中
|
||||
* * `bottom-end`:下方右对齐
|
||||
* * `left-start`:左侧顶部对齐
|
||||
* * `left`:左侧居中
|
||||
* * `left-end`:左侧底部对齐
|
||||
* * `right-start`:右侧顶部对齐
|
||||
* * `right`:右侧居中
|
||||
* * `right-end`:右侧底部对齐
|
||||
*/
|
||||
this.placement = 'auto';
|
||||
/**
|
||||
* 点击 [`<mdui-menu-item>`](/docs/2/components/menu#menu-item-api) 后,下拉组件是否保持打开状态
|
||||
*/
|
||||
this.stayOpenOnClick = false;
|
||||
/**
|
||||
* 鼠标悬浮触发下拉组件打开的延时,单位为毫秒
|
||||
*/
|
||||
this.openDelay = 150;
|
||||
/**
|
||||
* 鼠标悬浮触发下拉组件关闭的延时,单位为毫秒
|
||||
*/
|
||||
this.closeDelay = 150;
|
||||
/**
|
||||
* 是否在触发下拉组件的光标位置打开下拉组件,常用于打开鼠标右键菜单
|
||||
*/
|
||||
this.openOnPointer = false;
|
||||
this.panelRef = createRef();
|
||||
this.definedController = new DefinedController(this, {
|
||||
relatedElements: [''],
|
||||
});
|
||||
this.onDocumentClick = this.onDocumentClick.bind(this);
|
||||
this.onDocumentKeydown = this.onDocumentKeydown.bind(this);
|
||||
this.onWindowScroll = this.onWindowScroll.bind(this);
|
||||
this.onMouseLeave = this.onMouseLeave.bind(this);
|
||||
this.onFocus = this.onFocus.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onContextMenu = this.onContextMenu.bind(this);
|
||||
this.onMouseEnter = this.onMouseEnter.bind(this);
|
||||
this.onPanelClick = this.onPanelClick.bind(this);
|
||||
}
|
||||
get triggerElement() {
|
||||
return this.triggerElements[0];
|
||||
}
|
||||
// 这些属性变更时,需要更新样式
|
||||
async onPositionChange() {
|
||||
// 如果是打开状态,则更新 panel 的位置
|
||||
if (this.open) {
|
||||
await this.definedController.whenDefined();
|
||||
this.updatePositioner();
|
||||
}
|
||||
}
|
||||
async onOpenChange() {
|
||||
const hasUpdated = this.hasUpdated;
|
||||
// 默认为关闭状态。因此首次渲染时,且为关闭状态,不执行
|
||||
if (!this.open && !hasUpdated) {
|
||||
return;
|
||||
}
|
||||
await this.definedController.whenDefined();
|
||||
if (!hasUpdated) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
const easingLinear = getEasing(this, 'linear');
|
||||
const easingEmphasizedDecelerate = getEasing(this, 'emphasized-decelerate');
|
||||
const easingEmphasizedAccelerate = getEasing(this, 'emphasized-accelerate');
|
||||
// 打开
|
||||
// 要区分是否首次渲染,首次渲染时不触发事件,不执行动画;非首次渲染,触发事件,执行动画
|
||||
if (this.open) {
|
||||
if (hasUpdated) {
|
||||
const eventProceeded = this.emit('open', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// dropdown 打开时,尝试把焦点放到 panel 中
|
||||
const focusablePanel = this.panelElements.find((panel) => isFunction(panel.focus));
|
||||
setTimeout(() => {
|
||||
focusablePanel?.focus();
|
||||
});
|
||||
const duration = getDuration(this, 'medium4');
|
||||
await stopAnimations(this.panelRef.value);
|
||||
this.panelRef.value.hidden = false;
|
||||
this.updatePositioner();
|
||||
await Promise.all([
|
||||
animateTo(this.panelRef.value, [
|
||||
{ transform: `${this.getCssScaleName()}(0.45)` },
|
||||
{ transform: `${this.getCssScaleName()}(1)` },
|
||||
], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingEmphasizedDecelerate,
|
||||
}),
|
||||
animateTo(this.panelRef.value, [{ opacity: 0 }, { opacity: 1, offset: 0.125 }, { opacity: 1 }], {
|
||||
duration: hasUpdated ? duration : 0,
|
||||
easing: easingLinear,
|
||||
}),
|
||||
]);
|
||||
if (hasUpdated) {
|
||||
this.emit('opened');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const eventProceeded = this.emit('close', { cancelable: true });
|
||||
if (!eventProceeded) {
|
||||
return;
|
||||
}
|
||||
// dropdown 关闭时,如果不支持 focus 触发,且焦点在 dropdown 内,则焦点回到 trigger 上
|
||||
if (!this.hasTrigger('focus') &&
|
||||
isFunction(this.triggerElement?.focus) &&
|
||||
(this.contains(document.activeElement) ||
|
||||
this.contains(document.activeElement?.assignedSlot ?? null))) {
|
||||
this.triggerElement.focus();
|
||||
}
|
||||
const duration = getDuration(this, 'short4');
|
||||
await stopAnimations(this.panelRef.value);
|
||||
await Promise.all([
|
||||
animateTo(this.panelRef.value, [
|
||||
{ transform: `${this.getCssScaleName()}(1)` },
|
||||
{ transform: `${this.getCssScaleName()}(0.45)` },
|
||||
], { duration, easing: easingEmphasizedAccelerate }),
|
||||
animateTo(this.panelRef.value, [{ opacity: 1 }, { opacity: 1, offset: 0.875 }, { opacity: 0 }], { duration, easing: easingLinear }),
|
||||
]);
|
||||
// 可能关闭 dropdown 时该元素已经不存在了(比如页面直接跳转了)
|
||||
if (this.panelRef.value) {
|
||||
this.panelRef.value.hidden = true;
|
||||
}
|
||||
this.emit('closed');
|
||||
}
|
||||
}
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.definedController.whenDefined().then(() => {
|
||||
document.addEventListener('pointerdown', this.onDocumentClick);
|
||||
document.addEventListener('keydown', this.onDocumentKeydown);
|
||||
this.overflowAncestors = getOverflowAncestors(this.triggerElement);
|
||||
this.overflowAncestors.forEach((ancestor) => {
|
||||
ancestor.addEventListener('scroll', this.onWindowScroll);
|
||||
});
|
||||
// triggerElement 的尺寸变化时,重新调整 panel 的位置
|
||||
this.observeResize = observeResize(this.triggerElement, () => {
|
||||
this.updatePositioner();
|
||||
});
|
||||
});
|
||||
}
|
||||
disconnectedCallback() {
|
||||
// 移除组件时,如果关闭动画正在进行中,则会导致关闭动画无法执行完成,最终组件无法隐藏
|
||||
// 具体场景为 vue 的 <keep-alive> 中切换走,再切换回来时,面板仍然打开着
|
||||
if (!this.open && this.panelRef.value) {
|
||||
this.panelRef.value.hidden = true;
|
||||
}
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('pointerdown', this.onDocumentClick);
|
||||
document.removeEventListener('keydown', this.onDocumentKeydown);
|
||||
this.overflowAncestors?.forEach((ancestor) => {
|
||||
ancestor.removeEventListener('scroll', this.onWindowScroll);
|
||||
});
|
||||
this.observeResize?.unobserve();
|
||||
}
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener('mouseleave', this.onMouseLeave);
|
||||
this.definedController.whenDefined().then(() => {
|
||||
this.triggerElement.addEventListener('focus', this.onFocus);
|
||||
this.triggerElement.addEventListener('click', this.onClick);
|
||||
this.triggerElement.addEventListener('contextmenu', this.onContextMenu);
|
||||
this.triggerElement.addEventListener('mouseenter', this.onMouseEnter);
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return html `<slot name="trigger" part="trigger" class="trigger"></slot><slot ${ref(this.panelRef)} part="panel" class="panel" hidden @click="${this.onPanelClick}"></slot>`;
|
||||
}
|
||||
/**
|
||||
* 获取 dropdown 打开、关闭动画的 CSS scaleX 或 scaleY
|
||||
*/
|
||||
getCssScaleName() {
|
||||
return this.animateDirection === 'horizontal' ? 'scaleX' : 'scaleY';
|
||||
}
|
||||
/**
|
||||
* 在 document 上点击时,根据条件判断是否要关闭 dropdown
|
||||
*/
|
||||
onDocumentClick(e) {
|
||||
if (this.disabled || !this.open) {
|
||||
return;
|
||||
}
|
||||
const path = e.composedPath();
|
||||
// 点击 dropdown 外部区域,直接关闭
|
||||
if (!path.includes(this)) {
|
||||
this.open = false;
|
||||
}
|
||||
// 当包含 contextmenu 且不包含 click 时,点击 trigger,关闭
|
||||
if (this.hasTrigger('contextmenu') &&
|
||||
!this.hasTrigger('click') &&
|
||||
path.includes(this.triggerElement)) {
|
||||
this.open = false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 在 document 上按下按键时,根据条件判断是否要关闭 dropdown
|
||||
*/
|
||||
onDocumentKeydown(event) {
|
||||
if (this.disabled || !this.open) {
|
||||
return;
|
||||
}
|
||||
// 按下 ESC 键时,关闭 dropdown
|
||||
if (event.key === 'Escape') {
|
||||
this.open = false;
|
||||
return;
|
||||
}
|
||||
// 按下 Tab 键时,关闭 dropdown
|
||||
if (event.key === 'Tab') {
|
||||
// 如果不支持 focus 触发,则焦点回到 trigger 上(这个会在 onOpenChange 中执行 )这里只需阻止默认的 Tab 行为
|
||||
if (!this.hasTrigger('focus') && isFunction(this.triggerElement?.focus)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
this.open = false;
|
||||
}
|
||||
}
|
||||
onWindowScroll() {
|
||||
window.requestAnimationFrame(() => this.onPositionChange());
|
||||
}
|
||||
hasTrigger(trigger) {
|
||||
const triggers = this.trigger.split(' ');
|
||||
return triggers.includes(trigger);
|
||||
}
|
||||
onFocus() {
|
||||
if (this.disabled || this.open || !this.hasTrigger('focus')) {
|
||||
return;
|
||||
}
|
||||
this.open = true;
|
||||
}
|
||||
onClick(e) {
|
||||
// e.button 为 0 时,为鼠标左键点击。忽略鼠标中间和右键
|
||||
if (this.disabled || e.button || !this.hasTrigger('click')) {
|
||||
return;
|
||||
}
|
||||
// 支持 hover 或 focus 触发时,点击时,不关闭 dropdown
|
||||
if (this.open && (this.hasTrigger('hover') || this.hasTrigger('focus'))) {
|
||||
return;
|
||||
}
|
||||
this.pointerOffsetX = e.offsetX;
|
||||
this.pointerOffsetY = e.offsetY;
|
||||
this.open = !this.open;
|
||||
}
|
||||
onPanelClick(e) {
|
||||
if (!this.disabled &&
|
||||
!this.stayOpenOnClick &&
|
||||
$(e.target).is('mdui-menu-item')) {
|
||||
this.open = false;
|
||||
}
|
||||
}
|
||||
onContextMenu(e) {
|
||||
if (this.disabled || !this.hasTrigger('contextmenu')) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
this.pointerOffsetX = e.offsetX;
|
||||
this.pointerOffsetY = e.offsetY;
|
||||
this.open = true;
|
||||
}
|
||||
onMouseEnter() {
|
||||
// 不做 open 状态的判断,因为可以延时打开和关闭
|
||||
if (this.disabled || !this.hasTrigger('hover')) {
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(this.closeTimeout);
|
||||
if (this.openDelay) {
|
||||
this.openTimeout = window.setTimeout(() => {
|
||||
this.open = true;
|
||||
}, this.openDelay);
|
||||
}
|
||||
else {
|
||||
this.open = true;
|
||||
}
|
||||
}
|
||||
onMouseLeave() {
|
||||
// 不做 open 状态的判断,因为可以延时打开和关闭
|
||||
if (this.disabled || !this.hasTrigger('hover')) {
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(this.openTimeout);
|
||||
this.closeTimeout = window.setTimeout(() => {
|
||||
this.open = false;
|
||||
}, this.closeDelay || 50);
|
||||
}
|
||||
// 更新 panel 的位置
|
||||
updatePositioner() {
|
||||
const $panel = $(this.panelRef.value);
|
||||
const $window = $(window);
|
||||
const panelElements = this.panelElements;
|
||||
const panelRect = {
|
||||
width: Math.max(...(panelElements?.map((panel) => panel.offsetWidth) ?? [])),
|
||||
height: panelElements
|
||||
?.map((panel) => panel.offsetHeight)
|
||||
.reduce((total, height) => total + height, 0),
|
||||
};
|
||||
// 在光标位置触发时,假设 triggerElement 的宽高为 0,位置位于光标位置
|
||||
const triggerClientRect = this.triggerElement.getBoundingClientRect();
|
||||
const triggerRect = this.openOnPointer
|
||||
? {
|
||||
top: this.pointerOffsetY + triggerClientRect.top,
|
||||
left: this.pointerOffsetX + triggerClientRect.left,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
: triggerClientRect;
|
||||
// dropdown 与屏幕边界至少保留 8px 间距
|
||||
const screenMargin = 8;
|
||||
let transformOriginX;
|
||||
let transformOriginY;
|
||||
let top;
|
||||
let left;
|
||||
let placement = this.placement;
|
||||
// 自动判断 dropdown 的方位
|
||||
// 优先级为 bottom>top>right>left,start>center>end
|
||||
if (placement === 'auto') {
|
||||
const windowWidth = $window.width();
|
||||
const windowHeight = $window.height();
|
||||
let position;
|
||||
let alignment;
|
||||
if (windowHeight - triggerRect.top - triggerRect.height >
|
||||
panelRect.height + screenMargin) {
|
||||
// 下方放得下,放下方
|
||||
position = 'bottom';
|
||||
}
|
||||
else if (triggerRect.top > panelRect.height + screenMargin) {
|
||||
// 上方放得下,放上方
|
||||
position = 'top';
|
||||
}
|
||||
else if (windowWidth - triggerRect.left - triggerRect.width >
|
||||
panelRect.width + screenMargin) {
|
||||
// 右侧放得下,放右侧
|
||||
position = 'right';
|
||||
}
|
||||
else if (triggerRect.left > panelRect.width + screenMargin) {
|
||||
// 左侧放得下,放左侧
|
||||
position = 'left';
|
||||
}
|
||||
else {
|
||||
// 默认放下方
|
||||
position = 'bottom';
|
||||
}
|
||||
if (['top', 'bottom'].includes(position)) {
|
||||
if (windowWidth - triggerRect.left > panelRect.width + screenMargin) {
|
||||
// 左对齐放得下,左对齐
|
||||
alignment = 'start';
|
||||
}
|
||||
else if (triggerRect.left + triggerRect.width / 2 >
|
||||
panelRect.width / 2 + screenMargin &&
|
||||
windowWidth - triggerRect.left - triggerRect.width / 2 >
|
||||
panelRect.width / 2 + screenMargin) {
|
||||
// 居中对齐放得下,居中对齐
|
||||
alignment = undefined;
|
||||
}
|
||||
else if (triggerRect.left + triggerRect.width >
|
||||
panelRect.width + screenMargin) {
|
||||
// 右对齐放得下,右对齐
|
||||
alignment = 'end';
|
||||
}
|
||||
else {
|
||||
// 默认左对齐
|
||||
alignment = 'start';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (windowHeight - triggerRect.top > panelRect.height + screenMargin) {
|
||||
// 顶部对齐放得下,顶部对齐
|
||||
alignment = 'start';
|
||||
}
|
||||
else if (triggerRect.top + triggerRect.height / 2 >
|
||||
panelRect.height / 2 + screenMargin &&
|
||||
windowHeight - triggerRect.top - triggerRect.height / 2 >
|
||||
panelRect.height / 2 + screenMargin) {
|
||||
// 居中对齐放得下,居中对齐
|
||||
alignment = undefined;
|
||||
}
|
||||
else if (triggerRect.top + triggerRect.height >
|
||||
panelRect.height + screenMargin) {
|
||||
// 底部对齐放得下,底部对齐
|
||||
alignment = 'end';
|
||||
}
|
||||
else {
|
||||
// 默认顶部对齐
|
||||
alignment = 'start';
|
||||
}
|
||||
}
|
||||
placement = alignment
|
||||
? [position, alignment].join('-')
|
||||
: position;
|
||||
}
|
||||
// 根据 placement 计算 panel 的位置和方向
|
||||
const [position, alignment] = placement.split('-');
|
||||
this.animateDirection = ['top', 'bottom'].includes(position)
|
||||
? 'vertical'
|
||||
: 'horizontal';
|
||||
switch (position) {
|
||||
case 'top':
|
||||
transformOriginY = 'bottom';
|
||||
top = triggerRect.top - panelRect.height;
|
||||
break;
|
||||
case 'bottom':
|
||||
transformOriginY = 'top';
|
||||
top = triggerRect.top + triggerRect.height;
|
||||
break;
|
||||
default:
|
||||
transformOriginY = 'center';
|
||||
switch (alignment) {
|
||||
case 'start':
|
||||
top = triggerRect.top;
|
||||
break;
|
||||
case 'end':
|
||||
top = triggerRect.top + triggerRect.height - panelRect.height;
|
||||
break;
|
||||
default:
|
||||
top =
|
||||
triggerRect.top + triggerRect.height / 2 - panelRect.height / 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (position) {
|
||||
case 'left':
|
||||
transformOriginX = 'right';
|
||||
left = triggerRect.left - panelRect.width;
|
||||
break;
|
||||
case 'right':
|
||||
transformOriginX = 'left';
|
||||
left = triggerRect.left + triggerRect.width;
|
||||
break;
|
||||
default:
|
||||
transformOriginX = 'center';
|
||||
switch (alignment) {
|
||||
case 'start':
|
||||
left = triggerRect.left;
|
||||
break;
|
||||
case 'end':
|
||||
left = triggerRect.left + triggerRect.width - panelRect.width;
|
||||
break;
|
||||
default:
|
||||
left =
|
||||
triggerRect.left + triggerRect.width / 2 - panelRect.width / 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$panel.css({
|
||||
top,
|
||||
left,
|
||||
transformOrigin: [transformOriginX, transformOriginY].join(' '),
|
||||
});
|
||||
}
|
||||
};
|
||||
Dropdown.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Dropdown.prototype, "open", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Dropdown.prototype, "disabled", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Dropdown.prototype, "trigger", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Dropdown.prototype, "placement", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'stay-open-on-click',
|
||||
})
|
||||
], Dropdown.prototype, "stayOpenOnClick", void 0);
|
||||
__decorate([
|
||||
property({ type: Number, reflect: true, attribute: 'open-delay' })
|
||||
], Dropdown.prototype, "openDelay", void 0);
|
||||
__decorate([
|
||||
property({ type: Number, reflect: true, attribute: 'close-delay' })
|
||||
], Dropdown.prototype, "closeDelay", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
attribute: 'open-on-pointer',
|
||||
})
|
||||
], Dropdown.prototype, "openOnPointer", void 0);
|
||||
__decorate([
|
||||
queryAssignedElements({ slot: 'trigger', flatten: true })
|
||||
], Dropdown.prototype, "triggerElements", void 0);
|
||||
__decorate([
|
||||
queryAssignedElements({ flatten: true })
|
||||
], Dropdown.prototype, "panelElements", void 0);
|
||||
__decorate([
|
||||
watch('placement', true),
|
||||
watch('openOnPointer', true)
|
||||
], Dropdown.prototype, "onPositionChange", null);
|
||||
__decorate([
|
||||
watch('open')
|
||||
], Dropdown.prototype, "onOpenChange", null);
|
||||
Dropdown = __decorate([
|
||||
customElement('mdui-dropdown')
|
||||
], Dropdown);
|
||||
export { Dropdown };
|
||||
1
mdui_patched/components/dropdown/style.d.ts
vendored
Normal file
1
mdui_patched/components/dropdown/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
2
mdui_patched/components/dropdown/style.js
Normal file
2
mdui_patched/components/dropdown/style.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--z-index:2100;display:contents}.panel{display:block;position:fixed;z-index:var(--z-index)}`;
|
||||
1
mdui_patched/components/fab.d.ts
vendored
Normal file
1
mdui_patched/components/fab.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './fab/index.js';
|
||||
1
mdui_patched/components/fab.js
Normal file
1
mdui_patched/components/fab.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './fab/index.js';
|
||||
76
mdui_patched/components/fab/index.d.ts
vendored
Normal file
76
mdui_patched/components/fab/index.d.ts
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import type { Ripple } from '../ripple/index.js';
|
||||
import type { TemplateResult, CSSResultGroup } from 'lit';
|
||||
/**
|
||||
* @summary 浮动操作按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-fab icon="edit"></mdui-fab>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 文本
|
||||
* @slot icon - 图标
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 右侧的文本
|
||||
* @csspart icon - 左侧的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner-small - `size="small"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-normal - `size="normal"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-large - `size="large"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
export declare class Fab extends ButtonBase<FabEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* FAB 的形状,此组件的不同形状之间只有颜色不一样。可选值包括:
|
||||
*
|
||||
* * `primary`:使用 Primary container 背景色
|
||||
* * `surface`:使用 Surface container high 背景色
|
||||
* * `secondary`:使用 Secondary container 背景色
|
||||
* * `tertiary`:使用 Tertiary container 背景色
|
||||
*/
|
||||
variant: /*使用 Primary container 背景色*/ 'primary' | /*使用 Surface container high 背景色*/ 'surface' | /*使用 Secondary container 背景色*/ 'secondary' | /*使用 Tertiary container 背景色*/ 'tertiary';
|
||||
/**
|
||||
* FAB 的大小。可选值包括:
|
||||
* * `normal`:普通大小 FAB
|
||||
* * `small`:小型 FAB
|
||||
* * `large`:大型 FAB
|
||||
*/
|
||||
size: /*普通大小 FAB*/ 'normal' | /*小型 FAB*/ 'small' | /*大型 FAB*/ 'large';
|
||||
/**
|
||||
* Material Icons 图标名。也可以通过 `slot="icon"` 设置
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 是否为展开状态
|
||||
*/
|
||||
extended: boolean;
|
||||
private readonly rippleRef;
|
||||
private readonly hasSlotController;
|
||||
private readonly definedController;
|
||||
protected get rippleElement(): Ripple;
|
||||
/**
|
||||
* extended 变更时,设置动画
|
||||
*/
|
||||
private onExtendedChange;
|
||||
protected render(): TemplateResult;
|
||||
private renderLabel;
|
||||
private renderIcon;
|
||||
private renderInner;
|
||||
}
|
||||
export interface FabEventMap {
|
||||
focus: FocusEvent;
|
||||
blur: FocusEvent;
|
||||
invalid: CustomEvent<void>;
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-fab': Fab;
|
||||
}
|
||||
}
|
||||
149
mdui_patched/components/fab/index.js
Normal file
149
mdui_patched/components/fab/index.js
Normal file
@@ -0,0 +1,149 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref } from 'lit/directives/ref.js';
|
||||
import cc from 'classcat';
|
||||
import { DefinedController } from '@mdui/shared/controllers/defined.js';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { watch } from '@mdui/shared/decorators/watch.js';
|
||||
import { booleanConverter } from '@mdui/shared/helpers/decorator.js';
|
||||
import { delay } from '@mdui/shared/helpers/delay.js';
|
||||
import { nothingTemplate } from '@mdui/shared/helpers/template.js';
|
||||
import { ButtonBase } from '../button/button-base.js';
|
||||
import '../icon.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 浮动操作按钮组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-fab icon="edit"></mdui-fab>
|
||||
* ```
|
||||
*
|
||||
* @event focus - 获得焦点时触发
|
||||
* @event blur - 失去焦点时触发
|
||||
* @event invalid - 表单字段验证未通过时触发
|
||||
*
|
||||
* @slot - 文本
|
||||
* @slot icon - 图标
|
||||
*
|
||||
* @csspart button - 内部的 `<button>` 或 `<a>` 元素
|
||||
* @csspart label - 右侧的文本
|
||||
* @csspart icon - 左侧的图标
|
||||
* @csspart loading - 加载中状态的 `<mdui-circular-progress>` 元素
|
||||
*
|
||||
* @cssprop --shape-corner-small - `size="small"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-normal - `size="normal"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
* @cssprop --shape-corner-large - `size="large"` 时,组件的圆角大小。可以指定一个具体的像素值;但更推荐引用[设计令牌](/docs/2/styles/design-tokens#shape-corner)
|
||||
*/
|
||||
let Fab = class Fab extends ButtonBase {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
/**
|
||||
* FAB 的形状,此组件的不同形状之间只有颜色不一样。可选值包括:
|
||||
*
|
||||
* * `primary`:使用 Primary container 背景色
|
||||
* * `surface`:使用 Surface container high 背景色
|
||||
* * `secondary`:使用 Secondary container 背景色
|
||||
* * `tertiary`:使用 Tertiary container 背景色
|
||||
*/
|
||||
this.variant = 'primary';
|
||||
/**
|
||||
* FAB 的大小。可选值包括:
|
||||
* * `normal`:普通大小 FAB
|
||||
* * `small`:小型 FAB
|
||||
* * `large`:大型 FAB
|
||||
*/
|
||||
this.size = 'normal';
|
||||
/**
|
||||
* 是否为展开状态
|
||||
*/
|
||||
this.extended = false;
|
||||
this.rippleRef = createRef();
|
||||
this.hasSlotController = new HasSlotController(this, 'icon');
|
||||
this.definedController = new DefinedController(this, {
|
||||
relatedElements: [''],
|
||||
});
|
||||
}
|
||||
get rippleElement() {
|
||||
return this.rippleRef.value;
|
||||
}
|
||||
/**
|
||||
* extended 变更时,设置动画
|
||||
*/
|
||||
async onExtendedChange() {
|
||||
const hasUpdated = this.hasUpdated;
|
||||
if (this.extended) {
|
||||
this.style.width = `${this.scrollWidth}px`;
|
||||
}
|
||||
else {
|
||||
this.style.width = '';
|
||||
}
|
||||
await this.definedController.whenDefined();
|
||||
await this.updateComplete;
|
||||
if (this.extended && !hasUpdated) {
|
||||
this.style.width = `${this.scrollWidth}px`;
|
||||
}
|
||||
if (!hasUpdated) {
|
||||
// 延迟设置动画,避免首次渲染时也执行动画
|
||||
await delay();
|
||||
this.style.transitionProperty = 'box-shadow, width, bottom, transform'; // bottom, transform 在 bottom-app-bar 中用到
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const className = cc({
|
||||
button: true,
|
||||
'has-icon': this.icon || this.hasSlotController.test('icon'),
|
||||
});
|
||||
return html `<mdui-ripple ${ref(this.rippleRef)} .noRipple="${this.noRipple}"></mdui-ripple>${this.isButton()
|
||||
? this.renderButton({
|
||||
className,
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})
|
||||
: this.disabled || this.loading
|
||||
? html `<span part="button" class="_a ${className}">${this.renderInner()}</span>`
|
||||
: this.renderAnchor({
|
||||
className,
|
||||
part: 'button',
|
||||
content: this.renderInner(),
|
||||
})}`;
|
||||
}
|
||||
renderLabel() {
|
||||
return html `<slot part="label" class="label"></slot>`;
|
||||
}
|
||||
renderIcon() {
|
||||
if (this.loading) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
return html `<slot name="icon" part="icon" class="icon">${this.icon
|
||||
? html `<mdui-icon name="${this.icon}"></mdui-icon>`
|
||||
: nothingTemplate}</slot>`;
|
||||
}
|
||||
renderInner() {
|
||||
return [this.renderIcon(), this.renderLabel()];
|
||||
}
|
||||
};
|
||||
Fab.styles = [ButtonBase.styles, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Fab.prototype, "variant", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Fab.prototype, "size", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Fab.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
converter: booleanConverter,
|
||||
})
|
||||
], Fab.prototype, "extended", void 0);
|
||||
__decorate([
|
||||
watch('extended')
|
||||
], Fab.prototype, "onExtendedChange", null);
|
||||
Fab = __decorate([
|
||||
customElement('mdui-fab')
|
||||
], Fab);
|
||||
export { Fab };
|
||||
1
mdui_patched/components/fab/style.d.ts
vendored
Normal file
1
mdui_patched/components/fab/style.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const style: import("lit").CSSResult;
|
||||
8
mdui_patched/components/fab/style.js
Normal file
8
mdui_patched/components/fab/style.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { css } from 'lit';
|
||||
export const style = css `:host{--shape-corner-small:var(--mdui-shape-corner-small);--shape-corner-normal:var(--mdui-shape-corner-large);--shape-corner-large:var(--mdui-shape-corner-extra-large);position:relative;display:inline-block;flex-shrink:0;overflow:hidden;text-align:center;border-radius:var(--shape-corner-normal);cursor:pointer;-webkit-tap-highlight-color:transparent;transition-property:box-shadow;transition-timing-function:var(--mdui-motion-easing-emphasized);transition-duration:var(--mdui-motion-duration-medium4);width:3.5rem;height:3.5rem;box-shadow:var(--mdui-elevation-level3);font-size:var(--mdui-typescale-label-large-size);font-weight:var(--mdui-typescale-label-large-weight);letter-spacing:var(--mdui-typescale-label-large-tracking);line-height:var(--mdui-typescale-label-large-line-height)}.button{padding:0 1rem}:host([size=small]) .button{padding:0 .5rem}:host([size=large]) .button{padding:0 1.875rem}:host([lowered]){box-shadow:var(--mdui-elevation-level1)}:host([focus-visible]){box-shadow:var(--mdui-elevation-level3)}:host([lowered][focus-visible]){box-shadow:var(--mdui-elevation-level1)}:host([pressed]){box-shadow:var(--mdui-elevation-level3)}:host([lowered][pressed]){box-shadow:var(--mdui-elevation-level1)}:host([hover]){box-shadow:var(--mdui-elevation-level4)}:host([lowered][hover]){box-shadow:var(--mdui-elevation-level2)}:host([variant=primary]){color:rgb(var(--mdui-color-on-primary-container));background-color:rgb(var(--mdui-color-primary-container));--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-primary-container
|
||||
)}:host([variant=surface]){color:rgb(var(--mdui-color-primary));background-color:rgb(var(--mdui-color-surface-container-high));--mdui-comp-ripple-state-layer-color:var(--mdui-color-primary)}:host([variant=surface][lowered]){background-color:rgb(var(--mdui-color-surface-container-low))}:host([variant=secondary]){color:rgb(var(--mdui-color-on-secondary-container));background-color:rgb(var(--mdui-color-secondary-container));--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-secondary-container
|
||||
)}:host([variant=tertiary]){color:rgb(var(--mdui-color-on-tertiary-container));background-color:rgb(var(--mdui-color-tertiary-container));--mdui-comp-ripple-state-layer-color:var(
|
||||
--mdui-color-on-tertiary-container
|
||||
)}:host([size=small]){border-radius:var(--shape-corner-small);width:2.5rem;height:2.5rem}:host([size=large]){border-radius:var(--shape-corner-large);width:6rem;height:6rem}:host([disabled]:not([disabled=false i])),:host([loading]:not([loading=false i])){cursor:default;pointer-events:none}:host([disabled]:not([disabled=false i])){color:rgba(var(--mdui-color-on-surface),38%);background-color:rgba(var(--mdui-color-on-surface),12%);box-shadow:var(--mdui-elevation-level0)}:host([extended]:not([extended=false i])){width:auto}.label{display:inline-flex;transition:opacity var(--mdui-motion-duration-short2) var(--mdui-motion-easing-linear) var(--mdui-motion-duration-short2);padding-left:.25rem;padding-right:.25rem}.has-icon .label{margin-left:.5rem}:host([size=small]) .has-icon .label{margin-left:.25rem}:host([size=large]) .has-icon .label{margin-left:1rem}:host(:not([extended])) .label,:host([extended=false i]) .label{opacity:0;transition-delay:0s;transition-duration:var(--mdui-motion-duration-short1)}:host([size=large]) .label{font-size:1.5em}.icon{display:inline-flex;font-size:1.71428571em}:host([size=large]) .icon{font-size:2.57142857em}.icon mdui-icon,::slotted([slot=icon]){font-size:inherit}mdui-circular-progress{display:inline-flex;width:1.5rem;height:1.5rem}:host([size=large]) mdui-circular-progress{width:2.25rem;height:2.25rem}:host([disabled]:not([disabled=false i])) mdui-circular-progress{stroke:rgba(var(--mdui-color-on-surface),38%)}`;
|
||||
1
mdui_patched/components/icon.d.ts
vendored
Normal file
1
mdui_patched/components/icon.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './icon/index.js';
|
||||
1
mdui_patched/components/icon.js
Normal file
1
mdui_patched/components/icon.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './icon/index.js';
|
||||
31
mdui_patched/components/icon/index.d.ts
vendored
Normal file
31
mdui_patched/components/icon/index.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import type { TemplateResult, CSSResultGroup } from 'lit';
|
||||
/**
|
||||
* @summary 图标组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-icon name="search"></mdui-icon>
|
||||
* ```
|
||||
*
|
||||
* @slot - `svg` 图标的内容
|
||||
*/
|
||||
export declare class Icon extends MduiElement<IconEventMap> {
|
||||
static styles: CSSResultGroup;
|
||||
/**
|
||||
* Material Icons 图标名
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* svg 图标的路径
|
||||
*/
|
||||
src?: string;
|
||||
private readonly hasSlotController;
|
||||
protected render(): TemplateResult;
|
||||
}
|
||||
export interface IconEventMap {
|
||||
}
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'mdui-icon': Icon;
|
||||
}
|
||||
}
|
||||
59
mdui_patched/components/icon/index.js
Normal file
59
mdui_patched/components/icon/index.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { __decorate } from "tslib";
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
import { ajax } from '@mdui/jq/functions/ajax.js';
|
||||
import { MduiElement } from '@mdui/shared/base/mdui-element.js';
|
||||
import { HasSlotController } from '@mdui/shared/controllers/has-slot.js';
|
||||
import { componentStyle } from '@mdui/shared/lit-styles/component-style.js';
|
||||
import { style } from './style.js';
|
||||
/**
|
||||
* @summary 图标组件
|
||||
*
|
||||
* ```html
|
||||
* <mdui-icon name="search"></mdui-icon>
|
||||
* ```
|
||||
*
|
||||
* @slot - `svg` 图标的内容
|
||||
*/
|
||||
let Icon = class Icon extends MduiElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.hasSlotController = new HasSlotController(this, '[default]');
|
||||
}
|
||||
render() {
|
||||
const renderDefault = () => {
|
||||
if (this.name) {
|
||||
const [name, variant] = this.name.split('--');
|
||||
const familyMap = new Map([
|
||||
['outlined', 'Material Icons Outlined'],
|
||||
['filled', 'Material Icons'],
|
||||
['rounded', 'Material Icons Round'],
|
||||
['sharp', 'Material Icons Sharp'],
|
||||
['two-tone', 'Material Icons Two Tone'],
|
||||
]);
|
||||
return html `<span translate="no" style="${styleMap({ fontFamily: familyMap.get(variant) })}">${name}</span>`;
|
||||
}
|
||||
if (this.src) {
|
||||
return html `${until(ajax({ url: this.src }).then(unsafeSVG))}`;
|
||||
}
|
||||
return html ``;
|
||||
};
|
||||
return this.hasSlotController.test('[default]')
|
||||
? html `<slot></slot>`
|
||||
: renderDefault();
|
||||
}
|
||||
};
|
||||
Icon.styles = [componentStyle, style];
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Icon.prototype, "name", void 0);
|
||||
__decorate([
|
||||
property({ reflect: true })
|
||||
], Icon.prototype, "src", void 0);
|
||||
Icon = __decorate([
|
||||
customElement('mdui-icon')
|
||||
], Icon);
|
||||
export { Icon };
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user