gridsmith-ui 0.27.0 → 0.28.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/dist/charts.js +2 -2
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +5 -5
  5. package/dist/chat.js.map +1 -1
  6. package/dist/{chunk-64TXZ4L7.js → chunk-2ROVDVLZ.js} +3 -3
  7. package/dist/{chunk-64TXZ4L7.js.map → chunk-2ROVDVLZ.js.map} +1 -1
  8. package/dist/chunk-66JJCQU3.js +46 -0
  9. package/dist/chunk-66JJCQU3.js.map +1 -0
  10. package/dist/chunk-7RKC5C7G.js +35 -0
  11. package/dist/chunk-7RKC5C7G.js.map +1 -0
  12. package/dist/{chunk-OTCEJN64.js → chunk-BRAXJEEP.js} +7 -6
  13. package/dist/chunk-BRAXJEEP.js.map +1 -0
  14. package/dist/{chunk-IXR4UEF4.js → chunk-DQCHCLEJ.js} +9 -8
  15. package/dist/chunk-DQCHCLEJ.js.map +1 -0
  16. package/dist/{chunk-5TUVX4B2.js → chunk-EIWXVICU.js} +3 -3
  17. package/dist/{chunk-5TUVX4B2.js.map → chunk-EIWXVICU.js.map} +1 -1
  18. package/dist/{chunk-SFY2KMHG.js → chunk-FD4YED7O.js} +5 -4
  19. package/dist/chunk-FD4YED7O.js.map +1 -0
  20. package/dist/{chunk-MD2EFMES.js → chunk-GXMTS3YD.js} +3 -3
  21. package/dist/{chunk-MD2EFMES.js.map → chunk-GXMTS3YD.js.map} +1 -1
  22. package/dist/chunk-HTXP5BMM.js +38 -0
  23. package/dist/chunk-HTXP5BMM.js.map +1 -0
  24. package/dist/{chunk-R5NFCEZ3.js → chunk-OPFJEL3Z.js} +52 -24
  25. package/dist/chunk-OPFJEL3Z.js.map +1 -0
  26. package/dist/{chunk-EKBWWA6P.js → chunk-R4GXKH4U.js} +7 -7
  27. package/dist/chunk-R4GXKH4U.js.map +1 -0
  28. package/dist/{chunk-PO65I3MQ.js → chunk-TRDXWHD2.js} +6 -6
  29. package/dist/chunk-TRDXWHD2.js.map +1 -0
  30. package/dist/{chunk-2CKSSWYG.js → chunk-YUTF2X6B.js} +39 -20
  31. package/dist/chunk-YUTF2X6B.js.map +1 -0
  32. package/dist/data-grid.js +18 -11
  33. package/dist/data-grid.js.map +1 -1
  34. package/dist/editor-mentions.js +2 -2
  35. package/dist/editor.js +44 -24
  36. package/dist/editor.js.map +1 -1
  37. package/dist/index.d.ts +39 -2
  38. package/dist/index.js +397 -279
  39. package/dist/index.js.map +1 -1
  40. package/dist/kanban.js +18 -11
  41. package/dist/kanban.js.map +1 -1
  42. package/dist/resizable.js +20 -15
  43. package/dist/resizable.js.map +1 -1
  44. package/dist/roots.css +91 -15
  45. package/dist/tokens.css +111 -26
  46. package/dist/utils.d.ts +47 -5
  47. package/dist/utils.js +15 -5
  48. package/dist/utils.js.map +1 -1
  49. package/dist/virtualized.js +17 -11
  50. package/dist/virtualized.js.map +1 -1
  51. package/dist-static/tokens.css +111 -26
  52. package/package.json +1 -1
  53. package/dist/chunk-2CKSSWYG.js.map +0 -1
  54. package/dist/chunk-EKBWWA6P.js.map +0 -1
  55. package/dist/chunk-IXR4UEF4.js.map +0 -1
  56. package/dist/chunk-M2QRNBDQ.js +0 -42
  57. package/dist/chunk-M2QRNBDQ.js.map +0 -1
  58. package/dist/chunk-OTCEJN64.js.map +0 -1
  59. package/dist/chunk-PO65I3MQ.js.map +0 -1
  60. package/dist/chunk-R5NFCEZ3.js.map +0 -1
  61. package/dist/chunk-SFY2KMHG.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,47 @@
1
1
  # gridsmith-ui changelog
2
2
 
3
- ## Unreleased (0.27.0)
3
+ ## Unreleased (0.28.0)
4
+
5
+ One focus state and readable quiet colours (Sprint 30). Two looks replace the many each component drew: **keyboard focus**, where Tab has landed, is one outline, 2 px with a 2 px gap, in a colour derived to read on the theme's grounds, shown only from the keyboard; **active**, what was clicked or opened (a field clicked into, an open dropdown or picker, a file over a drop zone), is the accent border with a soft halo. Choices keep their selected look, never an outline or a halo. While an element shows the outline its own shadow steps aside. A field shows the outline when Tab reaches it and the active look when clicked into, by a small note of how focus arrived. The quiet colours read: muted and secondary text, the accent as text, the accent's tint's words and each status's words are derived to their WCAG minimum against what they sit on, the theme's own colour wherever it already reaches it. Two tokens are removed (`--ds-shadow-focus`, `--ds-input-focus-ring`), which breaks code that names them, and focus and the quiet colours change in most themes: a 0.x minor release, 0.28.0, says so, and an app pinned to `^0.27.0` doesn't reach it by itself. The upgrade note at the end says what an app on 0.27.0 does.
6
+
7
+ **Keyboard focus: one outline, on everything the keyboard reaches.**
8
+ - **The outline** is 2 px in `--ds-focus`, 2 px outside the element's edge, so the page shows in the gap and one colour reads beside any fill (GOV.UK's single focus style is the cross-check). It shows only from the keyboard (`:focus-visible`): a click on a button shows nothing. Every component draws it with one of the shared styles in `gridsmith-ui/utils`: `FOCUS_RING`, `HAS_FOCUS_RING` (a wrapper, for a control inside it) and `FOCUS_WITHIN_RING` (the same, but a click shows it too: a new wrapper takes `HAS_FOCUS_RING`), `PEER_FOCUS_RING` and `GROUP_FOCUS_RING` (a drawn piece: a checkbox's box, a radio's circle, a separator's grip), and `FOCUS_INSET`, the outline inside the edge. A few draw it from the same classes their own way: the Table's frame, for its scroll area (`HAS_FOCUS_RING`'s parts); a card that holds controls, round the whole card for its action, as a card that is a button draws it; and, from `roots.css`, what the library renders without classes (a chart's surface and each pie, the editor's task checkboxes).
9
+ - **About 70 places that showed the browser's own ring, or nothing,** now show the outline: among them Dialog's and Drawer's Close, the page numbers, the Calendar's toolbar, NotificationCenter's buttons, the sidebar's links and toggles, the crumbs, Alert's and Toast's actions, a clickable StatsCard and Tag, TransferList's checkboxes and filter, a chart's surface (Recharts' keyboard layer) and the editor's task checkboxes.
10
+ - **The element's own shadow steps aside** while the outline shows, so the outline sits on the page with its gap: a button's, a card's, and a segmented control's raised piece behind its selected segment. A hard shadow (neo-brutalist, playful geometric) no longer crowds the outline. A field keeps its inset shadow.
11
+ - **Where it sits.** Outside, with 4 px of room inside a container that clips it: the tab strip, the Navbar's links and a Kanban column take padding with the margin taken back, so nothing moves; TimePicker's columns are 8 px wider; a menu's and a dropdown's panel, the editor's toolbars and TransferList's lists keep at least 4 px at any density. Inside, where an edge-to-edge row or cell meets a container's edge: table rows and cells, DataGrid's cells, the Calendar's day cells, week events and day list (a month's days and an event's attendee list keep their content clear of it), a list's rows flush with a SplitView pane, the full-width items of ContextMenu, the crumbs' menu and BottomNav's overflow menu, and BottomNav's items and the Launcher's ribbon, which sit flush with the window. It sits `--ds-focus-inset` in (new): 5 px, and deeper where the theme's corners are rounder (about 7 px at a 16 px radius), so it always clears a table's rounded corners. On a fill it takes the fill's text colour: on the bold band, on a selected row, on the ribbon. A separator (ResizablePanels' handle, an AsidePanel's edge) draws it round its grip, which shows while it has keyboard focus.
12
+ - **A scroller brings the keyboard's item into view whole.** A browser scrolls a focused element in only when none of it shows, so a list's last option, a card at a board's edge or a row under the fold stayed cut off with its outline. Dropdown's list, the Kanban board and its columns, SplitView's panes, TimePicker's columns, the crumbs' menu, TransferList's lists, the Table's phone cards, DataGrid, ScrollArea (the sidebar's nav), VirtualizedList, ChatMessageList, NotificationCenter and the editor now scroll it in, with 4 px for the outline; the editor's phone toolbar keeps it clear of its edge's fade, and TimeViewport and the Gantt keep it clear of their pinned column and sticky scale. `useRevealFocus(element)` (new, exported) does it for a scroller of an app's own.
13
+ - **The sidebar, the preview header and the bold band** draw it in their own focus colour, derived against their own grounds; the bold band's tab and filter strips, on the surface, keep the page's.
14
+
15
+ **Active: the accent border and its halo.**
16
+ - **A field clicked into** shows the accent border (`--ds-accent-ink`) and the soft halo (`--ds-ring-active`; red, `--ds-ring-error`, with an error), laid over its shadow. **Reached with Tab,** it shows the outline, its border turning the focus colour. Typing changes nothing, and a date's segment or a select clicked into keeps the halo while its arrows step it. `lib/input-modality.ts` notes on `<html>` (`data-input-modality`) whether a pointer or the keyboard moved focus last; it installs itself as the library loads in a browser, and each field makes sure of it (`useInputModality`, exported with `installInputModality`, `inputModality` and `INPUT_MODALITY_ATTR`), so an app adds nothing. The shared field styles `FIELD_FOCUS_RING`, `FIELD_FOCUS_WITHIN_RING`, `FIELD_HAS_FOCUS_RING` and their `ERROR_` twins draw both; their wrapper forms show the field's look for the part you type in, and leave a button, a select, a link, a checkbox, a radio or a switch inside the field (a tag's remove, a picker's chevron, a composer's Send, an editor's toolbar or a task's checkbox), or a popup inside its box, to show its own outline: one focus point.
17
+ - **An open dropdown or picker** keeps the accent border and halo on its trigger (`ACTIVE_RING`), and so does FileUpload's zone while a file is over it. **A popup's own search field** (CommandPalette's, a searchable Dropdown's) has no look of its own: the open popup is what's active, and the text cursor shows where you type.
18
+ - **Options packed tight sit 4 px apart:** TimePicker's times and the date pickers' days, so the outline of the one beside the chosen one sits in the gap, never on its fill. The lists grow a little (an hour column 4 px a row).
19
+ - **Selected is its own look.** A selected card, swatch, the Table's phone card, CustomPanel's options and the Stepper's current step draw the accent border (`--ds-accent-ink`) and their fill, where some drew the halo; Gantt's selected bar draws the accent border, and its row's tint spans the track.
20
+
21
+ **Readable colours.** Each writer (the showcase, the builder's preview, a project card, the generated stylesheet) derives them after the theme's overrides, for each scope's grounds: the canvas and its gradient's colours, the surface, the muted fill, the accent's 10% and 20% tints, the subtle header's tint and the band's strip.
22
+ - **`--ds-focus`**, the outline's colour, at 3:1: the accent wherever it reaches it, else its nearest readable shade.
23
+ - **`--ds-text-muted` and `--ds-text-secondary`** at 4.5:1, still a step apart; placeholders and hints use the muted one.
24
+ - **`--ds-accent-ink`** (new), the accent as text, a mark or a state's edge, at 4.5:1: links, the sidebar's current item and a parent's marks, TreeView's marks, selected and open borders. Fills keep `--ds-accent-primary`.
25
+ - **The tint's words** (`--ds-accent-subtle-text`) are the accent's soft pair's text (`--ds-accent-text`): mentions, chat bubbles, the date pickers' ranges, Gantt's selected row, an info Alert's actions; the tints keep their fill.
26
+ - **Each status's words** (`--ds-status-success-text`, `-warning-text`, `-error-text`, `-info-text`; three new) read on their soft background and on the page, in every status palette: the palette's own colour where it reaches 4.5:1, else its soft pair's text (dark mode's paler one). The soft backgrounds don't change. Badge's and Tag's soft variants, Alert, Toast, StatsCard's trends, a field's error message, an upload's error and destructive menu items use them; a status's icons, dots and fills keep `--ds-status-<status>`.
27
+ - **The bold band's quieter text** (`--ds-text-on-primary-muted`, new) is the quietest of its text at 90, 80, 70 and 60% that reads on everything the band paints.
28
+ - **The sidebar's family** against the sidebar's own background: its focus colour and the accent as text (`--ds-sidebar-focus`, `--ds-sidebar-accent-ink`, new), and its quiet greys (`--ds-sidebar-text-muted`, `--ds-sidebar-text-secondary`), now derived.
29
+ - **A component given its own mode keeps it** (a SidebarNav or a Toast with `mode="light"`, the shell's header in a mode of its own): every wrapper in a mode derives its own readable colours, `roots.css` gives a light wrapper the whole light set (as a dark one had the dark set: it lacked the raised surfaces, the sidebar's, the header's, the tabs', the fields' and the statuses' light values), and the generated stylesheet gives a wrapper in the theme's saved mode its own accent, palettes, statuses and overrides back when the page is switched to the other mode. Before, a SidebarNav set to light in an app switched to dark drew the dark page's sidebar. Regenerating the theme's tokens brings the stylesheet's half.
30
+
31
+ **Tokens.** Removed: `--ds-shadow-focus` (use `FOCUS_RING`) and `--ds-input-focus-ring` (`FIELD_FOCUS_RING` on a field, `ACTIVE_RING` on an open trigger). Kept: `--ds-ring-active` and `--ds-ring-error`, the halo's colours; `--ds-border-focus`, now `--ds-focus`'s alias. New: `--ds-focus`, `--ds-accent-ink`, the three status words, `--ds-text-on-primary-muted`, `--ds-sidebar-focus`, `--ds-sidebar-accent-ink` and `--ds-focus-inset`. Regenerate the theme's tokens after upgrading (below).
32
+
33
+ **Also.** A horizontal tab strip's `className` (`TabsList`'s, and `Tabs`' given an array of tabs) now goes on the strip's outer box, round the scroller that makes the outline's room, where it was on the tab list: a class that styled the list itself (its gap, its border) no longer reaches it. RichTextEditor's link and image popups are named non-modal dialogs. A heading the library focuses after a flow's step moves the reader there with no outline, as a page load does. Toast's action takes its ground's words colour (the accent's ink on a plain toast, a status's words on its colour), as Alert's do. **The engine:** `gs:focus-outline-suppressed` accepts the shared styles by name (`outline-none ${FOCUS_RING}`), and its advice names `FOCUS_RING`; `gs:unknown-token` names the replacement of each removed token. **The guidance** (`get_tokens`' design intent) describes the three looks and the derived colours.
34
+
35
+ ### Upgrade note for agents (0.27.0 → 0.28.0)
36
+
37
+ Upgrade `gridsmith-ui` to `^0.28.0` (an app pinned to `^0.27.0` never reaches it), then:
38
+ - **The tokens.** Regenerate the theme's tokens (`get_tokens`), every app: they write `--ds-focus`, `--ds-accent-ink`, the status words and the sidebar's family, derived for the theme. Until then the library falls back to the colours each is derived from, as 0.27.0 drew them.
39
+ - **A removed token.** Replace `focus-visible:shadow-[var(--ds-shadow-focus)]`, and the `focus-visible:outline-none` beside it, with `${FOCUS_RING}` from `'gridsmith-ui/utils'`; replace a ring or shadow in `--ds-input-focus-ring` with `${FIELD_FOCUS_RING}` on a field, or `${ACTIVE_RING}` while a trigger is open. The engine names both (`gs:unknown-token`).
40
+ - **Focus of your own.** A hand-built element that takes focus uses the shared style rather than its own ring: `FOCUS_RING` on a button, a link, a card or a menu item; `HAS_FOCUS_RING` on a wrapper that shows focus for a control inside it; `FIELD_FOCUS_RING` on a field you build, with `useInputModality()` called once in it; `FOCUS_INSET` on an edge-to-edge table row. A scroller of your own that holds focusable items gives the outline 4 px of room (`p-[4px]`, with `-m-[4px]` where nothing may move) and `scroll-p-[4px]`, and calls `useRevealFocus(element)` if its items can show only in part. Gridsmith's components need nothing.
41
+ - **Accent and status text of your own.** Text in the accent on the page takes `text-[var(--ds-accent-ink)]`; a status's words take `text-[var(--ds-status-<status>-text)]`. Fills and marks keep their colours.
42
+ - **Tests.** A test that pinned a component's old focus classes (`focus-visible:shadow-[var(--ds-shadow-focus)]`, `focus-visible:ring-*`), its accent text (`text-[var(--ds-accent-primary)]`) or a status's words reads the new ones: the shared styles' classes, `--ds-accent-ink`, `--ds-status-<status>-text`. A test that clicked into a field and expected the outline gets the halo; one that tabbed in gets the outline.
43
+
44
+ ## 0.27.0 — 4 October 2026
4
45
 
5
46
  The calendar review (Sprint 25.19), dates on server-rendered pages (Sprint 25.20), the owner's review of the themes page with icon packs that build on Next.js (Sprint 25.21), and components a Next.js server component can render (Sprint 25.22). Small actions beside text are links; the Stepper's steps open when they are reached, are greyed while they can't start yet, and are a plain progress list when nothing opens them; events repeat, in the iCalendar standard's rule, with a field to set it, the Calendar drawing every occurrence and a dialog asking whether an edit is for one or the series; weeks start on the visitor's first day; fields rest on the soft edge again, with a strong edge kept for the controls whose edge is their state; a server-rendered page writes its dates in the visitor's form from the first paint and hydrates without a mismatch; an app hands the library its theme's icon pack, so every bundler builds it; a Next.js page can stay a server component, its helpers from `gridsmith-ui/utils`. It adds components (`RecurrencePicker`, `RecurrenceScopeDialog`, `LocaleProvider`), helpers (`lib/recurrence`, `useFormatLocale`, `useHydrated`, `useBrowserTimeZone`, `registerIconPack`, and the server-safe helpers on `gridsmith-ui/utils`), types (`Recurrence`, `Weekday` and the rest), props (`weekStartsOn` on DatePicker, a RadioGroup option's `reveal`, the shell's `canNavigateBack`) and a token (`--ds-control-edge-strong`), and changes behaviour and defaults (the Stepper's steps, the week's first day, the fields' edges, what a server-rendered page draws before it has loaded, an icon pack other than Lucide, the minimal header, the shell's height), which breaks some 0.26.0 code and tests: a 0.x minor release, 0.27.0, says so, and an app pinned to `^0.26.0` doesn't reach it by itself. The upgrade note at the end says what an app on 0.26.0 does.
6
47
 
package/dist/charts.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { useFormatLocale, useHydrated, TITLE_TEXT, Skeleton } from './chunk-64TXZ4L7.js';
2
+ import { useFormatLocale, useHydrated, TITLE_TEXT, Skeleton } from './chunk-2ROVDVLZ.js';
3
3
  import { formatLocale, elementType } from './chunk-OYNUU346.js';
4
4
  import { mergeRefs } from './chunk-7Q46JXSK.js';
5
- import { cn, GLASS_SURFACE } from './chunk-M2QRNBDQ.js';
5
+ import { cn, GLASS_SURFACE } from './chunk-66JJCQU3.js';
6
6
  import { createContext, forwardRef, useContext, useRef, useState, useMemo, useLayoutEffect, useEffect, useId, useSyncExternalStore, Children, isValidElement } from 'react';
7
7
  import { ResponsiveContainer, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Bar, LineChart as LineChart$1, Line, AreaChart as AreaChart$1, Area, PieChart as PieChart$1, Pie, Cell, ComposedChart, ScatterChart as ScatterChart$1, ZAxis, Scatter, RadarChart as RadarChart$1, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, RadialBarChart as RadialBarChart$1, RadialBar, FunnelChart as FunnelChart$1, Funnel, LabelList, Treemap, Sankey, Text, Legend, getNiceTickValues, Rectangle } from 'recharts';
8
8
  import { createPortal } from 'react-dom';