1919 */
2020package 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 ;
2225import com .vaadin .flow .component .button .Button ;
2326import com .vaadin .flow .component .button .ButtonVariant ;
2427import com .vaadin .flow .component .customfield .CustomField ;
2528import com .vaadin .flow .component .datepicker .DatePicker .DatePickerI18n ;
2629import 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+
2833import java .time .DayOfWeek ;
34+ import java .util .ArrayList ;
2935import java .util .Arrays ;
3036import java .util .Comparator ;
3137import java .util .EnumSet ;
3238import java .util .List ;
3339import java .util .Objects ;
3440import java .util .Set ;
3541import 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" )
4350public 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}
0 commit comments