/*
* Copyright 2000-2024 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.component.dialog;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.DomEvent;
import com.vaadin.flow.component.EventData;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.Shortcuts;
import com.vaadin.flow.component.Synchronize;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.shared.HasThemeVariant;
import com.vaadin.flow.component.shared.internal.OverlayClassListProxy;
import com.vaadin.flow.dom.ClassList;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.dom.ElementConstants;
import com.vaadin.flow.dom.ElementDetachEvent;
import com.vaadin.flow.dom.ElementDetachListener;
import com.vaadin.flow.dom.Style;
import com.vaadin.flow.internal.StateTree;
import com.vaadin.flow.router.NavigationTrigger;
import com.vaadin.flow.shared.Registration;
/**
* A Dialog is a small window that can be used to present information and user
* interface elements in an overlay.
*
* Dialogs can be made modal or non-modal. A modal Dialog blocks the user from
* interacting with the rest of the user interface while the Dialog is open, as
* opposed to a non-modal Dialog, which does not block interaction.
*
* Dialogs can be made draggable and resizable. When draggable, the user is able
* to move them around using a pointing device. It is recommended to make
* non-modal Dialogs draggable so that the user can interact with content that
* might otherwise be obscured by the Dialog. A resizable Dialog allows the user
* to resize the Dialog by dragging from the edges of the Dialog with a pointing
* device. Dialogs are not resizable by default.
*
* Dialogs automatically become scrollable when their content overflows. Custom
* scrollable areas can be created using the Scroller component.
*
* Best Practices:
* Dialogs are disruptive by nature and should be used sparingly. Do not use
* them to communicate nonessential information, such as success messages like
* “Logged in”, “Copied”, and so on. Instead, use Notifications when
* appropriate.
*
* @author Vaadin Ltd
*/
@Tag("vaadin-dialog")
@NpmPackage(value = "@vaadin/polymer-legacy-adapter", version = "24.5.3")
@JsModule("@vaadin/polymer-legacy-adapter/style-modules.js")
@NpmPackage(value = "@vaadin/dialog", version = "24.5.3")
@JsModule("@vaadin/dialog/src/vaadin-dialog.js")
@JsModule("./flow-component-renderer.js")
public class Dialog extends Component implements HasComponents, HasSize,
HasStyle, HasThemeVariant {
private static final String OVERLAY_LOCATOR_JS = "this.$.overlay";
private boolean autoAddedToTheUi;
private int configuredCloseActionListeners;
private String width;
private String minWidth;
private String maxWidth;
private String height;
private String minHeight;
private String maxHeight;
private DialogHeader dialogHeader;
private DialogFooter dialogFooter;
private Registration afterProgrammaticNavigationListenerRegistration;
/**
* Creates an empty dialog.
*/
public Dialog() {
// Needs to be updated on each
// attach, as element depends on node id which is subject to change if
// the dialog is transferred to another UI, e.g. due to
// @PreserveOnRefresh
getElement().getNode().addAttachListener(this::attachComponentRenderer);
// Workaround for: https://github.com/vaadin/flow/issues/3496
getElement().setProperty("opened", false);
getElement().addPropertyChangeListener("opened", event -> {
// Only handle client-side changes, server-side changes are already
// handled by setOpened
if (event.isUserOriginated()) {
doSetOpened(this.isOpened(), event.isUserOriginated());
}
});
addListener(DialogResizeEvent.class, event -> {
width = event.getWidth();
height = event.getHeight();
});
setOverlayRole("dialog");
}
/**
* `vaadin-dialog-close-action` is sent when the user clicks outside the
* overlay or presses the escape key.
*/
@DomEvent("vaadin-dialog-close-action")
public static class DialogCloseActionEvent extends ComponentEvent