All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.flow.component.splitlayout.SplitLayout Maven / Gradle / Ivy

There is a newer version: 24.5.5
Show newest version
/**
 * Copyright (C) 2000-2024 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */
package com.vaadin.flow.component.splitlayout;

import java.util.Locale;
import java.util.Objects;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.internal.StateTree;
import com.vaadin.flow.shared.Registration;

/**
 * Split Layout is a component with two content areas and a draggable split
 * handle between them.
 *
 * @author Vaadin Ltd
 */
@SuppressWarnings("deprecation")
@NpmPackage(value = "@vaadin/split-layout", version = "23.5.2")
@NpmPackage(value = "@vaadin/vaadin-split-layout", version = "23.5.2")
public class SplitLayout extends GeneratedVaadinSplitLayout
        implements HasSize {

    private Component primaryComponent;
    private Component secondaryComponent;
    private StateTree.ExecutionRegistration updateStylesRegistration;
    private Double splitterPosition;

    /**
     * numeration of all available orientation for VaadinSplitLayout component
     */
    public enum Orientation {
        VERTICAL, HORIZONTAL;
    }

    /**
     * Constructs an empty SplitLayout.
     */
    public SplitLayout() {
        setOrientation(Orientation.HORIZONTAL);
        addAttachListener(
                e -> this.requestStylesUpdatesForSplitterPosition(e.getUI()));
    }

    /**
     * Constructs a SplitLayout with the given initial components to set to the
     * primary and secondary splits.
     *
     * @param primaryComponent
     *            the component set to the primary split
     * @param secondaryComponent
     *            the component set to the secondary split
     */
    public SplitLayout(Component primaryComponent,
            Component secondaryComponent) {
        this();
        addToPrimary(primaryComponent);
        addToSecondary(secondaryComponent);
    }

    /**
     * Constructs a SplitLayout with the orientation.
     *
     * @param orientation
     *            the orientation set to the layout
     */
    public SplitLayout(Orientation orientation) {
        setOrientation(orientation);
        addAttachListener(
                e -> this.requestStylesUpdatesForSplitterPosition(e.getUI()));
    }

    /**
     * Constructs a SplitLayout with the given initial components to set to the
     * primary and secondary splits and with the orientation.
     *
     * @param primaryComponent
     *            the component set to the primary split
     * @param secondaryComponent
     *            the component set to the secondary split
     * @param orientation
     *            the orientation set to the layout
     */
    public SplitLayout(Component primaryComponent, Component secondaryComponent,
            Orientation orientation) {
        this(primaryComponent, secondaryComponent);
        setOrientation(orientation);
    }

    /**
     * Set the orientation of the SplitLayout.
     * 

* Default value is {@link Orientation#HORIZONTAL}. * * * @param orientation * the orientation of the SplitLayout. Valid enumerate values are * VERTICAL and HORIZONTAL, never {@code null} */ public void setOrientation(Orientation orientation) { Objects.requireNonNull(orientation, "Orientation cannot be null"); this.setOrientation(orientation.toString().toLowerCase(Locale.ENGLISH)); } /** * Get the orientation of the SplitLayout. *

* Default value is {@link Orientation#HORIZONTAL}. *

* NOTE: This property is not synchronized automatically from the * client side, so the returned value may not be the same as in client side. *

* * * @return the {@code orientation} property of the SplitLayout. */ public Orientation getOrientation() { return Orientation.valueOf(super.getOrientationString().toUpperCase()); } /** * Sets the given components to the primary split of this layout, i.e. the * left split if in horizontal mode and the top split if in vertical mode. *

* Note: Calling this method with multiple arguments will wrap the * components inside a {@code

} element. *

* Note: Removing the primary component through the component API * will move the secondary component to the primary split, causing this * layout to desync with the server. This is a known issue. * * @see #setOrientation(Orientation) */ @Override public void addToPrimary(Component... components) { primaryComponent = getComponentOrWrap(components); setComponent(primaryComponent, "primary"); } /** * Get the component currently set to the primary split. * * @return the primary component, may be null */ public Component getPrimaryComponent() { return primaryComponent; } /** * Sets the given components to the secondary split of this layout, i.e. the * right split if in horizontal mode and the bottom split if in vertical * mode. *

* Note: Calling this method with multiple arguments will wrap the * components inside a {@code

} element. * * @see #setOrientation(Orientation) */ @Override public void addToSecondary(Component... components) { secondaryComponent = getComponentOrWrap(components); setComponent(secondaryComponent, "secondary"); } /** * Get the component currently set to the secondary split. * * @return the primary component, may be null */ public Component getSecondaryComponent() { return secondaryComponent; } /** * Sets the relative position of the splitter in percentages. The given * value is used to set how much space is given to the primary component * relative to the secondary component. In horizontal mode this is the width * of the component and in vertical mode this is the height. The given value * will automatically be clamped to the range [0, 100]. * * Note that when using vertical orientation, this method only works if the * split layout has an explicit height, either as an absolute value or as * percentage. When using a percentage value, ensure that ancestors have an * explicit height as well. * * @param position * the relative position of the splitter, in percentages */ public void setSplitterPosition(double position) { this.splitterPosition = position; getUI().ifPresent(this::requestStylesUpdatesForSplitterPosition); } private void requestStylesUpdatesForSplitterPosition(UI ui) { if (this.updateStylesRegistration != null) { updateStylesRegistration.remove(); } this.updateStylesRegistration = ui.beforeClientResponse(this, context -> { // Update width or height if splitter position is set. updateStylesForSplitterPosition(); this.updateStylesRegistration = null; }); } private void updateStylesForSplitterPosition() { if (this.splitterPosition == null) { return; } double primary = Math.min(Math.max(this.splitterPosition, 0), 100); double secondary = 100 - primary; setPrimaryStyle("flex", String.format("1 1 %s%%", primary)); setSecondaryStyle("flex", String.format("1 1 %s%%", secondary)); } /** * Set a style to the component in the primary split. * * @param styleName * name of the style to set * @param value * the value to set */ public void setPrimaryStyle(String styleName, String value) { setInnerComponentStyle(styleName, value, true); } /** * Set a style to the component in the secondary split. * * @param styleName * name of the style to set * @param value * the value to set */ public void setSecondaryStyle(String styleName, String value) { setInnerComponentStyle(styleName, value, false); } /** * Returns the component if the given components array contains only one or * a wrapper div with the given components if the array contains more. * * @param components * the components to wrap * @return the component or a wrapper div */ private Component getComponentOrWrap(Component... components) { return components.length == 1 ? components[0] : new Div(components); } /** * Sets the given component to the given slot. * * @param component * the component to set * @param slot * the slot to set the component to */ private void setComponent(Component component, String slot) { getElement().getChildren() .filter(node -> slot.equals(node.getAttribute("slot"))) .forEach(node -> { node.removeAttribute("slot"); getElement().removeChild(node); }); component.getElement().setAttribute("slot", slot); getElement().appendChild(component.getElement()); } @Override public void remove(Component... components) { super.remove(components); } /** * Removes the primary and the secondary components. */ @Override public void removeAll() { super.removeAll(); } /** * Adds a listener for the {@code splitter-dragend} event, which is fired * when the user has stopped resizing the splitter with drag and drop. * * @param listener * the listener to add * @return a registration for removing the listener */ @Override public Registration addSplitterDragendListener( ComponentEventListener> listener) { return super.addSplitterDragendListener(listener); } private void setInnerComponentStyle(String styleName, String value, boolean primary) { Component innerComponent = primary ? primaryComponent : secondaryComponent; if (innerComponent != null) { innerComponent.getElement().executeJs("this.style[$0]=$1", styleName, value); } else { getElement().executeJs( "var element = this.children[$0]; if (element) { element.style[$1]=$2; }", primary ? 0 : 1, styleName, value); } } /** * Adds theme variants to the component. * * @param variants * theme variants to add */ @Override public void addThemeVariants(SplitLayoutVariant... variants) { super.addThemeVariants(variants); } /** * Removes theme variants from the component. * * @param variants * theme variants to remove */ @Override public void removeThemeVariants(SplitLayoutVariant... variants) { super.removeThemeVariants(variants); } public static class SplitterDragendEvent> extends GeneratedVaadinSplitLayout.SplitterDragendEvent { public SplitterDragendEvent(T source, boolean fromClient) { super(source, fromClient); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy