@espressif/dashboard-ui-components 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,93 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres
5
5
  to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [1.5.0] - 2026-09-22
8
+
9
+ A minor release adding a combined date and time control.
10
+
11
+ ### Added
12
+ - **`DateTimePicker`** — one read-only input that opens a dropdown with a
13
+ `Calendar` and a `TimePicker`, together editing one `Date`. Picking a day
14
+ keeps the dropdown open so the time can be set in the same interaction; a
15
+ time typed before a day is kept and applied to the chosen day; an incomplete
16
+ time (the browser reports `""` mid-edit) never snaps the value. `defaultTime`
17
+ sets the time of day used when a day is picked first (default `"00:00"`),
18
+ `timeStep` below 60 shows seconds, `clearable` shows an X inside the input
19
+ that clears both parts without changing the layout. Carries the usual
20
+ `label` / `required` / `error` / `errorContent` / `hintContent` / `size` /
21
+ `rounded` / `disabled` / `open` / `onOpenChange` props and an optional
22
+ hidden `name` input with the ISO string, like `DatePicker`. Values are local
23
+ wall-clock `Date`s; callers convert to UTC or epoch seconds.
24
+ - **`SelectTrigger`** — `label`, `required`, `hintContent`, `error` and
25
+ `errorContent`, the same field chrome `Input` has: a label row above the
26
+ trigger (label, required marker, right-aligned hint) and an error line
27
+ below it, with `aria-required` / `aria-invalid` / `aria-describedby` wired.
28
+ With none of them set the trigger renders exactly as before, so existing
29
+ `FormLabel` + `Select` compositions are unaffected.
30
+ - **`SectionCard`** — `open` for a controlled collapsible state, paired with
31
+ the existing `onOpenChange`. Lets an action in the header (an "Edit"
32
+ button, for instance) expand the card. Omit it and the card keeps its
33
+ `defaultOpen`-seeded internal state exactly as before. `hideCollapseIcon`
34
+ drops the chevron from the header's right column while the header row
35
+ itself stays a labelled toggle, for cards whose action button already
36
+ says the card can be expanded.
37
+ - **`Illustration`** — `animated` (default `false`). Off, the component
38
+ renders an illustration's static resting frame and strips every SMIL
39
+ element from the markup, so pages that only need a picture get exactly
40
+ that. On, the animation plays. Sources mark parts that exist in only one
41
+ variant with `data-variant="static"` / `data-variant="animated"` groups.
42
+ Illustrations without animations render identically either way.
43
+ - **`DatePicker`** — `clearable` and `clearLabel`. When `clearable` is set
44
+ and a date is selected, a 16px X appears inside the trigger next to the
45
+ calendar icon (the same end slot `DateTimePicker` uses) and calls
46
+ `onChange(undefined)` without opening the calendar. Off by default, so existing pickers are unchanged
47
+ (previously the only way to clear was re-clicking the selected day).
48
+
49
+ ### Changed
50
+ - **`Illustration`** — `rm-data-download` redrawn: the RainMaker logo cloud
51
+ rains data, records travel along a dashed connector into a laptop, and rows
52
+ of the on-screen table light up as they land while the download progress
53
+ fills. Colours come from the theme tokens except the cloud, which keeps the
54
+ logo's own reds. Ids are prefixed `rmdd-` so the inlined markup cannot
55
+ collide with other inline SVGs on the page. The source carries both a
56
+ static resting frame and the SMIL animation; see `animated` below.
57
+ - **`OverflowBadgeList`** — each item is now a `StatusBadge` instead of a
58
+ hand-styled `Badge`, so the pills match status chips elsewhere (rounded,
59
+ `StatusBadge` paddings, 14/16/18px icon). New `badgeSize` (`"sm" |
60
+ "default" | "lg"`, default `"default"`); `badgeVariant` still defaults to
61
+ `"outline"`. Long labels still truncate at 12rem.
62
+ - **`StatusBadge`** — the label is wrapped in a `min-w-0 truncate` span, so a
63
+ `className` with a `max-w-*` now ellipsises instead of overflowing.
64
+ - **`SelectTrigger`** — the chevron is now 16px at every `size` (it scaled
65
+ 14/16/20px before), matching the fixed 16px decorators inside `Input`, so a
66
+ Select and an Input placed side by side show the same icon dimensions.
67
+
68
+ ### Fixed
69
+ - **`Dialog`, `Sheet`, `DropdownMenu`, `Checkbox`, `Switch`, `Toggle`,
70
+ `ToggleGroup`, `Accordion`, `RadioGroup`, `PreviewCard`, `CopyButton`,
71
+ `NavBar`** — controlled mode is now genuinely controlled. The shared
72
+ `useControlledState` hook used to write its internal state on every
73
+ change and only then call `onChange`, so a component whose owner kept
74
+ `open`/`checked`/`value` unchanged still flipped on its own. A
75
+ `FullscreenDialog` with `open={true}` closed on the X button even when
76
+ its `onOpenChange` handler decided not to close (for example while a
77
+ navigation guard asked for confirmation), leaving an empty page. With
78
+ `value` defined the hook now reports that value and the setter only
79
+ notifies `onChange`; uncontrolled usage is unchanged.
80
+ - **`DatePicker`** — a controlled picker whose `value` is set back to
81
+ `undefined` no longer flips to uncontrolled mode and shows a stale day; the
82
+ component now treats the presence of the `value` prop as "controlled".
83
+ - **Field label geometry** — a `FormLabel` stacked above a control and an
84
+ `Input`'s own label row used to leave different gaps between label text and
85
+ control: `FormLabel` was an inline `<label>` sitting on a taller anonymous
86
+ line box, and the `Input` row grew from 14px to 20px whenever a hint was
87
+ present because the hint kept the default line-height. Both now render the
88
+ same 14px block-level row (`flex items-center gap-2 leading-none`; hints
89
+ are `leading-none`), so labels sit exactly 8px above every control. The
90
+ required marker also gets the same `gap-2` spacing in both.
91
+ - **`DatePicker`** — the calendar's square background no longer pokes past
92
+ the rounded corners of its dropdown; the popover now clips its content.
93
+
7
94
  ## [1.4.0] - 2026-09-18
8
95
 
9
96
  A minor release that lets `ConfirmationDialog` be opened without a trigger, and
@@ -1,4 +1,4 @@
1
- import { Avatar, Menu, List, Button, Link } from './chunk-UHRNPXO5.js';
1
+ import { Avatar, Menu, List, Button, Link } from './chunk-ZEQNTNMW.js';
2
2
  import { cn } from './chunk-VU4CZ76T.js';
3
3
  import { motion, AnimatePresence } from 'framer-motion';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,6 +1,6 @@
1
- import { FooterCard, MyAccountMenu, ProfileCard, AppLogo } from './chunk-TSNA6BHK.js';
2
- import { useSidebar, SidebarTrigger, SidebarProvider, Sidebar2, SidebarInset, parseTextMarkup, isPathPrefixOf, isSidebarGroup } from './chunk-UHRNPXO5.js';
3
- import { Button, Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator } from './chunk-7BO76CNB.js';
1
+ import { FooterCard, MyAccountMenu, ProfileCard, AppLogo } from './chunk-45DCL46L.js';
2
+ import { useSidebar, SidebarTrigger, SidebarProvider, Sidebar2, SidebarInset, parseTextMarkup, isPathPrefixOf, isSidebarGroup } from './chunk-ZEQNTNMW.js';
3
+ import { Button, Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator } from './chunk-OKB2WTX7.js';
4
4
  import { cn } from './chunk-VU4CZ76T.js';
5
5
  import { Menu, Palette, Check, Globe, LogOut } from 'lucide-react';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Separator } from './chunk-7BO76CNB.js';
1
+ import { Separator } from './chunk-OKB2WTX7.js';
2
2
  import { cn, isPresetColor, resolveColor } from './chunk-VU4CZ76T.js';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import * as React from 'react';
@@ -10,20 +10,21 @@ import { ChevronRight, MoreHorizontal } from 'lucide-react';
10
10
 
11
11
  function useControlledState(props) {
12
12
  const { value, defaultValue, onChange } = props;
13
- const [state, setInternalState] = React9.useState(
14
- value !== void 0 ? value : defaultValue
13
+ const isControlled = value !== void 0;
14
+ const [internalState, setInternalState] = React9.useState(
15
+ isControlled ? value : defaultValue
15
16
  );
16
17
  React9.useEffect(() => {
17
- if (value !== void 0) setInternalState(value);
18
- }, [value]);
18
+ if (isControlled) setInternalState(value);
19
+ }, [isControlled, value]);
19
20
  const setState = React9.useCallback(
20
21
  (next, ...args) => {
21
- setInternalState(next);
22
+ if (!isControlled) setInternalState(next);
22
23
  onChange?.(next, ...args);
23
24
  },
24
- [onChange]
25
+ [isControlled, onChange]
25
26
  );
26
- return [state, setState];
27
+ return [isControlled ? value : internalState, setState];
27
28
  }
28
29
  function getStrictContext(name) {
29
30
  const Context = React9.createContext(void 0);
@@ -1,6 +1,6 @@
1
- import { ProgressBar } from './chunk-XMEZ2BP6.js';
2
- import { Card, CardContent } from './chunk-KCMVLNM5.js';
3
- import { Tooltip2 } from './chunk-UHRNPXO5.js';
1
+ import { ProgressBar } from './chunk-X7LDLZBT.js';
2
+ import { Card, CardContent } from './chunk-ABBHGIFI.js';
3
+ import { Tooltip2 } from './chunk-ZEQNTNMW.js';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
5
 
6
6
  function CopyrightCard({