From 38b3fda0acbc769fc75df514de0b5bab75576c80 Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Mon, 31 Aug 2026 14:36:50 -0300 Subject: [PATCH 1/2] docs: document the empty state of the no-argument constructor Close #3 --- README.md | 21 +++++++++++++++++++ SPECIFICATIONS.md | 7 ++++--- .../addons/relativetime/RelativeTime.java | 15 ++++++++++++- .../addons/relativetime/UseCasesDemo.java | 6 ++++-- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b9b6d9c..6174554 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,27 @@ The relative string is computed and updated in the browser by the underlying web For continuously-ticking elapsed displays use `Format.DURATION` or `Format.MICRO`. `Format.RELATIVE` (the default) collapses past times under a minute to "now". See [SPECIFICATIONS.md](SPECIFICATIONS.md) §2.8 for the full live-update behaviour matrix. +### Components without a value yet + +`new RelativeTime()` writes no `datetime` attribute, so **it renders nothing** until `setDateTime` is called. This is intentional, not a failure: there is deliberately no default value, because defaulting to the current instant would display a time that is not the intended one, and would keep ticking away from it until the real value arrived. + +Use the no-argument constructor when the value is not available at construction time. For an instance-reusing grid renderer: + +```java +grid.addColumn(new ComponentRenderer<>(RelativeTime::new, + (rt, task) -> rt.setDateTime(task.getCreated()))); +``` + +For a display that starts empty and is filled in from a listener: + +```java +RelativeTime preview = new RelativeTime().setFormatStyle(FormatStyle.LONG); +picker.addValueChangeListener(e -> preview.setDateTime(e.getValue())); +add(preview); +``` + +Call `clear()` to return the component to the empty state. + ## Special configuration when using Spring By default, Vaadin Flow only includes `com/vaadin/flow/component` to be always scanned for UI components and views. For this reason, the add-on might need to be allowed in order to display correctly. diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 014a5ca..9303e2b 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -119,7 +119,8 @@ The cadence depends on the displayed unit: ### 3.1 Construction ```java -// Empty: datetime can be set later +// No datetime: renders nothing until setDateTime is called. Intended for component +// renderers, asynchronously loaded values, and displays that start empty. RelativeTime rt = new RelativeTime(); add(rt); @@ -133,7 +134,7 @@ add(new RelativeTime(LocalDate.of(2025, 1, 1))); ```java public class RelativeTime extends Component { // HasStyle inherited from Component - public RelativeTime(); // empty; datetime can be set later + public RelativeTime(); // no datetime; renders nothing until set public RelativeTime(Instant datetime); public RelativeTime(OffsetDateTime datetime); public RelativeTime(ZonedDateTime datetime); @@ -199,7 +200,7 @@ When no configuration is applied: - `time-zone` is unset, so absolute-date output uses the viewer's browser default zone. - The `title` attribute is set automatically to the absolute formatted date and is surfaced as a native tooltip. - The element auto-updates on its own timer; no polling code is needed on the Java side. -- `RelativeTime` with no `datetime` set renders as an empty inline element. +- `RelativeTime` with no `datetime` set renders as an empty inline element. There is deliberately no default value: defaulting to the current instant would display a time other than the intended one and keep ticking away from it. See §3.1. ## 5. Theming diff --git a/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java b/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java index c990a3f..f6664b1 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java +++ b/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java @@ -49,6 +49,11 @@ * the server's. There is no server-side API to read the displayed string; the string lives only * in the DOM. * + *

Empty state. A component with no target datetime renders nothing at all: the + * underlying element has no text to show. This is the documented behaviour of the + * {@linkplain #RelativeTime() no-argument constructor} and of {@link #clear()}, not a failure; see + * that constructor for when an empty component is the right starting point. + * *

Attributes, not properties. Setters write HTML attributes * ({@code setAttribute}), not DOM properties, because the upstream element is * attribute-driven and its kebab-case attribute names match the upstream docs @@ -94,7 +99,15 @@ public class RelativeTime extends Component { private Instant lastDateTime; - /** Creates an empty component. {@link #setDateTime} can be called later. */ + /** + * Creates a component with no target datetime: nothing is rendered until {@link #setDateTime} is + * called. Use it when the value is not available at construction time, such as in component + * renderers ({@code new ComponentRenderer<>(RelativeTime::new, (rt, item) -> ...)}), + * asynchronously loaded data, or displays that start empty and are reset with {@link #clear()}. + * + *

No default is applied on purpose: defaulting to the current instant would display a time + * other than the intended one, and would keep ticking away from it. + */ public RelativeTime() {} /** Creates a component bound to the given instant. */ diff --git a/src/test/java/com/flowingcode/vaadin/addons/relativetime/UseCasesDemo.java b/src/test/java/com/flowingcode/vaadin/addons/relativetime/UseCasesDemo.java index 141c281..1623dc9 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/relativetime/UseCasesDemo.java +++ b/src/test/java/com/flowingcode/vaadin/addons/relativetime/UseCasesDemo.java @@ -96,8 +96,10 @@ public UseCasesDemo() { addUseCase(layout, "stopwatch", "Live stopwatch", buildStopwatch(), "A running counter using Format.DURATION (ticks every second from 0s with no \"now\"" - + " plateau). The Start button pins the datetime to now; Stop clears it. Pattern:" - + " timers for in-progress work, build/deploy status, \"uptime since\" indicators."); + + " plateau). Built with the no-argument constructor, so it renders nothing until" + + " Start pins the datetime to now; Stop clears it and it goes back to empty." + + " Pattern: timers for in-progress work, build/deploy status, \"uptime since\"" + + " indicators."); addUseCase(layout, "session-expiry", "Session expiry warning", buildSessionWarning(), From 39e029bd1ee9183c3a4925d8c4ce469d2eb8978a Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Tue, 1 Sep 2026 10:02:02 -0300 Subject: [PATCH 2/2] WIP: apply review feedback on empty-state wording --- README.md | 2 +- SPECIFICATIONS.md | 2 +- .../addons/relativetime/RelativeTime.java | 21 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6174554..fe9660d 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ For continuously-ticking elapsed displays use `Format.DURATION` or `Format.MICRO ### Components without a value yet -`new RelativeTime()` writes no `datetime` attribute, so **it renders nothing** until `setDateTime` is called. This is intentional, not a failure: there is deliberately no default value, because defaulting to the current instant would display a time that is not the intended one, and would keep ticking away from it until the real value arrived. +`new RelativeTime()` writes no `datetime` attribute and renders nothing until `setDateTime` is called. No default is applied: the current instant would be a value the caller did not choose, and it would keep ticking away from the intended one until that value arrives. Use the no-argument constructor when the value is not available at construction time. For an instance-reusing grid renderer: diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 9303e2b..8749a67 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -200,7 +200,7 @@ When no configuration is applied: - `time-zone` is unset, so absolute-date output uses the viewer's browser default zone. - The `title` attribute is set automatically to the absolute formatted date and is surfaced as a native tooltip. - The element auto-updates on its own timer; no polling code is needed on the Java side. -- `RelativeTime` with no `datetime` set renders as an empty inline element. There is deliberately no default value: defaulting to the current instant would display a time other than the intended one and keep ticking away from it. See §3.1. +- `RelativeTime` with no `datetime` set renders as an empty inline element. No default datetime is applied; see §3.1. ## 5. Theming diff --git a/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java b/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java index f6664b1..2a0dc9a 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java +++ b/src/main/java/com/flowingcode/vaadin/addons/relativetime/RelativeTime.java @@ -49,10 +49,9 @@ * the server's. There is no server-side API to read the displayed string; the string lives only * in the DOM. * - *

Empty state. A component with no target datetime renders nothing at all: the - * underlying element has no text to show. This is the documented behaviour of the - * {@linkplain #RelativeTime() no-argument constructor} and of {@link #clear()}, not a failure; see - * that constructor for when an empty component is the right starting point. + *

Empty state. A component with no target datetime renders nothing: the underlying + * element has no text to show. This applies to the {@linkplain #RelativeTime() no-argument + * constructor} and to {@link #clear()}. See the constructor for the cases it serves. * *

Attributes, not properties. Setters write HTML attributes * ({@code setAttribute}), not DOM properties, because the upstream element is @@ -100,13 +99,15 @@ public class RelativeTime extends Component { private Instant lastDateTime; /** - * Creates a component with no target datetime: nothing is rendered until {@link #setDateTime} is - * called. Use it when the value is not available at construction time, such as in component - * renderers ({@code new ComponentRenderer<>(RelativeTime::new, (rt, item) -> ...)}), - * asynchronously loaded data, or displays that start empty and are reset with {@link #clear()}. + * Creates a relative time component without a target datetime. Renders nothing until + * {@link #setDateTime} is called. * - *

No default is applied on purpose: defaulting to the current instant would display a time - * other than the intended one, and would keep ticking away from it. + *

Use this constructor when the datetime is unavailable at creation, such as in component + * renderers ({@code new ComponentRenderer<>(RelativeTime::new, ...)}), asynchronous data + * loading, or displays reset via {@link #clear()}. + * + *

No default datetime is applied. The current instant would be a value the caller did not + * choose, and it would keep ticking away from the intended one until that value arrives. */ public RelativeTime() {}