gridsmith-ui 0.26.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 (111) hide show
  1. package/CHANGELOG.md +1010 -0
  2. package/README.md +21 -5
  3. package/dist/charts.d.ts +2 -2
  4. package/dist/charts.js +59 -44
  5. package/dist/charts.js.map +1 -1
  6. package/dist/chat.js +7 -6
  7. package/dist/chat.js.map +1 -1
  8. package/dist/{chunk-X2HEV7FB.js → chunk-2ROVDVLZ.js} +24 -34
  9. package/dist/chunk-2ROVDVLZ.js.map +1 -0
  10. package/dist/chunk-3BRQRKDO.js +1 -0
  11. package/dist/chunk-3BRQRKDO.js.map +1 -1
  12. package/dist/chunk-66JJCQU3.js +46 -0
  13. package/dist/chunk-66JJCQU3.js.map +1 -0
  14. package/dist/chunk-7Q46JXSK.js +1 -0
  15. package/dist/chunk-7Q46JXSK.js.map +1 -1
  16. package/dist/chunk-7RKC5C7G.js +35 -0
  17. package/dist/chunk-7RKC5C7G.js.map +1 -0
  18. package/dist/{chunk-OTCEJN64.js → chunk-BRAXJEEP.js} +8 -6
  19. package/dist/chunk-BRAXJEEP.js.map +1 -0
  20. package/dist/chunk-CRQ6KCRD.js +1 -0
  21. package/dist/chunk-CRQ6KCRD.js.map +1 -1
  22. package/dist/{chunk-MYIJNVTK.js → chunk-DQCHCLEJ.js} +11 -9
  23. package/dist/chunk-DQCHCLEJ.js.map +1 -0
  24. package/dist/{chunk-RWKCAKN3.js → chunk-EIWXVICU.js} +7 -6
  25. package/dist/chunk-EIWXVICU.js.map +1 -0
  26. package/dist/{chunk-SFY2KMHG.js → chunk-FD4YED7O.js} +6 -4
  27. package/dist/chunk-FD4YED7O.js.map +1 -0
  28. package/dist/{chunk-MD2EFMES.js → chunk-GXMTS3YD.js} +4 -3
  29. package/dist/chunk-GXMTS3YD.js.map +1 -0
  30. package/dist/chunk-HP7WUZPK.js +1 -0
  31. package/dist/chunk-HP7WUZPK.js.map +1 -1
  32. package/dist/chunk-HTXP5BMM.js +38 -0
  33. package/dist/chunk-HTXP5BMM.js.map +1 -0
  34. package/dist/chunk-NRHIYS5W.js +1 -0
  35. package/dist/chunk-NRHIYS5W.js.map +1 -1
  36. package/dist/{chunk-KWLNEH53.js → chunk-OPFJEL3Z.js} +59 -28
  37. package/dist/chunk-OPFJEL3Z.js.map +1 -0
  38. package/dist/chunk-OYNUU346.js +78 -0
  39. package/dist/chunk-OYNUU346.js.map +1 -0
  40. package/dist/chunk-QM4SJKWV.js +1 -0
  41. package/dist/chunk-QM4SJKWV.js.map +1 -1
  42. package/dist/{chunk-ZYVXV4WC.js → chunk-R4GXKH4U.js} +58 -11
  43. package/dist/chunk-R4GXKH4U.js.map +1 -0
  44. package/dist/{chunk-HXVXJUGV.js → chunk-TJEV7YAY.js} +38 -10
  45. package/dist/chunk-TJEV7YAY.js.map +1 -0
  46. package/dist/{chunk-EX64MN2U.js → chunk-TRDXWHD2.js} +8 -7
  47. package/dist/chunk-TRDXWHD2.js.map +1 -0
  48. package/dist/chunk-WH2FUFAC.js +1 -0
  49. package/dist/chunk-WH2FUFAC.js.map +1 -1
  50. package/dist/chunk-XVB55M3N.js +1 -0
  51. package/dist/chunk-XVB55M3N.js.map +1 -1
  52. package/dist/{chunk-CYN5O567.js → chunk-YUTF2X6B.js} +45 -22
  53. package/dist/chunk-YUTF2X6B.js.map +1 -0
  54. package/dist/chunk-ZI3OQDET.js +1 -0
  55. package/dist/chunk-ZI3OQDET.js.map +1 -1
  56. package/dist/data-grid.d.ts +1 -1
  57. package/dist/data-grid.js +21 -12
  58. package/dist/data-grid.js.map +1 -1
  59. package/dist/editor-mentions.js +3 -2
  60. package/dist/editor-mentions.js.map +1 -1
  61. package/dist/editor.js +47 -26
  62. package/dist/editor.js.map +1 -1
  63. package/dist/{feather-VFWLAILO.js → feather-FNBQ74RR.js} +10 -17
  64. package/dist/feather-FNBQ74RR.js.map +1 -0
  65. package/dist/{heroicons-H3Z7DFCF.js → heroicons-DODCSYWD.js} +9 -8
  66. package/dist/heroicons-DODCSYWD.js.map +1 -0
  67. package/dist/icons.d.ts +31 -4
  68. package/dist/icons.js +2 -1
  69. package/dist/icons.js.map +1 -1
  70. package/dist/index.d.ts +456 -66
  71. package/dist/index.js +2264 -1091
  72. package/dist/index.js.map +1 -1
  73. package/dist/kanban.js +20 -12
  74. package/dist/kanban.js.map +1 -1
  75. package/dist/{lucide-MR32KM4G.js → lucide-ZWE3EPGP.js} +9 -8
  76. package/dist/lucide-ZWE3EPGP.js.map +1 -0
  77. package/dist/{phosphor-ABQQL5N5.js → phosphor-DIHPA4AJ.js} +9 -8
  78. package/dist/phosphor-DIHPA4AJ.js.map +1 -0
  79. package/dist/resizable.js +24 -17
  80. package/dist/resizable.js.map +1 -1
  81. package/dist/roots.css +116 -22
  82. package/dist/{tabler-ANUSY4D2.js → tabler-D3VYTSGI.js} +9 -8
  83. package/dist/tabler-D3VYTSGI.js.map +1 -0
  84. package/dist/tokens.css +122 -34
  85. package/dist/{use-pagination-BnKOnBdz.d.ts → use-pagination-BxcRlNQG.d.ts} +6 -0
  86. package/dist/utils.d.ts +321 -5
  87. package/dist/utils.js +885 -1
  88. package/dist/utils.js.map +1 -1
  89. package/dist/virtualized.d.ts +1 -1
  90. package/dist/virtualized.js +20 -12
  91. package/dist/virtualized.js.map +1 -1
  92. package/dist-static/tokens.css +122 -34
  93. package/package.json +5 -3
  94. package/dist/chunk-CYN5O567.js.map +0 -1
  95. package/dist/chunk-EX64MN2U.js.map +0 -1
  96. package/dist/chunk-HXVXJUGV.js.map +0 -1
  97. package/dist/chunk-KWLNEH53.js.map +0 -1
  98. package/dist/chunk-M2QRNBDQ.js +0 -41
  99. package/dist/chunk-M2QRNBDQ.js.map +0 -1
  100. package/dist/chunk-MD2EFMES.js.map +0 -1
  101. package/dist/chunk-MYIJNVTK.js.map +0 -1
  102. package/dist/chunk-OTCEJN64.js.map +0 -1
  103. package/dist/chunk-RWKCAKN3.js.map +0 -1
  104. package/dist/chunk-SFY2KMHG.js.map +0 -1
  105. package/dist/chunk-X2HEV7FB.js.map +0 -1
  106. package/dist/chunk-ZYVXV4WC.js.map +0 -1
  107. package/dist/feather-VFWLAILO.js.map +0 -1
  108. package/dist/heroicons-H3Z7DFCF.js.map +0 -1
  109. package/dist/lucide-MR32KM4G.js.map +0 -1
  110. package/dist/phosphor-ABQQL5N5.js.map +0 -1
  111. package/dist/tabler-ANUSY4D2.js.map +0 -1
package/dist/utils.d.ts CHANGED
@@ -5,9 +5,325 @@ declare const GLASS_BACKDROP = "[backdrop-filter:var(--ds-glass-filter)] [-webki
5
5
  declare const GLASS_SURFACE = "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)] shadow-[var(--ds-shadow-card),var(--ds-glass-inset)]";
6
6
  declare const GLASS_OVERLAY = "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)] shadow-[var(--ds-shadow-modal),var(--ds-glass-inset)]";
7
7
  declare const GLASS_DROPDOWN = "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)] shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]";
8
- declare const ACTIVE_RING = "border-[var(--ds-border-focus)] ring-2 ring-[var(--ds-ring-active)]";
9
- declare const FOCUS_RING = "focus-visible:outline-none focus-visible:border-[var(--ds-border-focus)] focus-visible:ring-2 focus-visible:ring-[var(--ds-ring-active)]";
10
- declare const FOCUS_WITHIN_RING = "focus-within:border-[var(--ds-border-focus)] focus-within:ring-2 focus-within:ring-[var(--ds-ring-active)]";
11
- declare const HAS_FOCUS_RING = "has-[:focus-visible]:border-[var(--ds-border-focus)] has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-[var(--ds-ring-active)]";
8
+ declare const FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:shadow-none";
9
+ /**
10
+ * On a wrapper that shows focus for a control inside it: HAS_FOCUS_RING, from the keyboard only (`:has(:focus-visible)`).
11
+ * FOCUS_WITHIN_RING shows it on any focus inside, a click's too, since `:focus-within` has no keyboard-only form: kept
12
+ * for code that uses it, and a new wrapper takes HAS_FOCUS_RING (D6: keyboard focus shows only from the keyboard).
13
+ */
14
+ declare const FOCUS_WITHIN_RING = "focus-within:outline-2 focus-within:outline-solid focus-within:outline-offset-2 focus-within:outline-[var(--ds-focus)] focus-within:shadow-none";
15
+ declare const HAS_FOCUS_RING = "has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-solid has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-[var(--ds-focus)] has-[:focus-visible]:shadow-none";
16
+ /**
17
+ * The outline on a drawn child, where the element that takes focus is hidden or wraps it: a checkbox's box beside its
18
+ * input (`peer`), a radio's circle inside its button, a separator's grip, a Gantt milestone's diamond (`group`). The
19
+ * same outline, gap and shadow rule.
20
+ */
21
+ declare const PEER_FOCUS_RING = "peer-focus-visible:outline-2 peer-focus-visible:outline-solid peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[var(--ds-focus)] peer-focus-visible:shadow-none";
22
+ declare const GROUP_FOCUS_RING = "group-focus-visible:outline-2 group-focus-visible:outline-solid group-focus-visible:outline-offset-2 group-focus-visible:outline-[var(--ds-focus)] group-focus-visible:shadow-none";
23
+ /**
24
+ * The same outline drawn inside the element's edge, for edge-to-edge rows, cells and scroll regions only (the plan's
25
+ * P3): elements that are never filled solid, since inside the edge there is no gap to keep one colour readable on a fill.
26
+ * It sits `--ds-focus-inset` in: 5 px, deeper where the theme's corners are rounder, so it clears a table's rounded
27
+ * corners (D8, the owner's decision A); what such an element holds keeps 1 px more clear of its edge. Anywhere else the
28
+ * outline stays outside, with room made for it. Moved here from use-keyboard-scroll.ts (Sprint 30) so the server-safe
29
+ * `gridsmith-ui/utils` can export it.
30
+ */
31
+ declare const FOCUS_INSET = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-[var(--ds-focus-inset)] focus-visible:outline-[var(--ds-focus)]";
32
+ /**
33
+ * A field (D6, P4, P13). Reached with Tab: the keyboard's outline, and its border in the focus colour, as GOV.UK turns a
34
+ * focused input's border: it is where you type. Clicked into: the active look instead, the accent border and its soft
35
+ * halo (`ring-2` in --ds-ring-active, laid over the field's own shadow), and no outline. A browser matches :focus-visible
36
+ * on a text field either way, so lib/input-modality.ts notes on <html> whether a pointer moved focus last; with no note
37
+ * yet, the outline. The field keeps its own (inset) shadow in both: no shadow-none here.
38
+ *
39
+ * The wrapper forms (_WITHIN_ and _HAS_, for a box round the part you type in) show it while that part has focus, and
40
+ * not while a control of the field's own does: a button, a select, a link, a checkbox, a radio or a switch inside it (a
41
+ * tag's remove, a picker's chevron, a composer's Send, an editor's toolbar or a task's checkbox), or anything in a popup
42
+ * inside the box (a dialog of its own; a field that is itself in a dialog still shows it). That control shows its own outline, so there is one focus point, never
43
+ * two (P11). _WITHIN_ reads :focus, as a click on a date's segment isn't :focus-visible; _HAS_ reads :focus-visible.
44
+ * Either outranks the field's hover border, so hovering keeps the look.
45
+ */
46
+ declare const FIELD_FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:focus-visible:outline-none [[data-input-modality=pointer]_&]:focus-visible:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:focus-visible:ring-2 [[data-input-modality=pointer]_&]:focus-visible:ring-[var(--ds-ring-active)]";
47
+ declare const FIELD_FOCUS_WITHIN_RING = "has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-solid has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-offset-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-[var(--ds-focus)] has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-[var(--ds-ring-active)]";
48
+ declare const FIELD_HAS_FOCUS_RING = "has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-solid has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-offset-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-[var(--ds-focus)] has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-[var(--ds-ring-active)]";
49
+ declare const ERROR_FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:focus-visible:outline-none [[data-input-modality=pointer]_&]:focus-visible:ring-2 [[data-input-modality=pointer]_&]:focus-visible:ring-[var(--ds-ring-error)]";
50
+ declare const ERROR_FOCUS_WITHIN_RING = "has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-solid has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-offset-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-[var(--ds-focus)] has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-[var(--ds-ring-error)]";
51
+ declare const ERROR_HAS_FOCUS_RING = "has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-solid has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-offset-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-[var(--ds-focus)] has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-[var(--ds-ring-error)]";
52
+ declare const ACTIVE_RING = "border-[var(--ds-accent-ink)] ring-2 ring-[var(--ds-ring-active)]";
53
+ declare const ERROR_ACTIVE_RING = "border-[var(--ds-status-error)] ring-2 ring-[var(--ds-ring-error)]";
12
54
 
13
- export { ACTIVE_RING, FOCUS_RING, FOCUS_WITHIN_RING, GLASS_BACKDROP, GLASS_DROPDOWN, GLASS_OVERLAY, GLASS_SURFACE, HAS_FOCUS_RING, cn };
55
+ /**
56
+ * The locale LocaleProvider writes in on the server for a page language and a request's Accept-Language header (Sprint
57
+ * 25.22's review), for server code's own dates and numbers: a server page passes it to the helpers from
58
+ * `gridsmith-ui/utils`, so its words read as the components' beside them. `requestLocale(LANG, (await
59
+ * headers()).get('accept-language'))`.
60
+ */
61
+ declare function requestLocale(lang: string | undefined, acceptLanguage?: string | null): string;
62
+
63
+ /** A day of the week as `Date.getDay()` counts them: Sunday 0, Monday 1 … Saturday 6. */
64
+ type Weekday = 0 | 1 | 2 | 3 | 4 | 5 | 6;
65
+
66
+ /**
67
+ * How something repeats (Sprint 25.19 R1): the iCalendar standard's rule (RFC 5545 `RRULE`), in the subset Outlook's and
68
+ * Google's menus write (P5), read in the event's local time. The quick choices are stored in the standard's implied form
69
+ * (P6): a weekly rule with no `weekdays`, a monthly rule with no `day` or `nth` and a bare yearly rule repeat on the
70
+ * start's own weekday, date or anniversary, so moving the event moves them. The event's own start is always its first
71
+ * occurrence.
72
+ */
73
+ type RecurrenceFrequency = "daily" | "weekly" | "monthly" | "yearly";
74
+ /** An nth weekday of a month: the first to the fourth, or the last (−1). A fifth weekday is the last. */
75
+ type WeekOfMonth = 1 | 2 | 3 | 4 | -1;
76
+ interface Recurrence {
77
+ freq: RecurrenceFrequency;
78
+ /** Every n days, weeks, months or years. Default 1. */
79
+ interval?: number;
80
+ /** Weekly: the days it repeats on, Sunday 0 to Saturday 6. Left out, the start's own weekday. */
81
+ weekdays?: Weekday[];
82
+ /** Monthly, or yearly with `month`: a day of the month, 1 to 31, or −1 for the last day. A month without the day is skipped. */
83
+ day?: number;
84
+ /** Monthly, or yearly with `month`: an nth weekday, `{ week: 1, weekday: 2 }` the first Tuesday. */
85
+ nth?: {
86
+ week: WeekOfMonth;
87
+ weekday: Weekday;
88
+ };
89
+ /** Yearly: the month, 1 to 12, with `day` or `nth`. A bare yearly rule repeats on the start's anniversary. */
90
+ month?: number;
91
+ /** The week's first day (WKST), which places a weekly rule's weeks. Default Monday, as RFC 5545 says. */
92
+ weekStart?: Weekday;
93
+ /**
94
+ * The last moment it occurs. A date at midnight includes its whole day ("until 30 November"); an all-day event's is a
95
+ * date. RecurrencePicker stores the end of the chosen day, which other apps read exactly. Left out with `count`, it
96
+ * never ends. A rule read back from JSON may carry it as a string: the library reads it as the date it was.
97
+ */
98
+ until?: Date;
99
+ /** How many times it occurs, the first included, and the excluded dates among them (RFC 5545). */
100
+ count?: number;
101
+ }
102
+ /** The fields a repeating event carries; a Calendar event has them as `repeat` and `exceptions` (P12: never `recurrence`). */
103
+ interface RepeatingEvent {
104
+ id: string;
105
+ start: Date;
106
+ end?: Date;
107
+ allDay?: boolean;
108
+ /** The rule, or a rule string `parseRRule` reads ("RRULE:FREQ=WEEKLY;BYDAY=TU,TH"). */
109
+ repeat?: Recurrence | string;
110
+ /** The dates left out, as day keys in local time ("2026-10-20"): the original date of each occurrence removed or moved. */
111
+ exceptions?: string[];
112
+ /**
113
+ * On an occurrence, its series' id and its original date (a day key), as RFC 5545's RECURRENCE-ID links an edited
114
+ * instance to its series. Each occurrence `occurrences` gives carries it, and so does an occurrence changed on its own
115
+ * ("This event"), which the page stores under an id of its own: the series leaves the date out, and the edit helpers
116
+ * find it by its link.
117
+ */
118
+ series?: {
119
+ id: string;
120
+ date: string;
121
+ };
122
+ }
123
+ /** Which occurrences a change or a deletion applies to: this one, it and the ones after it, or the whole series. */
124
+ type RecurrenceScope = "this" | "following" | "all";
125
+ /**
126
+ * What a choice in RecurrenceScopeDialog does to the page's events: `events`, the list as it now is, for a page that
127
+ * keeps its events in state; or `save`, the events to write (new or changed, each by its id), and `remove`, the ids to
128
+ * delete, for a page that stores them elsewhere.
129
+ */
130
+ interface RepeatChange<T> {
131
+ events: T[];
132
+ save: T[];
133
+ remove: string[];
134
+ }
135
+ /** One occurrence of a series: the event without its repeat fields, its own id, start and end, and where it came from. */
136
+ type Occurrence<T extends RepeatingEvent> = Omit<T, "repeat" | "exceptions"> & {
137
+ id: string;
138
+ start: Date;
139
+ end?: Date;
140
+ /** The series' id and this occurrence's original date (a day key), which the edit helpers take. */
141
+ series: {
142
+ id: string;
143
+ date: string;
144
+ };
145
+ };
146
+ /**
147
+ * The rule a string holds, or null when it is outside P5's subset (the event is then drawn once, its rule kept as written):
148
+ * FREQ, INTERVAL and WKST; weekly BYDAY days; a monthly or yearly BYMONTHDAY, or one nth BYDAY ("1TU", or "TU" with
149
+ * BYSETPOS=1); a yearly BYMONTH with either; UNTIL (a date, a floating or a UTC date-time) or COUNT. The "RRULE:" prefix
150
+ * is optional. A daily rule with days (every weekday, as some apps write it) reads as weekly on them.
151
+ */
152
+ declare function parseRRule(text: string): Recurrence | null;
153
+ /**
154
+ * The rule as an RRULE string, "RRULE:FREQ=…", for an iCalendar file or another app. UNTIL is written as a date for an
155
+ * all-day event and in UTC for a timed one, as RFC 5545 asks.
156
+ */
157
+ declare function toRRule(rule: Recurrence, { allDay }?: {
158
+ allDay?: boolean;
159
+ }): string;
160
+ /**
161
+ * A rule from a value: the object itself, the rule a string holds, or null for an unreadable string or none. A rule read
162
+ * back from JSON (storage, an API) has its end as a string, which is read as the date it was; an end that isn't a date
163
+ * makes the rule unreadable, so the event is drawn once rather than guessed at.
164
+ */
165
+ declare function readRecurrence(value: Recurrence | string | undefined | null): Recurrence | null;
166
+ /** The nth weekday a date is: the last when it is in its month's last seven days (a fifth Tuesday is the last). */
167
+ declare function nthOf(date: Date): {
168
+ week: WeekOfMonth;
169
+ weekday: Weekday;
170
+ };
171
+ /**
172
+ * Every occurrence of a repeating event that overlaps [from, to), in order: the event without its repeat fields, each
173
+ * with the id "<id>::<date>", its own start and end (the same wall-clock times and number of days) and `series`, its
174
+ * original date. Its excluded dates are left out. An event that doesn't repeat, or whose rule can't be read, is itself,
175
+ * when it overlaps.
176
+ */
177
+ declare function occurrences<T extends RepeatingEvent>(event: T, from: Date, to: Date): Array<T | Occurrence<T>>;
178
+ /**
179
+ * The occurrence of a series on a day (a day key), or undefined when it has none that day (the rule skips it, or it is
180
+ * excluded): for a page whose Edit has an address of its own, which carries the series' id and the date. Given the
181
+ * page's events, an occurrence changed on its own on that date ("This event") is found too.
182
+ */
183
+ declare function occurrenceOn<T extends RepeatingEvent>(series: T, date: string, events?: readonly T[]): Occurrence<T> | undefined;
184
+ /**
185
+ * Saves the user's edit to an occurrence, for the scope they chose in RecurrenceScopeDialog: the page stores what it
186
+ * returns. `occurrence` is the event they opened, one the Calendar handed over or one changed on its own before (the
187
+ * page's own); `changes` the form's fields, every one or only those changed (only what differs from the opened event
188
+ * applies); `newId` an id of the page's, for the event or the series a choice makes.
189
+ * - "This event": the occurrence becomes an event of its own, linked to its series by `series`, its date left out of the
190
+ * series; one changed on its own before just takes the edit.
191
+ * - "This and following events": the series ends the day before and a new one starts on the date, under `newId`, with
192
+ * the edit; the events changed on their own from the date on go with it.
193
+ * - "All events": the series takes the edit, and a moved time or day moves it and its rule, so every earlier date stays.
194
+ * The events changed on their own keep what they changed themselves (a field, another day, other times) and follow the
195
+ * rest. A changed repeat removes them, as Outlook does, and their dates go back to the new rule (RecurrenceScopeDialog's
196
+ * `edited` says so first); a deleted date stays deleted.
197
+ */
198
+ declare function saveOccurrence<T extends RepeatingEvent>(events: readonly T[], occurrence: Occurrence<T> | T, scope: RecurrenceScope, changes: Partial<T>, newId: string): RepeatChange<T>;
199
+ /**
200
+ * Deletes an occurrence, for the scope the user chose in RecurrenceScopeDialog: the page stores what it returns. "This
201
+ * event" leaves its date out of the series (an event changed on its own is removed, and its date stays empty); "This
202
+ * and following events" ends the series the day before and removes the events changed on their own from the date on;
203
+ * "All events" removes the series and every event changed on its own.
204
+ */
205
+ declare function deleteOccurrence<T extends RepeatingEvent>(events: readonly T[], occurrence: Occurrence<T> | T, scope: RecurrenceScope): RepeatChange<T>;
206
+ /**
207
+ * How many of a series' events changed on their own each scope covers, for RecurrenceScopeDialog's `edited`: "This and
208
+ * following events" those from the occurrence's date on, "All events" every one.
209
+ */
210
+ declare function countEdited<T extends RepeatingEvent>(events: readonly T[], occurrence: Occurrence<T> | T): {
211
+ following: number;
212
+ all: number;
213
+ };
214
+ /**
215
+ * The rule in words, for its date: "Every week on Tuesday and Thursday, until 30 November 2026", "Every month on the
216
+ * first Tuesday", "Every year on 6 October". The days and dates are written in the locale given (a component's
217
+ * useFormatLocale(), Sprint 25.20), else the browser's reading of the page's language.
218
+ */
219
+ declare function describeRecurrence(rule: Recurrence, start: Date, locale?: string | undefined): string;
220
+ interface RecurrencePreset {
221
+ /** The choice in words, as describeRecurrence writes it for the date. */
222
+ label: string;
223
+ rule: Recurrence;
224
+ }
225
+ /**
226
+ * The quick choices for a date, each one including it (P6): every day; every weekday, for a weekday; every week on its
227
+ * weekday; every month on its nth weekday (the fourth and "the last" both for a fourth one in a month's last seven days,
228
+ * only "the last" for a fifth); every month on its date, and on the last day when it is one; every year on its
229
+ * anniversary. The weekly, monthly-by-date and yearly choices are the
230
+ * implied form, so they follow the date when the event moves.
231
+ */
232
+ declare function recurrencePresets(start: Date, locale?: string | undefined): RecurrencePreset[];
233
+ /** Whether two rules repeat the same way (an `until` compared by its moment). */
234
+ declare function sameRecurrence(a: Recurrence | null | undefined, b: Recurrence | null | undefined): boolean;
235
+
236
+ /**
237
+ * Time zones by the browser's own names, and their offsets (Sprint 25.17 A28), apart from the TimezoneSelect component since
238
+ * Sprint 25.22 so a server can call them: nothing here needs React. `gridsmith-ui/utils` exports canonicalTimeZone and
239
+ * timeZoneOffset for server code; browserTimeZone reads the zone of whatever runs it, a server's own there.
240
+ */
241
+ /**
242
+ * The browser's own name for a zone (Sprint 25.17 A28, R28-51): one browser always names a zone one way, so a stored
243
+ * "Asia/Calcutta" and a listed "Asia/Kolkata" are one zone, with no alias table shipped. An id the browser doesn't know
244
+ * stays as given.
245
+ */
246
+ declare function canonicalTimeZone(zone: string): string;
247
+ /**
248
+ * A zone's offset from UTC at an instant, as the locale given names it ("GMT+1", "GMT-5", "GMT+5:30"; a component's
249
+ * useFormatLocale(), else the browser's reading): read at that instant, so it follows daylight saving.
250
+ */
251
+ declare function timeZoneOffset(zone: string, at?: Date, locale?: string | undefined): string;
252
+
253
+ /**
254
+ * Calendar days, and ranges of them in words (Sprint 25.7, Part D). A calendar day is a whole-number day index: days since
255
+ * 1970-01-01, counted on UTC day boundaries, so every day is the same width and a clock change never stretches or shrinks
256
+ * one. A "YYYY-MM-DD" string is a calendar day in the user's zone and is never parsed as UTC (new Date("2026-03-03") is
257
+ * 2 March, 19:00 in New York). Apart from the time scale (lib/time-scale.ts) since Sprint 25.22, so a server can call
258
+ * them: nothing here needs React or a browser, and `gridsmith-ui/utils` exports them for server code. On a server a Date
259
+ * or a date-time string is read in the server's time zone; a calendar day or a day index is the same everywhere.
260
+ */
261
+ /** A Date, or a string: "YYYY-MM-DD" is a calendar day; any other string is a date-time. */
262
+ type DateInput = Date | string;
263
+ type TimeZoom = "day" | "week" | "month" | "quarter";
264
+ /** Narrow to wide. */
265
+ declare const TIME_ZOOMS: readonly TimeZoom[];
266
+ /**
267
+ * The day index of a date: "2026-03-03" → that calendar day's index; a Date or a date-time string → its local calendar
268
+ * day plus the fraction of the day its local clock shows (a day's first instant is the whole day); a number is a day
269
+ * index already, as the scale's own functions take it. NaN for anything else: null from JSON, a string that is no date.
270
+ */
271
+ declare function dayOf(value: DateInput | number): number;
272
+ /** Local midnight of that calendar day; a fraction adds that much of the day on the local clock. */
273
+ declare function dateOfDay(day: number): Date;
274
+ /**
275
+ * Where a range that ends at `value` stops. A whole-day end is inclusive: "2026-03-14" (or a Date at local midnight,
276
+ * as the date pickers give) → the start of 15 March. A date-time end is half-open: it stops at that moment, as a day
277
+ * index does. A range's start can make a midnight Date half-open too (scale.span, formatDateRange, timeExtent).
278
+ */
279
+ declare function endDayOf(value: DateInput | number): number;
280
+ /**
281
+ * The earliest start and the latest end of some ranges, as day indices for useTimeScale: the end is where the last
282
+ * range stops (inclusive for a whole day, as endDayOf), and a range with no end ends where it starts (a milestone).
283
+ * NaN for no dated range, which the scale shows as today. A range, a start or an end that is null is skipped.
284
+ */
285
+ declare function timeExtent(ranges: Iterable<{
286
+ start: DateInput;
287
+ end?: DateInput;
288
+ }>): {
289
+ start: number;
290
+ end: number;
291
+ };
292
+ interface DateRangeWords {
293
+ locale?: string;
294
+ /** Joins the two ends in place of Intl's separator. Default " to " in English, and Intl's own separator elsewhere. */
295
+ to?: string;
296
+ /** Intl options for the days. Default { day: "numeric", month: "long" }; the year is added when the ends' years differ. */
297
+ day?: Intl.DateTimeFormatOptions;
298
+ /** Intl options for the times of a date-time range. Default { hour: "2-digit", minute: "2-digit" }. */
299
+ time?: Intl.DateTimeFormatOptions;
300
+ }
301
+ /**
302
+ * A range in words, in the locale, for accessible names: "3 to 14 March", "28 September to 3 October", "16 September"
303
+ * for one day. The end is inclusive for a whole day, as scale.span (a day index is where the range stops). A date-time
304
+ * range is named by its times, and the end's day only when it differs: "Friday 23 October, 06:00 to 14:00". Intl
305
+ * joins each day and time in the locale's own way, and outside English the two ends too ("10/31(土曜日)~11/01(日曜日)");
306
+ * the year shows when the two ends are in different years. A null end is the start's own day; a start that is no date
307
+ * gives "".
308
+ */
309
+ declare function formatDateRange(start: DateInput | number, end?: DateInput | number, words?: DateRangeWords): string;
310
+
311
+ /**
312
+ * Sprint 25.9, A3 — what a chart's category axis holds, and how its labels fit. No Recharts here: the charts entry and
313
+ * the tests import it, and it never measures on its own (the measurer is handed in).
314
+ *
315
+ * - `categoryKind(labels)`: "scale" when every non-empty label is a date, a time, a period or a number, else "names".
316
+ * Anchored patterns only — never `Date.parse`, which V8 lets read "Tier 1", "Sprint 1" and "Northern Region 2" as dates.
317
+ * - `createAxisMeasurer(el)`: canvas text widths in the axis's resolved font, read from a probe that carries
318
+ * `font-size: var(--ds-font-size-xs)`, so a `calc()` token (`calc(16px * .75)`, a 14 px base) measures right.
319
+ * - `fitLabel(name, width, measure)`: one line; else two lines split at a space; else "…" on the second. Never drops it.
320
+ */
321
+ type CategoryKind = "names" | "scale";
322
+ /**
323
+ * Whether a category axis holds names or a scale (dates, times, periods, numbers). Every non-empty label must match an
324
+ * anchored pattern to be "scale"; an all-empty set is "scale". LineChart and AreaChart are always "scale"; BarChart and
325
+ * CompositeChart guess with this, and their `categoryKind` prop overrides the guess.
326
+ */
327
+ declare function categoryKind(labels: ReadonlyArray<unknown>, locale?: string): CategoryKind;
328
+
329
+ export { ACTIVE_RING, type CategoryKind, type DateInput, type DateRangeWords, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, ERROR_HAS_FOCUS_RING, FIELD_FOCUS_RING, FIELD_FOCUS_WITHIN_RING, FIELD_HAS_FOCUS_RING, FOCUS_INSET, FOCUS_RING, FOCUS_WITHIN_RING, GLASS_BACKDROP, GLASS_DROPDOWN, GLASS_OVERLAY, GLASS_SURFACE, GROUP_FOCUS_RING, HAS_FOCUS_RING, type Occurrence, PEER_FOCUS_RING, type Recurrence, type RecurrenceFrequency, type RecurrencePreset, type RecurrenceScope, type RepeatChange, type RepeatingEvent, TIME_ZOOMS, type TimeZoom, type WeekOfMonth, type Weekday, canonicalTimeZone, categoryKind, cn, countEdited, dateOfDay, dayOf, deleteOccurrence, describeRecurrence, endDayOf, formatDateRange, nthOf, occurrenceOn, occurrences, parseRRule, readRecurrence, recurrencePresets, requestLocale, sameRecurrence, saveOccurrence, timeExtent, timeZoneOffset, toRRule };