Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MapField, LabelField and VariantField #362

Merged
merged 8 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,586 changes: 1,464 additions & 5,122 deletions demo-v23/package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions demo-v23/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,10 @@
"@vaadin/vaadin-crud": "$@vaadin/vaadin-crud",
"@vaadin/vaadin-grid-pro": "$@vaadin/vaadin-grid-pro",
"@vaadin/vaadin-rich-text-editor": "$@vaadin/vaadin-rich-text-editor",
"@polymer/polymer": "$@polymer/polymer",
"construct-style-sheets-polyfill": "$construct-style-sheets-polyfill",
"@vaadin/common-frontend": "$@vaadin/common-frontend",
"construct-style-sheets-polyfill": "$construct-style-sheets-polyfill",
"lit": "$lit",
"@polymer/polymer": "$@polymer/polymer",
"chokidar": "$chokidar",
"date-fns": "$date-fns"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* @since 2021-09-10
*/
@Order(5)
public class HasCollectionValueComponentProviderBuilder implements ContentBuilder<CollectionField<String, List<String>>> {
public class CollectionFieldBuilder implements ContentBuilder<CollectionField<String, List<String>>> {

@Override
public void buildContent(CollectionField<String, List<String>> component, Consumer<Component[]> callback) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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.superfields.collections.CollectionValueComponentProvider;
import org.vaadin.miki.superfields.collections.MapEntryField;
import org.vaadin.miki.superfields.collections.MapField;
import org.vaadin.miki.superfields.numbers.SuperIntegerField;
import org.vaadin.miki.superfields.text.SuperTextField;
import org.vaadin.miki.superfields.util.CollectionComponentProviders;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;

/**
* Builds content for {@link MapField}.
*
* @author miki
* @since 2022-04-12
*/
@Order(5)
public class MapFieldBuilder implements ContentBuilder<MapField<String, Integer>> {
@Override
public void buildContent(MapField<String, Integer> component, Consumer<Component[]> callback) {
final Map<CollectionValueComponentProvider<Map.Entry<String, Integer>, ?>, String> providersWithCaptions = new LinkedHashMap<>();

final CollectionValueComponentProvider<Map.Entry<String, Integer>, MapEntryField<String, Integer>> fieldsOnly = CollectionComponentProviders.mapEntryField(SuperTextField::new, SuperIntegerField::new);
providersWithCaptions.put(fieldsOnly, "Unlabelled text and integer fields");
providersWithCaptions.put(CollectionComponentProviders.rowWithRemoveButtonFirst(
CollectionComponentProviders.mapEntryField("Key", SuperTextField::new, "Value", SuperIntegerField::new)
, "Remove"
), "Remove button and labelled text and integer fields");

// configure the combo box
final ComboBox<CollectionValueComponentProvider<Map.Entry<String, Integer>, ?>> box = new ComboBox<>("Choose item layout:", providersWithCaptions.keySet());
box.setItemLabelGenerator(providersWithCaptions::get);
box.addValueChangeListener(event -> component.setCollectionValueComponentProvider(event.getValue()));
box.setAllowCustomValue(false);
box.setValue(fieldsOnly);

callback.accept(new Component[]{box});

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.vaadin.miki.demo.builders;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import org.vaadin.miki.demo.ContentBuilder;
import org.vaadin.miki.demo.Order;
import org.vaadin.miki.superfields.variant.VariantField;

import java.time.LocalDate;
import java.util.function.Consumer;
import java.util.stream.Stream;

/**
* Builds content for {@link VariantField}.
*
* @author miki
* @since 2022-04-11
*/
@Order(80)
public class VariantFieldBuilder implements ContentBuilder<VariantField> {

@Override
public void buildContent(VariantField component, Consumer<Component[]> callback) {
final HorizontalLayout layout = new HorizontalLayout(
Stream.of(new Object[]{"LocalDate", LocalDate.now()},
new Object[]{"number (Integer)", 42},
new Object[]{"String", "Pay no mind to the distant thunder"})
.map(data -> new Button("Set a " + data[0].toString(), event -> component.setValue(data[1])))
.toArray(Component[]::new)
);
layout.add(new Button("Set null (clear value)", event -> component.clear()));
callback.accept(new Component[]{layout});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.vaadin.miki.demo.providers;

import org.vaadin.miki.demo.ComponentProvider;
import org.vaadin.miki.demo.Order;
import org.vaadin.miki.superfields.collections.MapEntryField;
import org.vaadin.miki.superfields.collections.MapField;
import org.vaadin.miki.superfields.numbers.SuperIntegerField;
import org.vaadin.miki.superfields.text.SuperTextField;
import org.vaadin.miki.superfields.util.CollectionComponentProviders;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;

/**
* Provides a {@link MapField}.
* @author miki
* @since 2022-04-08
*/
@Order(147)
public class MapFieldProvider implements ComponentProvider<MapField<String, Integer>> {

@Override
public MapField<String, Integer> getComponent() {
return new MapField<>(LinkedHashMap::new,
CollectionComponentProviders.columnWithHeaderAndFooterRows(
Arrays.asList(
CollectionComponentProviders.removeAllButton("Clear"),
CollectionComponentProviders.addFirstButton("Add as first")
),
Collections.singletonList(CollectionComponentProviders.addLastButton("Add as last"))),
CollectionComponentProviders.rowWithRemoveButtonFirst((i, c) -> new MapEntryField<>(
() -> new SuperTextField("Any text:"), () -> new SuperIntegerField("Any integer:")
), "Remove"))
.withHelperText("(this is a Map<String, Integer>)");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.vaadin.miki.demo.providers;

import com.vaadin.flow.data.binder.ValidationResult;
import com.vaadin.flow.data.binder.Validator;
import com.vaadin.flow.data.binder.ValueContext;
import org.vaadin.miki.demo.ComponentProvider;
import org.vaadin.miki.demo.Order;
import org.vaadin.miki.superfields.dates.SuperDatePicker;
import org.vaadin.miki.superfields.numbers.SuperIntegerField;
import org.vaadin.miki.superfields.text.LabelField;
import org.vaadin.miki.superfields.text.SuperTextField;
import org.vaadin.miki.superfields.variant.TypedFieldProvider;
import org.vaadin.miki.superfields.variant.VariantField;

import java.time.LocalDate;

/**
* Provides a {@link VariantField}.
*
* @author miki
* @since 2022-04-11
*/
@Order(85)
public class VariantFieldProvider implements ComponentProvider<VariantField>, Validator<Object> {

@Override
public ValidationResult apply(Object o, ValueContext valueContext) {
return o != null && o.toString().length() > 5 ? ValidationResult.ok() : ValidationResult.error("(toString() on the value must be longer than 5 characters)");
}

@Override
public VariantField getComponent() {
return new VariantField()
.withTypedFieldProvider(TypedFieldProvider.of(Integer.class, SuperIntegerField::new),
TypedFieldProvider.of(String.class, SuperTextField::new),
TypedFieldProvider.of(LocalDate.class, SuperDatePicker::new))
.withNullComponentProvider(() -> new LabelField<>().withNullRepresentation("(no value specified)"))
.withHelperText("(this is a CustomField<Object>)")
.withLabel("Choose a value type below, then edit it here:");
}
}
1 change: 1 addition & 0 deletions demo-v23/src/main/resources/MapField.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A field that works with any `Map<K, V>` allowing different components for keys and values. Uses a `CollectionField` to produce a `Map` from a list of `Map.Entry`.
1 change: 1 addition & 0 deletions demo-v23/src/main/resources/VariantField.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
An extendable `CustomField<Object>` that displays values in components that match the registered type(s).
51 changes: 21 additions & 30 deletions demo-v23/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,32 @@
/**
* This file contains project specific customizations for the webpack build.
* This file contains project specific customizations for the webpack build.
* It is autogenerated if it didn't exist or if it was made for an older
* incompatible version.
*
* Defaults are provided in an autogenerated webpack.generated.js file and used by this file.
* Defaults are provided in an autogenerated webpack.generated.js file and used by this file.
* The webpack.generated.js file is overwritten on each build and no customization can be done there.
*/
const merge = require('webpack-merge');
const flowDefaults = require('./webpack.generated.js');

module.exports = merge(flowDefaults, {

});

/**
* This file can be used to configure the flow plugin defaults.
* <code>
* // Add a custom plugin
* flowDefaults.plugins.push(new MyPlugin());
*
* // Update the rules to also transpile `.mjs` files
* if (!flowDefaults.module.rules[0].test) {
* throw "Unexpected structure in generated webpack config";
* }
* flowDefaults.module.rules[0].test = /\.m?js$/
*
* // Include a custom JS in the entry point in addition to generated-flow-imports.js
* if (typeof flowDefaults.entry.index != "string") {
* throw "Unexpected structure in generated webpack config";
* }
* flowDefaults.entry.index = [flowDefaults.entry.index, "myCustomFile.js"];
* </code>
* or add new configuration in the merge block.
* <code>
* module.exports = merge(flowDefaults, {
* mode: 'development',
* devtool: 'inline-source-map'
* });
* </code>
* To change the webpack config, add a new configuration object in
* the merge arguments below:
*/
module.exports = merge(flowDefaults,
// Override default configuration
// {
// mode: 'development',
// devtool: 'inline-source-map',
// },

// Add a custom plugin
// (install the plugin with `npm install --save-dev webpack-bundle-analyzer`)
// {
// plugins: [
// new require('webpack-bundle-analyzer').BundleAnalyzerPlugin({
// analyzerMode: 'static'
// })
// ]
// },
);
3 changes: 2 additions & 1 deletion superfields/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# 0.12.0 - Support for Vaadin 23
## New features and enhancements
(nothing reported)
* \#349 - [Support for Vaadin 23](https://github.com/vaadin-miki/super-fields/issues/349)
## Changes to API
* \#345 - [Upgrade to Vaadin 14.8.1](https://github.com/vaadin-miki/super-fields/issues/345)
## Bug fixes
(nothing reported)
# 0.11.2 - HasValueChangeMode
## New features and enhancements
* \#337 - [ValueChangeMode and clear button](https://github.com/vaadin-miki/super-fields/issues/337)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Focusable;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.HasValue;
Expand Down Expand Up @@ -31,7 +32,7 @@
* @param <C> Type of the collection.
*/
public class CollectionField<T, C extends Collection<T>> extends CustomField<C>
implements CollectionController, WithIdMixin<CollectionField<T, 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>> {
Expand Down Expand Up @@ -258,6 +259,13 @@ public final void setCollectionValueComponentProvider(CollectionValueComponentPr
return collectionValueComponentProvider;
}

@Override
public void focus() {
if(!this.fields.isEmpty() && this.fields.get(0) instanceof Focusable<?>)
((Focusable<?>) this.fields.get(0)).focus(); // fixes #360 by forwarding focusing to the first component in the list if available
super.focus();
}

/**
* Gets the component at specified position. No range checking.
* For testing purposes only.
Expand Down
Loading