Skip to content
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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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:

```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.
Expand Down
7 changes: 4 additions & 3 deletions SPECIFICATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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. No default datetime is applied; see §3.1.

## 5. Theming

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
* the server's. There is no server-side API to read the displayed string; the string lives only
* in the DOM.
*
* <p><b>Empty state.</b> 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.
*
* <p><b>Attributes, not properties.</b> 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
Expand Down Expand Up @@ -94,7 +98,17 @@ public class RelativeTime extends Component {

private Instant lastDateTime;

/** Creates an empty component. {@link #setDateTime} can be called later. */
/**
* Creates a relative time component without a target datetime. Renders nothing until
* {@link #setDateTime} is called.
*
* <p>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()}.
*
* <p>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.
*/
Comment on lines +101 to +111

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* 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()}.
*
* <p>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.
*/
/**
* Creates a relative time component without a target datetime. Renders nothing until
* {@link #setDateTime} is called.
*
* <p>Use this constructor when the datetime is unavailable at creation, such as in
* component renderers ({@code new ComponentRenderer<>(RelativeTime::new, ...)}),
* asynchronous data loading, or views reset via {@link #clear()}.
*/

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, with one addition. I kept a short paragraph on why there is no default, because that rationale is what issue #3 was about, and without it in the code the question comes back the next time someone reads the constructor. Reworded in the direct voice:

"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."

Also changed "views reset via clear()" to "displays", since clear() resets the component, not a view.

public RelativeTime() {}

/** Creates a component bound to the given instant. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Loading