Skip to content

Commit

Permalink
#414 #415 done (#417)
Browse files Browse the repository at this point in the history
HasLabelPositionable done
  • Loading branch information
vaadin-miki authored Sep 26, 2022
1 parent 6678c34 commit 493e252
Show file tree
Hide file tree
Showing 30 changed files with 342 additions and 22 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ The author of the majority of the code is Miki, but this project would not be po
* Jean-Christophe Gueriaud
* Holger Hähnel
* Matthias Hämmerle
* Jarmo Kemppainen
* Gerald Koch
* Sebastian Kühnau
* Jean-François Lamy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.vaadin.miki.demo.builders;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.combobox.ComboBox;
import org.vaadin.miki.demo.ContentBuilder;
import org.vaadin.miki.demo.Order;
import org.vaadin.miki.markers.HasLabelPositionable;
import org.vaadin.miki.shared.labels.LabelPosition;

import java.util.function.Consumer;

/**
* @author miki
* @since 2022-09-23
*/
@Order(33)
public class HasPositionableLabelBuilder implements ContentBuilder<HasLabelPositionable> {
@Override
public void buildContent(HasLabelPositionable component, Consumer<Component[]> callback) {
final ComboBox<LabelPosition> positions = new ComboBox<>("Pick label position:", LabelPosition.values());
positions.setAllowCustomValue(false);
positions.addValueChangeListener(event -> component.setLabelPosition(event.getValue()));
callback.accept(new Component[]{positions});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.time.LocalDate;
import java.util.function.Consumer;

@Order(61)
@Order(1)
public class ObjectFieldBuilder implements ContentBuilder<ObjectField<Book>> {
@Override
public void buildContent(ObjectField<Book> component, Consumer<Component[]> callback) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* @author miki
* @since 2022-04-11
*/
@Order(80)
@Order(1)
public class VariantFieldBuilder implements ContentBuilder<VariantField> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public CollectionField<String, List<String>> getComponent() {
),
Collections.singletonList(CollectionComponentProviders.addLastButton("Add as last"))),
CollectionComponentProviders.rowWithRemoveButtonFirst(CollectionComponentProviders.labelledField(SuperTextField::new, "Value"), "Remove")
).withHelperText("(validator requires precisely three elements)");
)
.withHelperText("(validator requires precisely three elements)")
.withLabel("Enter some words:")
;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ public class GridMultiSelectProvider implements ComponentProvider<GridMultiSelec
@Override
public GridMultiSelect<SuperFieldsGridItem> getComponent() {
final GridMultiSelect<SuperFieldsGridItem> gridSelect = new GridMultiSelect<>(SuperFieldsGridItem.class, true, SuperFieldsGridItem.getAllRegisteredProviders())
.withHelperText("(you can select multiple rows)");
.withHelperText("(you can select multiple rows)")
.withLabel("Choose as many as you like:")
;
gridSelect.getGrid().getColumnByKey("nameLength").setAutoWidth(true);
return gridSelect;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public class GridSelectProvider implements ComponentProvider<GridSelect<SuperFie
@Override
public GridSelect<SuperFieldsGridItem> getComponent() {
final GridSelect<SuperFieldsGridItem> gridSelect = new GridSelect<>(SuperFieldsGridItem.class, true, SuperFieldsGridItem.getAllRegisteredProviders())
.withHelperText("(at most one row can be selected)");
.withHelperText("(at most one row can be selected)")
.withLabel("Please select your favourite component:");
gridSelect.getGrid().getColumnByKey("nameLength").setAutoWidth(true);
return gridSelect;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public MapField<String, Integer> getComponent() {
() -> new SuperTextField("Any text:"),
() -> new SuperIntegerField("Any integer:")
), "Remove"))
.withHelperText("(this is a Map<String, Integer>)");
.withHelperText("(this is a Map<String, Integer>)")
.withLabel("Please enter key-value data:")
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public ObjectFieldProvider() {
@Override
public ObjectField<Book> getComponent() {
return this.factory.buildAndConfigureObjectField(Book.class)
.withHelperText("(this field with all its components is automatically generated from a model class)")
.withHelperAbove();
.withHelperText("(this entire form with all its components is automatically generated from a model class)")
.withLabel("Book details:")
;
}
}
4 changes: 4 additions & 0 deletions superfields/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Some components contain server-side methods to control text selection in their w

The web components listen to each key press and mouse click. If text selection changes as a result of that action, they send an event to the server-side component. This may happen quite often and increase server load, so the feature is turned off by default. To turn it on simply call `setReceivingSelectionEventsFromClient(true)` (or `withReceivingSelectionEventsFromClient(true)`).

#### Label position

Most of the components that can have a label allow positioning said label through `setLabelPosition(...)` (or `withLabelPosition(...)`). This should work in most layouts, with `FormLayout` being an obvious exception. Not all components support all possible values of `LabelPosition` (`SuperCheckbox` ignores vertical alignment). In addition, things might work weird when using right-to-left languages - if that happens, please report the problem in GitHub.

#### Log messages

Quite a few components log their state using [SLF4J](https://www.slf4j.org). Critical information is logged as error or warning, debugging messages are, well, debug or trace. Information about [how to configure which log messages get displayed can be found e.g. on Stack Overflow](https://stackoverflow.com/questions/45997759/how-to-change-slf4j-logging-level).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.vaadin.miki.markers;

import com.vaadin.flow.component.HasElement;
import org.vaadin.miki.shared.labels.LabelPosition;

/**
* Marker interface for components that have a positionable label.
*
* @author miki
* @since 2022-09-23
*/
public interface HasLabelPositionable extends HasElement {

/**
* Attribute name that contains the selected label position value.
*/
String LABEL_POSITION_ATTRIBUTE = "data-label-position";
/**
* Attribute name that contains details of the label for easy styling.
*/
String LABEL_POSITION_DETAILS_ATTRIBUTE = "data-label-position-details";

/**
* Sets the label position to a new one.
* @param position A position to use. Setting {@code null} will reset it to the default setting.
*/
default void setLabelPosition(LabelPosition position) {
if(position == null || position == LabelPosition.DEFAULT) {
this.getElement().removeAttribute(LABEL_POSITION_ATTRIBUTE);
this.getElement().removeAttribute(LABEL_POSITION_DETAILS_ATTRIBUTE);
}
else {
this.getElement().setAttribute(LABEL_POSITION_ATTRIBUTE, position.name());
this.getElement().setAttribute(LABEL_POSITION_DETAILS_ATTRIBUTE, position.getPositionData());
}
}

/**
* Returns current label position, if it has been set.
* @return A {@link LabelPosition}.
*/
default LabelPosition getLabelPosition() {
if(this.getElement().hasAttribute(LABEL_POSITION_ATTRIBUTE))
return LabelPosition.valueOf(this.getElement().getAttribute(LABEL_POSITION_ATTRIBUTE));
else return LabelPosition.DEFAULT;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.vaadin.miki.markers;

import org.vaadin.miki.shared.labels.LabelPosition;

/**
* A mixin for {@link HasLabelPositionable}.
*
* @author miki
* @since 2022-09-23
*/
public interface WithLabelPositionableMixin<SELF extends HasLabelPositionable> extends HasLabelPositionable {

/**
* Chains {@link #setLabelPosition(LabelPosition)} and returns itself.
* @param position Position.
* @return This.
*/
@SuppressWarnings("unchecked")
default SELF withLabelPosition(LabelPosition position) {
this.setLabelPosition(position);
return (SELF) this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.vaadin.miki.shared.labels;

import java.util.Locale;

/**
* Available label positions.
*
* @author miki
* @since 2022-09-23
*/
public enum LabelPosition {

/**
* Default label position, without any changes.
*/
DEFAULT(false),

/**
* Label is placed to the side of the component, before it, and aligned to the start of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the left, aligned to the top.
*/
BEFORE_START,
/**
* Label is placed to the side of the component, before it, and aligned to the middle of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the left, in the vertical middle of column.
*/
BEFORE_MIDDLE,
/**
* Label is placed to the side of the component, before it, and aligned to the end of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the left, aligned to the bottom.
*/
BEFORE_END,
/**
* Label is placed to the side of the component, after it, and aligned to the start of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the right, aligned to the top.
*/
AFTER_START,
/**
* Label is placed to the side of the component, after it, and aligned to the middle of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the right, in the vertical middle of column.
*/
AFTER_MIDDLE,
/**
* Label is placed to the side of the component, after it, and aligned to the end of the column.
* In left-to-right, top-to-bottom layouts, this means: label on the right, aligned to the bottom.
*/
AFTER_END,
/**
* Label is placed as the last thing of the entire component.
* In left-to-right, top-to-bottom layouts, this means: label on the bottom.
*/
LAST(false);

private final String positionData;

LabelPosition() {
this(true);
}

/**
* Creates the enum.
* @param side Whether the label is on the side of the component.
*/
LabelPosition(boolean side) {
this.positionData = String.join(" ", ((side ? "side_" : "") + this.name()).toLowerCase(Locale.ROOT).split("_"));
}

/**
* The attribute value that corresponds to the given label position. Used by CSS selectors.
* This is a space-separated list of styles. Never {@code null}.
*
* @return A non-{@code null} array.
*/
public String getPositionData() {
return positionData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,29 @@

import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.dependency.CssImport;
import org.vaadin.miki.markers.WithIdMixin;
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithLabelPositionableMixin;
import org.vaadin.miki.markers.WithTitleMixin;
import org.vaadin.miki.markers.WithValueMixin;

import java.util.Objects;

/**
* A regular {@link Checkbox} that has its read-only state synchronised with enabledness.
* This exists purely as a workaround for <a href="https://github.com/vaadin/web-components/issues/688">a known issue of Vaadin</a>.
* While this exists mostly as a workaround for <a href="https://github.com/vaadin/web-components/issues/688">a known issue of Vaadin</a>,
* it also supports label position (though only {@link org.vaadin.miki.shared.labels.LabelPosition}{@code #BEFORE_*}, thus allowing
* the label to be positioned on the other side of the actual checkbox).
*
* @author miki
* @since 2022-09-14
*/
@SuppressWarnings("squid:S110") // no way around big number of parent classes
@CssImport(value = "./styles/label-positions-checkbox.css", themeFor = "vaadin-checkbox")
public class SuperCheckbox extends Checkbox implements
WithLabelMixin<SuperCheckbox>, WithValueMixin<AbstractField.ComponentValueChangeEvent<Checkbox, Boolean>, Boolean, SuperCheckbox>,
WithIdMixin<SuperCheckbox>, WithTitleMixin<SuperCheckbox> {
WithIdMixin<SuperCheckbox>, WithTitleMixin<SuperCheckbox>, WithLabelPositionableMixin<SuperCheckbox> {

@Override
public void setReadOnly(boolean readOnly) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.customfield.CustomField;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.orderedlayout.FlexLayout;
import com.vaadin.flow.function.SerializablePredicate;
import com.vaadin.flow.function.SerializableSupplier;
Expand All @@ -16,6 +17,8 @@
import org.vaadin.miki.markers.WithHelperMixin;
import org.vaadin.miki.markers.WithHelperPositionableMixin;
import org.vaadin.miki.markers.WithIdMixin;
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithLabelPositionableMixin;
import org.vaadin.miki.markers.WithValueMixin;

import java.util.ArrayList;
Expand All @@ -33,12 +36,14 @@
* @param <T> Type of the element in the collection.
* @param <C> Type of the collection.
*/
@CssImport(value = "./styles/label-positions.css", themeFor = "vaadin-custom-field")
public class CollectionField<T, C extends Collection<T>> extends CustomField<C>
implements CollectionController, WithIdMixin<CollectionField<T, C>>, HasStyle,
WithCollectionValueComponentProviderMixin<T, CollectionField<T, C>>,
WithHelperMixin<CollectionField<T, C>>, WithHelperPositionableMixin<CollectionField<T, C>>,
WithValueMixin<AbstractField.ComponentValueChangeEvent<CustomField<C>, C>, C, CollectionField<T, C>>,
WithCollectionElementFilterMixin<T, CollectionField<T, C>> {
WithCollectionElementFilterMixin<T, CollectionField<T, C>>,
WithLabelPositionableMixin<CollectionField<T, C>>, WithLabelMixin<CollectionField<T, C>> {

/**
* CSS class name that will be added to the main layout of this component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.customfield.CustomField;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.function.SerializablePredicate;
import com.vaadin.flow.function.SerializableSupplier;
import org.vaadin.miki.markers.WithHelperMixin;
import org.vaadin.miki.markers.WithHelperPositionableMixin;
import org.vaadin.miki.markers.WithIdMixin;
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithLabelPositionableMixin;
import org.vaadin.miki.markers.WithValueMixin;
import org.vaadin.miki.superfields.layouts.FlexLayoutHelpers;

Expand All @@ -33,11 +35,13 @@
* @author miki
* @since 2022-04-08
*/
@CssImport(value = "./styles/label-positions.css", themeFor = "vaadin-custom-field")
public class MapField<K, V> extends CustomField<Map<K, V>> implements HasStyle,
WithIdMixin<MapField<K, V>>, WithValueMixin<AbstractField.ComponentValueChangeEvent<CustomField<Map<K, V>>, Map<K, V>>, Map<K, V>, MapField<K, V>>,
WithHelperPositionableMixin<MapField<K, V>>, WithHelperMixin<MapField<K, V>>,
WithLabelMixin<MapField<K, V>>, WithCollectionValueComponentProviderMixin<Map.Entry<K, V>, MapField<K, V>>,
WithCollectionElementFilterMixin<Map.Entry<K, V>, MapField<K, V>> {
WithCollectionElementFilterMixin<Map.Entry<K, V>, MapField<K, V>>,
WithLabelPositionableMixin<MapField<K, V>> {

/**
* Produces a non-null entry filter (entry, its key and its value must be non-{@code null}).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.shared.Registration;
import org.vaadin.miki.events.text.TextSelectionListener;
Expand All @@ -19,6 +20,7 @@
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithLocaleMixin;
import org.vaadin.miki.markers.WithPlaceholderMixin;
import org.vaadin.miki.markers.WithLabelPositionableMixin;
import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin;
import org.vaadin.miki.markers.WithRequiredMixin;
import org.vaadin.miki.markers.WithTitleMixin;
Expand All @@ -39,10 +41,11 @@
*/
@JsModule("./super-date-picker.js")
@Tag("super-date-picker")
@CssImport(value = "./styles/label-positions.css", themeFor = "super-date-picker")
@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes
public class SuperDatePicker extends DatePicker
implements CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin<SuperDatePicker>,
TextSelectionNotifier<SuperDatePicker>, HasSuperDatePickerI18N,
TextSelectionNotifier<SuperDatePicker>, HasSuperDatePickerI18N, WithLabelPositionableMixin<SuperDatePicker>,
WithLocaleMixin<SuperDatePicker>, WithLabelMixin<SuperDatePicker>, WithTitleMixin<SuperDatePicker>,
WithPlaceholderMixin<SuperDatePicker>, WithDatePatternMixin<SuperDatePicker>,
WithValueMixin<AbstractField.ComponentValueChangeEvent<DatePicker, LocalDate>, LocalDate, SuperDatePicker>,
Expand Down
Loading

0 comments on commit 493e252

Please sign in to comment.