Skip to content

Commit 568c574

Browse files
author
Felipe Lang
committed
feat: show overflow button when component is too narrow
Close #5
1 parent 8564c7a commit 568c574

File tree

6 files changed

+388
-54
lines changed

6 files changed

+388
-54
lines changed

src/main/java/com/flowingcode/vaadin/addons/dayofweekselector/DayOfWeekSelector.java

Lines changed: 97 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,43 @@
1919
*/
2020
package com.flowingcode.vaadin.addons.dayofweekselector;
2121

22+
import com.vaadin.flow.component.ClientCallable;
23+
import com.vaadin.flow.component.Component;
24+
import com.vaadin.flow.component.Tag;
2225
import com.vaadin.flow.component.button.Button;
2326
import com.vaadin.flow.component.button.ButtonVariant;
2427
import com.vaadin.flow.component.customfield.CustomField;
2528
import com.vaadin.flow.component.datepicker.DatePicker.DatePickerI18n;
2629
import com.vaadin.flow.component.dependency.CssImport;
27-
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
30+
import com.vaadin.flow.component.dependency.JsModule;
31+
import com.vaadin.flow.dom.Element;
32+
2833
import java.time.DayOfWeek;
34+
import java.util.ArrayList;
2935
import java.util.Arrays;
3036
import java.util.Comparator;
3137
import java.util.EnumSet;
3238
import java.util.List;
3339
import java.util.Objects;
3440
import java.util.Set;
3541
import java.util.stream.Collectors;
36-
import java.util.stream.Stream;
3742

3843
/**
3944
* Shows the days of the week so they can be selected.
4045
*/
4146
@SuppressWarnings("serial")
4247
@CssImport("./styles/fc-days-of-week-selector-styles.css")
48+
@JsModule("./src/fc-days-of-week-selector.ts")
49+
@Tag("fc-days-of-week-selector")
4350
public class DayOfWeekSelector extends CustomField<Set<DayOfWeek>> {
4451

52+
public static final class CssProperties {
53+
public static final String OVERFLOW_ICON_SIZE = "--fc-days-of-week-selector-overflow-icon-size";
54+
55+
private CssProperties() {
56+
}
57+
}
58+
4559
private static class DayOfWeekButton extends Button {
4660
private static final String CLASS_NAME = "fc-days-of-week-selector-button";
4761

@@ -59,6 +73,7 @@ public DayOfWeek getDayOfWeek() {
5973
return dayOfWeek;
6074
}
6175

76+
@ClientCallable
6277
private void toggleState() {
6378
setState(!state);
6479
}
@@ -74,29 +89,13 @@ private void setState(boolean state) {
7489

7590
}
7691

77-
private HorizontalLayout buttonsLayout;
92+
private List<DayOfWeekButton> dayButtons = new ArrayList<>();
7893

7994
/**
8095
* Creates a new instance of {@code DayOfWeekSelector}.
8196
*/
8297
public DayOfWeekSelector() {
83-
getStyle().set("padding", "var(--lumo-space-m)");
84-
this.setWidthFull();
85-
86-
buttonsLayout = new HorizontalLayout();
87-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.SUNDAY, "S"));
88-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.MONDAY, "M"));
89-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.TUESDAY, "T"));
90-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.WEDNESDAY, "W"));
91-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.THURSDAY, "T"));
92-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.FRIDAY, "F"));
93-
buttonsLayout.add(new DayOfWeekButton(DayOfWeek.SATURDAY, "S"));
94-
95-
buttonsLayout.setClassName("fc-days-of-week-selector-buttons-layout");
96-
97-
getButtons().forEach(button -> button.addClickListener(ev -> updateValue()));
98-
add(buttonsLayout);
99-
clear();
98+
initDefaultDayButtons();
10099
}
101100

102101
/**
@@ -142,32 +141,35 @@ protected boolean valueEquals(Set<DayOfWeek> value1, Set<DayOfWeek> value2) {
142141
return value1 != value2 && Objects.equals(value1, value2);
143142
}
144143

145-
private Stream<DayOfWeekButton> getButtons() {
146-
return buttonsLayout.getChildren()
147-
.filter(DayOfWeekButton.class::isInstance)
148-
.map(DayOfWeekButton.class::cast);
149-
}
150-
151144
@Override
152145
protected Set<DayOfWeek> generateModelValue() {
153-
return getButtons().filter(DayOfWeekButton::getState).map(DayOfWeekButton::getDayOfWeek)
154-
.collect(Collectors.toCollection(this::getEmptyValue));
146+
return dayButtons.stream().filter(DayOfWeekButton::getState).map(DayOfWeekButton::getDayOfWeek)
147+
.collect(Collectors.toCollection(this::getEmptyValue));
155148
}
156149

157150
@Override
158151
protected void setPresentationValue(Set<DayOfWeek> newPresentationValue) {
159-
getButtons()
160-
.forEach(button -> button.setState(newPresentationValue.contains(button.getDayOfWeek())));
152+
dayButtons
153+
.forEach(button -> button.setState(newPresentationValue.contains(button.getDayOfWeek())));
161154
}
162155

163156
@Override
164157
public void setReadOnly(boolean readOnly) {
165158
getElement().setProperty("readonly", readOnly);
166159
getElement().setAttribute("readonly", readOnly);
167-
getButtons().forEach(button -> button.setEnabled(!readOnly));
160+
dayButtons.forEach(button -> {
161+
button.setEnabled(!readOnly);
162+
if (readOnly) {
163+
button.addClassName("readOnly");
164+
} else {
165+
button.removeClassName("readOnly");
166+
}
167+
});
168168
}
169169

170-
/** Sets the value of this object. */
170+
/**
171+
* Sets the value of this object.
172+
*/
171173
public void setValue(DayOfWeek first, DayOfWeek... rest) {
172174
setValue(EnumSet.of(first, rest));
173175
}
@@ -202,14 +204,14 @@ public void setWeekDaysShort(List<String> weekdaysShort) {
202204
for (DayOfWeek day : DayOfWeek.values()) {
203205
int index = day.getValue() % 7;
204206
String text = weekdaysShort.get(index);
205-
getButtons().filter(button -> button.getDayOfWeek() == day)
206-
.forEach(button -> button.setText(text));
207+
dayButtons.stream().filter(button -> button.getDayOfWeek() == day)
208+
.forEach(button -> button.setText(text));
207209
}
208210
}
209211

210212
/**
211213
* Sets the tooltips of the week days, starting from {@code sun} and ending on {@code sat}.
212-
*
214+
*
213215
* @param weekdaysTooltip the tooltips of the week days
214216
*/
215217
public void setWeekDaysTooltip(List<String> weekdaysTooltip) {
@@ -218,8 +220,8 @@ public void setWeekDaysTooltip(List<String> weekdaysTooltip) {
218220
for (DayOfWeek day : DayOfWeek.values()) {
219221
int index = day.getValue() % 7;
220222
String text = weekdaysTooltip.get(index);
221-
getButtons().filter(button -> button.getDayOfWeek() == day)
222-
.forEach(button -> button.setTooltipText(text));
223+
dayButtons.stream().filter(button -> button.getDayOfWeek() == day)
224+
.forEach(button -> button.setTooltipText(text));
223225
}
224226
}
225227

@@ -233,14 +235,68 @@ public void setWeekDaysTooltip(List<String> weekdaysTooltip) {
233235
* @throws IllegalArgumentException if firstDayOfWeek is invalid
234236
*/
235237
public void setFirstDayOfWeek(DayOfWeek first) {
236-
DayOfWeekButton[] buttons = getButtons().toArray(DayOfWeekButton[]::new);
238+
DayOfWeekButton[] buttons = dayButtons.toArray(DayOfWeekButton[]::new);
237239
if (buttons[0].dayOfWeek != first) {
240+
var sortedButtons = new ArrayList<DayOfWeekButton>();
238241
Arrays.sort(buttons, Comparator.comparing(DayOfWeekButton::getDayOfWeek));
239-
buttonsLayout.removeAll();
240-
for (int i = 0; i < 7; i++) {
241-
buttonsLayout.add(buttons[(i + first.getValue() - 1) % 7]);
242+
for (int i = 0; i < buttons.length; i++) {
243+
sortedButtons.add(buttons[(i + first.getValue() - 1) % buttons.length]);
242244
}
245+
setDayButtons(sortedButtons);
243246
}
244247
}
245248

249+
/**
250+
* Sets the icon for the overflow menu trigger.
251+
*
252+
* @param icon the icon component, not {@code null}
253+
* @throws NullPointerException if {@code icon} is {@code null}
254+
*/
255+
public void setOverflowIcon(Component icon) {
256+
Objects.requireNonNull(icon, "icon cannot be null");
257+
258+
// Remove any existing slotted icon before appending the new one
259+
getElement().getChildren()
260+
.filter(el -> "overflowIcon".equals(el.getAttribute("slot")))
261+
.findFirst()
262+
.ifPresent(Element::removeFromParent);
263+
264+
icon.setClassName("overflow-icon");
265+
// Assign icon to the slot
266+
icon.getElement().setAttribute("slot", "overflowIcon");
267+
getElement().appendChild(icon.getElement());
268+
}
269+
270+
private void initDefaultDayButtons() {
271+
setDayButtons(List.of(new DayOfWeekButton(DayOfWeek.SUNDAY, "S"),
272+
new DayOfWeekButton(DayOfWeek.MONDAY, "M"),
273+
new DayOfWeekButton(DayOfWeek.TUESDAY, "T"),
274+
new DayOfWeekButton(DayOfWeek.WEDNESDAY, "W"),
275+
new DayOfWeekButton(DayOfWeek.THURSDAY, "T"),
276+
new DayOfWeekButton(DayOfWeek.FRIDAY, "F"),
277+
new DayOfWeekButton(DayOfWeek.SATURDAY, "S")
278+
));
279+
}
280+
281+
private void setDayButtons(List<DayOfWeekButton> buttons) {
282+
this.clearDayButtons();
283+
this.dayButtons = buttons;
284+
buttons.forEach(button -> button.addClickListener(ev -> updateValue()));
285+
this.addDayButtons();
286+
}
287+
288+
private void addDayButtons() {
289+
this.dayButtons.forEach(button -> {
290+
button.getElement().setAttribute("slot", "daysOfWeek");
291+
this.getElement().appendChild(button.getElement());
292+
});
293+
}
294+
295+
private void clearDayButtons() {
296+
this.dayButtons.forEach(button -> {
297+
button.getElement().removeAttribute("slot");
298+
button.removeFromParent();
299+
});
300+
}
301+
246302
}

src/main/resources/META-INF/frontend/styles/fc-days-of-week-selector-styles.css

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ vaadin-button.fc-days-of-week-selector-button[theme~='primary'][disabled]::part(
3535
opacity: 1;
3636
}
3737

38-
vaadin-custom-field[readonly] vaadin-button.fc-days-of-week-selector-button[disabled] {
38+
vaadin-button.fc-days-of-week-selector-button[disabled].readOnly{
3939
color: var(--lumo-secondary-text-color);
4040
background: transparent;
4141
}
4242

43-
vaadin-custom-field[readonly] vaadin-button.fc-days-of-week-selector-button[theme~='primary'][disabled] {
43+
vaadin-button.fc-days-of-week-selector-button[theme~='primary'][disabled].readOnly {
4444
border: var(--vaadin-input-field-readonly-border, 1px dashed var(--lumo-contrast-30pct));
4545
}
4646

@@ -50,3 +50,7 @@ vaadin-horizontal-layout.fc-days-of-week-selector-buttons-layout {
5050
flex-wrap: wrap;
5151
padding: 0 10px;
5252
}
53+
54+
vaadin-context-menu-overlay vaadin-context-menu-list-box::part(items) {
55+
padding: 0 var(--lumo-space-xs);
56+
}

0 commit comments

Comments
 (0)