ReactMaterial3/dist/react-you-ui13.mjs

496 lines
19 KiB
JavaScript

import { jsx as C } from "react/jsx-runtime";
import S from "react";
import { o as P } from "./create-component-CVXl33PD.mjs";
import { _ as o, n as u, r as $, x as O, c as L, E as h, a as N, b as z } from "./class-map-CwiboTfb.mjs";
import "./divider-Diu_1O5h.mjs";
import { E as b, r as g, a as l } from "./animation-DjClVFum.mjs";
import { m as H } from "./delegate-BXi1gVeU.mjs";
import { r as _ } from "./redispatch-event-taWUbWUt.mjs";
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const M = {
dialog: [
[
// Dialog slide down
[{ transform: "translateY(-50px)" }, { transform: "translateY(0)" }],
{ duration: 500, easing: b.EMPHASIZED }
]
],
scrim: [
[
// Scrim fade in
[{ opacity: 0 }, { opacity: 0.32 }],
{ duration: 500, easing: "linear" }
]
],
container: [
[
// Container fade in
[{ opacity: 0 }, { opacity: 1 }],
{ duration: 50, easing: "linear", pseudoElement: "::before" }
],
[
// Container grow
// Note: current spec says to grow from 0dp->100% and shrink from
// 100%->35%. We change this to 35%->100% to simplify the animation that
// is supposed to clip content as it grows. From 0dp it's possible to see
// text/actions appear before the container has fully grown.
[{ height: "35%" }, { height: "100%" }],
{ duration: 500, easing: b.EMPHASIZED, pseudoElement: "::before" }
]
],
headline: [
[
// Headline fade in
[{ opacity: 0 }, { opacity: 0, offset: 0.2 }, { opacity: 1 }],
{ duration: 250, easing: "linear", fill: "forwards" }
]
],
content: [
[
// Content fade in
[{ opacity: 0 }, { opacity: 0, offset: 0.2 }, { opacity: 1 }],
{ duration: 250, easing: "linear", fill: "forwards" }
]
],
actions: [
[
// Actions fade in
[{ opacity: 0 }, { opacity: 0, offset: 0.5 }, { opacity: 1 }],
{ duration: 300, easing: "linear", fill: "forwards" }
]
]
}, V = {
dialog: [
[
// Dialog slide up
[{ transform: "translateY(0)" }, { transform: "translateY(-50px)" }],
{ duration: 150, easing: b.EMPHASIZED_ACCELERATE }
]
],
scrim: [
[
// Scrim fade out
[{ opacity: 0.32 }, { opacity: 0 }],
{ duration: 150, easing: "linear" }
]
],
container: [
[
// Container shrink
[{ height: "100%" }, { height: "35%" }],
{
duration: 150,
easing: b.EMPHASIZED_ACCELERATE,
pseudoElement: "::before"
}
],
[
// Container fade out
[{ opacity: "1" }, { opacity: "0" }],
{ delay: 100, duration: 50, easing: "linear", pseudoElement: "::before" }
]
],
headline: [
[
// Headline fade out
[{ opacity: 1 }, { opacity: 0 }],
{ duration: 100, easing: "linear", fill: "forwards" }
]
],
content: [
[
// Content fade out
[{ opacity: 1 }, { opacity: 0 }],
{ duration: 100, easing: "linear", fill: "forwards" }
]
],
actions: [
[
// Actions fade out
[{ opacity: 1 }, { opacity: 0 }],
{ duration: 100, easing: "linear", fill: "forwards" }
]
]
};
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const W = H($);
let s = class extends W {
// We do not use `delegatesFocus: true` due to a Chromium bug with
// selecting text.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=950357
/**
* Opens the dialog when set to `true` and closes it when set to `false`.
*/
get open() {
return this.isOpen;
}
set open(e) {
e !== this.isOpen && (this.isOpen = e, e ? (this.setAttribute("open", ""), this.show()) : (this.removeAttribute("open"), this.close()));
}
constructor() {
super(), this.quick = !1, this.returnValue = "", this.noFocusTrap = !1, this.getOpenAnimation = () => M, this.getCloseAnimation = () => V, this.isOpen = !1, this.isOpening = !1, this.isConnectedPromise = this.getIsConnectedPromise(), this.isAtScrollTop = !1, this.isAtScrollBottom = !1, this.nextClickIsFromContent = !1, this.hasHeadline = !1, this.hasActions = !1, this.hasIcon = !1, this.escapePressedWithoutCancel = !1, this.treewalker = document.createTreeWalker(this, NodeFilter.SHOW_ELEMENT), this.addEventListener("submit", this.handleSubmit);
}
/**
* Opens the dialog and fires a cancelable `open` event. After a dialog's
* animation, an `opened` event is fired.
*
* Add an `autofocus` attribute to a child of the dialog that should
* receive focus after opening.
*
* @return A Promise that resolves after the animation is finished and the
* `opened` event was fired.
*/
async show() {
var i;
this.isOpening = !0, await this.isConnectedPromise, await this.updateComplete;
const e = this.dialog;
if (e.open || !this.isOpening) {
this.isOpening = !1;
return;
}
if (!this.dispatchEvent(new Event("open", { cancelable: !0 }))) {
this.open = !1, this.isOpening = !1;
return;
}
e.showModal(), this.open = !0, this.scroller && (this.scroller.scrollTop = 0), (i = this.querySelector("[autofocus]")) == null || i.focus(), await this.animateDialog(this.getOpenAnimation()), this.dispatchEvent(new Event("opened")), this.isOpening = !1;
}
/**
* Closes the dialog and fires a cancelable `close` event. After a dialog's
* animation, a `closed` event is fired.
*
* @param returnValue A return value usually indicating which button was used
* to close a dialog. If a dialog is canceled by clicking the scrim or
* pressing Escape, it will not change the return value after closing.
* @return A Promise that resolves after the animation is finished and the
* `closed` event was fired.
*/
async close(e = this.returnValue) {
if (this.isOpening = !1, !this.isConnected) {
this.open = !1;
return;
}
await this.updateComplete;
const t = this.dialog;
if (!t.open || this.isOpening) {
this.open = !1;
return;
}
const i = this.returnValue;
if (this.returnValue = e, !this.dispatchEvent(new Event("close", { cancelable: !0 }))) {
this.returnValue = i;
return;
}
await this.animateDialog(this.getCloseAnimation()), t.close(e), this.open = !1, this.dispatchEvent(new Event("closed"));
}
connectedCallback() {
super.connectedCallback(), this.isConnectedPromiseResolve();
}
disconnectedCallback() {
super.disconnectedCallback(), this.isConnectedPromise = this.getIsConnectedPromise();
}
render() {
const e = this.open && !(this.isAtScrollTop && this.isAtScrollBottom), t = {
"has-headline": this.hasHeadline,
"has-actions": this.hasActions,
"has-icon": this.hasIcon,
scrollable: e,
"show-top-divider": e && !this.isAtScrollTop,
"show-bottom-divider": e && !this.isAtScrollBottom
}, i = this.open && !this.noFocusTrap, a = O`
<div
class="focus-trap"
tabindex="0"
aria-hidden="true"
@focus=${this.handleFocusTrapFocus}></div>
`, { ariaLabel: r } = this;
return O`
<div class="scrim"></div>
<dialog
class=${L(t)}
aria-label=${r || h}
aria-labelledby=${this.hasHeadline ? "headline" : h}
role=${this.type === "alert" ? "alertdialog" : h}
@cancel=${this.handleCancel}
@click=${this.handleDialogClick}
@close=${this.handleClose}
@keydown=${this.handleKeydown}
.returnValue=${this.returnValue || h}>
${i ? a : h}
<div class="container" @click=${this.handleContentClick}>
<div class="headline">
<div class="icon" aria-hidden="true">
<slot name="icon" @slotchange=${this.handleIconChange}></slot>
</div>
<h2 id="headline" aria-hidden=${!this.hasHeadline || h}>
<slot
name="headline"
@slotchange=${this.handleHeadlineChange}></slot>
</h2>
<md-divider></md-divider>
</div>
<div class="scroller">
<div class="content">
<div class="top anchor"></div>
<slot name="content"></slot>
<div class="bottom anchor"></div>
</div>
</div>
<div class="actions">
<md-divider></md-divider>
<slot name="actions" @slotchange=${this.handleActionsChange}></slot>
</div>
</div>
${i ? a : h}
</dialog>
`;
}
firstUpdated() {
this.intersectionObserver = new IntersectionObserver((e) => {
for (const t of e)
this.handleAnchorIntersection(t);
}, { root: this.scroller }), this.intersectionObserver.observe(this.topAnchor), this.intersectionObserver.observe(this.bottomAnchor);
}
handleDialogClick() {
if (this.nextClickIsFromContent) {
this.nextClickIsFromContent = !1;
return;
}
this.dispatchEvent(new Event("cancel", { cancelable: !0 })) && this.close();
}
handleContentClick() {
this.nextClickIsFromContent = !0;
}
handleSubmit(e) {
const t = e.target, { submitter: i } = e;
t.method !== "dialog" || !i || this.close(i.getAttribute("value") ?? this.returnValue);
}
handleCancel(e) {
if (e.target !== this.dialog)
return;
this.escapePressedWithoutCancel = !1;
const t = !_(this, e);
e.preventDefault(), !t && this.close();
}
handleClose() {
var e;
this.escapePressedWithoutCancel && (this.escapePressedWithoutCancel = !1, (e = this.dialog) == null || e.dispatchEvent(new Event("cancel", { cancelable: !0 })));
}
handleKeydown(e) {
e.key === "Escape" && (this.escapePressedWithoutCancel = !0, setTimeout(() => {
this.escapePressedWithoutCancel = !1;
}));
}
async animateDialog(e) {
var k;
if ((k = this.cancelAnimations) == null || k.abort(), this.cancelAnimations = new AbortController(), this.quick)
return;
const { dialog: t, scrim: i, container: a, headline: r, content: d, actions: c } = this;
if (!t || !i || !a || !r || !d || !c)
return;
const { container: p, dialog: f, scrim: v, headline: m, content: w, actions: A } = e, E = [
[t, f ?? []],
[i, v ?? []],
[a, p ?? []],
[r, m ?? []],
[d, w ?? []],
[c, A ?? []]
], y = [];
for (const [F, I] of E)
for (const D of I) {
const T = F.animate(...D);
this.cancelAnimations.signal.addEventListener("abort", () => {
T.cancel();
}), y.push(T);
}
await Promise.all(y.map((F) => F.finished.catch(() => {
})));
}
handleHeadlineChange(e) {
const t = e.target;
this.hasHeadline = t.assignedElements().length > 0;
}
handleActionsChange(e) {
const t = e.target;
this.hasActions = t.assignedElements().length > 0;
}
handleIconChange(e) {
const t = e.target;
this.hasIcon = t.assignedElements().length > 0;
}
handleAnchorIntersection(e) {
const { target: t, isIntersecting: i } = e;
t === this.topAnchor && (this.isAtScrollTop = i), t === this.bottomAnchor && (this.isAtScrollBottom = i);
}
getIsConnectedPromise() {
return new Promise((e) => {
this.isConnectedPromiseResolve = e;
});
}
handleFocusTrapFocus(e) {
var m;
const [t, i] = this.getFirstAndLastFocusableChildren();
if (!t || !i) {
(m = this.dialog) == null || m.focus();
return;
}
const a = e.target === this.firstFocusTrap, r = !a, d = e.relatedTarget === t, c = e.relatedTarget === i, p = !d && !c;
if (r && c || a && p) {
t.focus();
return;
}
if (a && d || r && p) {
i.focus();
return;
}
}
getFirstAndLastFocusableChildren() {
if (!this.treewalker)
return [null, null];
let e = null, t = null;
for (this.treewalker.currentNode = this.treewalker.root; this.treewalker.nextNode(); ) {
const i = this.treewalker.currentNode;
B(i) && (e || (e = i), t = i);
}
return [e, t];
}
};
o([
u({ type: Boolean })
], s.prototype, "open", null);
o([
u({ type: Boolean })
], s.prototype, "quick", void 0);
o([
u({ attribute: !1 })
], s.prototype, "returnValue", void 0);
o([
u()
], s.prototype, "type", void 0);
o([
u({ type: Boolean, attribute: "no-focus-trap" })
], s.prototype, "noFocusTrap", void 0);
o([
l("dialog")
], s.prototype, "dialog", void 0);
o([
l(".scrim")
], s.prototype, "scrim", void 0);
o([
l(".container")
], s.prototype, "container", void 0);
o([
l(".headline")
], s.prototype, "headline", void 0);
o([
l(".content")
], s.prototype, "content", void 0);
o([
l(".actions")
], s.prototype, "actions", void 0);
o([
g()
], s.prototype, "isAtScrollTop", void 0);
o([
g()
], s.prototype, "isAtScrollBottom", void 0);
o([
l(".scroller")
], s.prototype, "scroller", void 0);
o([
l(".top.anchor")
], s.prototype, "topAnchor", void 0);
o([
l(".bottom.anchor")
], s.prototype, "bottomAnchor", void 0);
o([
l(".focus-trap")
], s.prototype, "firstFocusTrap", void 0);
o([
g()
], s.prototype, "hasHeadline", void 0);
o([
g()
], s.prototype, "hasActions", void 0);
o([
g()
], s.prototype, "hasIcon", void 0);
function B(n) {
var r;
const e = ":is(button,input,select,textarea,object,:is(a,area)[href],[tabindex],[contenteditable=true])", t = ":not(:disabled,[disabled])";
return n.matches(e + t + ':not([tabindex^="-"])') ? !0 : !n.localName.includes("-") || !n.matches(t) ? !1 : ((r = n.shadowRoot) == null ? void 0 : r.delegatesFocus) ?? !1;
}
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const R = N`:host{border-start-start-radius:var(--md-dialog-container-shape-start-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-start-end-radius:var(--md-dialog-container-shape-start-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-end-radius:var(--md-dialog-container-shape-end-end, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));border-end-start-radius:var(--md-dialog-container-shape-end-start, var(--md-dialog-container-shape, var(--md-sys-shape-corner-extra-large, 28px)));display:contents;margin:auto;max-height:min(560px,100% - 48px);max-width:min(560px,100% - 48px);min-height:140px;min-width:280px;position:fixed;height:fit-content;width:fit-content}dialog{background:rgba(0,0,0,0);border:none;border-radius:inherit;flex-direction:column;height:inherit;margin:inherit;max-height:inherit;max-width:inherit;min-height:inherit;min-width:inherit;outline:none;overflow:visible;padding:0;width:inherit}dialog[open]{display:flex}::backdrop{background:none}.scrim{background:var(--md-sys-color-scrim, #000);display:none;inset:0;opacity:32%;pointer-events:none;position:fixed;z-index:1}:host([open]) .scrim{display:flex}h2{all:unset;align-self:stretch}.headline{align-items:center;color:var(--md-dialog-headline-color, var(--md-sys-color-on-surface, #1d1b20));display:flex;flex-direction:column;font-family:var(--md-dialog-headline-font, var(--md-sys-typescale-headline-small-font, var(--md-ref-typeface-brand, Roboto)));font-size:var(--md-dialog-headline-size, var(--md-sys-typescale-headline-small-size, 1.5rem));line-height:var(--md-dialog-headline-line-height, var(--md-sys-typescale-headline-small-line-height, 2rem));font-weight:var(--md-dialog-headline-weight, var(--md-sys-typescale-headline-small-weight, var(--md-ref-typeface-weight-regular, 400)));position:relative}slot[name=headline]::slotted(*){align-items:center;align-self:stretch;box-sizing:border-box;display:flex;gap:8px;padding:24px 24px 0}.icon{display:flex}slot[name=icon]::slotted(*){color:var(--md-dialog-icon-color, var(--md-sys-color-secondary, #625b71));fill:currentColor;font-size:var(--md-dialog-icon-size, 24px);margin-top:24px;height:var(--md-dialog-icon-size, 24px);width:var(--md-dialog-icon-size, 24px)}.has-icon slot[name=headline]::slotted(*){justify-content:center;padding-top:16px}.scrollable slot[name=headline]::slotted(*){padding-bottom:16px}.scrollable.has-headline slot[name=content]::slotted(*){padding-top:8px}.container{border-radius:inherit;display:flex;flex-direction:column;flex-grow:1;overflow:hidden;position:relative;transform-origin:top}.container::before{background:var(--md-dialog-container-color, var(--md-sys-color-surface-container-high, #ece6f0));border-radius:inherit;content:"";inset:0;position:absolute}.scroller{display:flex;flex:1;flex-direction:column;overflow:hidden;z-index:1}.scrollable .scroller{overflow-y:scroll}.content{color:var(--md-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));font-family:var(--md-dialog-supporting-text-font, var(--md-sys-typescale-body-medium-font, var(--md-ref-typeface-plain, Roboto)));font-size:var(--md-dialog-supporting-text-size, var(--md-sys-typescale-body-medium-size, 0.875rem));line-height:var(--md-dialog-supporting-text-line-height, var(--md-sys-typescale-body-medium-line-height, 1.25rem));flex:1;font-weight:var(--md-dialog-supporting-text-weight, var(--md-sys-typescale-body-medium-weight, var(--md-ref-typeface-weight-regular, 400)));height:min-content;position:relative}slot[name=content]::slotted(*){box-sizing:border-box;padding:24px}.anchor{position:absolute}.top.anchor{top:0}.bottom.anchor{bottom:0}.actions{position:relative}slot[name=actions]::slotted(*){box-sizing:border-box;display:flex;gap:8px;justify-content:flex-end;padding:16px 24px 24px}.has-actions slot[name=content]::slotted(*){padding-bottom:8px}md-divider{display:none;position:absolute}.has-headline.show-top-divider .headline md-divider,.has-actions.show-bottom-divider .actions md-divider{display:flex}.headline md-divider{bottom:0}.actions md-divider{top:0}@media(forced-colors: active){dialog{outline:2px solid WindowText}}
`;
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
let x = class extends s {
};
x.styles = [R];
x = o([
z("md-dialog")
], x);
const q = P({
react: S,
tagName: "md-dialog",
elementClass: x,
events: {
onClose: "close",
onShow: "show",
onOpen: "open",
onOpened: "opened",
onClosed: "closed",
onCancel: "cancel"
}
}), te = (n) => {
const { children: e, quick: t, returnValue: i, noFocusTrap: a, open: r, fullScreen: d, style: c, className: p, id: f, onClose: v, onShow: m, onOpen: w, onOpened: A, onClosed: E, onCancel: y } = n;
return /* @__PURE__ */ C(
q,
{
quick: t,
returnValue: i,
noFocusTrap: a,
open: r,
style: {
...c,
...d ? {
width: "100vw",
height: "100vh",
maxWidth: "100vw",
maxHeight: "100vh"
} : {}
},
className: p,
id: f,
onClose: v,
onShow: m,
onOpen: w,
onOpened: A,
onClosed: E,
onCancel: y,
children: e
}
);
}, ie = (n) => /* @__PURE__ */ C("div", { slot: "headline", ...n, children: n.children }), oe = (n) => /* @__PURE__ */ C("div", { slot: "content", ...n, children: n.children }), se = (n) => /* @__PURE__ */ C("div", { slot: "actions", ...n, children: n.children });
export {
te as Dialog,
se as DialogActions,
oe as DialogContent,
ie as DialogTitle
};