@kennycorrea/ui 0.11.4 → 1.6.1

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 (242) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/README.md +251 -1
  3. package/dist/atoms/ActionMenu/ActionMenu.d.ts +37 -0
  4. package/dist/atoms/ActionMenu/ActionMenu.js +28 -0
  5. package/dist/atoms/ActionMenu/index.d.ts +1 -0
  6. package/dist/atoms/ActionMenu/index.js +1 -0
  7. package/dist/atoms/ActionSheet/ActionSheet.d.ts +10 -4
  8. package/dist/atoms/ActionSheet/ActionSheet.js +6 -15
  9. package/dist/atoms/ActionSheet/confirm.d.ts +1 -1
  10. package/dist/atoms/ActionSheet/confirm.js +1 -1
  11. package/dist/atoms/Avatar/Avatar.d.ts +1 -1
  12. package/dist/atoms/Badge/Badge.js +4 -4
  13. package/dist/atoms/Button/Button.js +2 -3
  14. package/dist/atoms/Button/Button.types.d.ts +5 -8
  15. package/dist/atoms/ContextMenu/ContextMenu.d.ts +1 -1
  16. package/dist/atoms/ContextMenu/ContextMenu.js +1 -1
  17. package/dist/atoms/Icon/Icon.d.ts +7 -9
  18. package/dist/atoms/Icon/Icon.js +23 -8
  19. package/dist/atoms/Pill/Pill.d.ts +17 -0
  20. package/dist/atoms/Pill/Pill.js +12 -0
  21. package/dist/atoms/Pill/index.d.ts +1 -0
  22. package/dist/atoms/Pill/index.js +1 -0
  23. package/dist/atoms/ResponsiveDialog/ResponsiveDialog.d.ts +9 -2
  24. package/dist/atoms/ResponsiveDialog/ResponsiveDialog.js +6 -15
  25. package/dist/atoms/StatusIndicator/StatusIndicator.d.ts +14 -0
  26. package/dist/atoms/StatusIndicator/StatusIndicator.js +8 -0
  27. package/dist/atoms/StatusIndicator/index.d.ts +1 -0
  28. package/dist/atoms/StatusIndicator/index.js +1 -0
  29. package/dist/atoms/TextLink/TextLink.d.ts +36 -0
  30. package/dist/atoms/TextLink/TextLink.js +17 -0
  31. package/dist/atoms/TextLink/index.d.ts +1 -0
  32. package/dist/atoms/TextLink/index.js +1 -0
  33. package/dist/atoms/Toast/Toast.d.ts +1 -1
  34. package/dist/atoms/Toast/Toast.js +1 -1
  35. package/dist/atoms/index.d.ts +4 -0
  36. package/dist/atoms/index.js +4 -0
  37. package/dist/hooks/breakpoints.d.ts +20 -0
  38. package/dist/hooks/breakpoints.js +13 -0
  39. package/dist/hooks/index.d.ts +4 -0
  40. package/dist/hooks/index.js +4 -0
  41. package/dist/hooks/useControllableState.d.ts +17 -0
  42. package/dist/hooks/useControllableState.js +22 -0
  43. package/dist/hooks/useElementWidth.d.ts +7 -0
  44. package/dist/hooks/useElementWidth.js +22 -0
  45. package/dist/hooks/useMediaQuery.d.ts +18 -0
  46. package/dist/hooks/useMediaQuery.js +51 -0
  47. package/dist/index.d.ts +4 -0
  48. package/dist/index.js +4 -0
  49. package/dist/molecules/AccentPicker/AccentPicker.d.ts +30 -0
  50. package/dist/molecules/AccentPicker/AccentPicker.js +27 -0
  51. package/dist/molecules/AccentPicker/index.d.ts +1 -0
  52. package/dist/molecules/AccentPicker/index.js +1 -0
  53. package/dist/molecules/Breadcrumbs/Breadcrumbs.d.ts +27 -0
  54. package/dist/molecules/Breadcrumbs/Breadcrumbs.js +40 -0
  55. package/dist/molecules/Breadcrumbs/index.d.ts +1 -0
  56. package/dist/molecules/Breadcrumbs/index.js +1 -0
  57. package/dist/molecules/Calendar/Calendar.d.ts +42 -0
  58. package/dist/molecules/Calendar/Calendar.js +111 -0
  59. package/dist/molecules/Calendar/index.d.ts +1 -0
  60. package/dist/molecules/Calendar/index.js +1 -0
  61. package/dist/molecules/DateInput/DateInput.d.ts +35 -0
  62. package/dist/molecules/DateInput/DateInput.js +41 -0
  63. package/dist/molecules/DateInput/index.d.ts +1 -0
  64. package/dist/molecules/DateInput/index.js +1 -0
  65. package/dist/molecules/EmptyState/EmptyState.d.ts +19 -0
  66. package/dist/molecules/EmptyState/EmptyState.js +7 -0
  67. package/dist/molecules/EmptyState/index.d.ts +1 -0
  68. package/dist/molecules/EmptyState/index.js +1 -0
  69. package/dist/molecules/ErrorState/ErrorState.d.ts +18 -0
  70. package/dist/molecules/ErrorState/ErrorState.js +12 -0
  71. package/dist/molecules/ErrorState/index.d.ts +1 -0
  72. package/dist/molecules/ErrorState/index.js +1 -0
  73. package/dist/molecules/ErrorSummary/ErrorSummary.d.ts +25 -0
  74. package/dist/molecules/ErrorSummary/ErrorSummary.js +32 -0
  75. package/dist/molecules/ErrorSummary/index.d.ts +1 -0
  76. package/dist/molecules/ErrorSummary/index.js +1 -0
  77. package/dist/molecules/FilterChips/FilterChips.d.ts +10 -0
  78. package/dist/molecules/FilterChips/FilterChips.js +13 -0
  79. package/dist/molecules/FilterChips/index.d.ts +1 -0
  80. package/dist/molecules/FilterChips/index.js +1 -0
  81. package/dist/molecules/FilterPopover/FilterPopover.d.ts +27 -0
  82. package/dist/molecules/FilterPopover/FilterPopover.js +32 -0
  83. package/dist/molecules/FilterPopover/index.d.ts +1 -0
  84. package/dist/molecules/FilterPopover/index.js +1 -0
  85. package/dist/molecules/FormActions/FormActions.d.ts +16 -0
  86. package/dist/molecules/FormActions/FormActions.js +5 -0
  87. package/dist/molecules/FormActions/index.d.ts +1 -0
  88. package/dist/molecules/FormActions/index.js +1 -0
  89. package/dist/molecules/FormField/FormField.d.ts +52 -0
  90. package/dist/molecules/FormField/FormField.js +63 -0
  91. package/dist/molecules/FormField/index.d.ts +1 -0
  92. package/dist/molecules/FormField/index.js +1 -0
  93. package/dist/molecules/FormSection/FormSection.d.ts +14 -0
  94. package/dist/molecules/FormSection/FormSection.js +10 -0
  95. package/dist/molecules/FormSection/index.d.ts +1 -0
  96. package/dist/molecules/FormSection/index.js +1 -0
  97. package/dist/molecules/KeyValueList/KeyValueList.d.ts +22 -0
  98. package/dist/molecules/KeyValueList/KeyValueList.js +9 -0
  99. package/dist/molecules/KeyValueList/index.d.ts +1 -0
  100. package/dist/molecules/KeyValueList/index.js +1 -0
  101. package/dist/molecules/LoadingState/LoadingState.d.ts +20 -0
  102. package/dist/molecules/LoadingState/LoadingState.js +22 -0
  103. package/dist/molecules/LoadingState/index.d.ts +1 -0
  104. package/dist/molecules/LoadingState/index.js +1 -0
  105. package/dist/molecules/NavItem/NavItem.d.ts +31 -0
  106. package/dist/molecules/NavItem/NavItem.js +72 -0
  107. package/dist/molecules/NavItem/context.d.ts +14 -0
  108. package/dist/molecules/NavItem/context.js +5 -0
  109. package/dist/molecules/NavItem/index.d.ts +1 -0
  110. package/dist/molecules/NavItem/index.js +1 -0
  111. package/dist/molecules/Pagination/Pagination.d.ts +32 -0
  112. package/dist/molecules/Pagination/Pagination.js +57 -0
  113. package/dist/molecules/Pagination/index.d.ts +1 -0
  114. package/dist/molecules/Pagination/index.js +1 -0
  115. package/dist/molecules/PasswordInput/PasswordInput.d.ts +14 -0
  116. package/dist/molecules/PasswordInput/PasswordInput.js +16 -0
  117. package/dist/molecules/PasswordInput/index.d.ts +1 -0
  118. package/dist/molecules/PasswordInput/index.js +1 -0
  119. package/dist/molecules/SearchField/SearchField.d.ts +24 -0
  120. package/dist/molecules/SearchField/SearchField.js +58 -0
  121. package/dist/molecules/SearchField/index.d.ts +1 -0
  122. package/dist/molecules/SearchField/index.js +1 -0
  123. package/dist/molecules/StatGroup/StatGroup.d.ts +21 -0
  124. package/dist/molecules/StatGroup/StatGroup.js +10 -0
  125. package/dist/molecules/StatGroup/index.d.ts +1 -0
  126. package/dist/molecules/StatGroup/index.js +1 -0
  127. package/dist/molecules/ThemeToggle/ThemeToggle.d.ts +23 -0
  128. package/dist/molecules/ThemeToggle/ThemeToggle.js +26 -0
  129. package/dist/molecules/ThemeToggle/index.d.ts +1 -0
  130. package/dist/molecules/ThemeToggle/index.js +1 -0
  131. package/dist/molecules/UserMenu/UserMenu.d.ts +20 -0
  132. package/dist/molecules/UserMenu/UserMenu.js +14 -0
  133. package/dist/molecules/UserMenu/index.d.ts +1 -0
  134. package/dist/molecules/UserMenu/index.js +1 -0
  135. package/dist/molecules/index.d.ts +21 -0
  136. package/dist/molecules/index.js +21 -0
  137. package/dist/organisms/AppShell/AppShell.d.ts +29 -0
  138. package/dist/organisms/AppShell/AppShell.js +34 -0
  139. package/dist/organisms/AppShell/context.d.ts +14 -0
  140. package/dist/organisms/AppShell/context.js +6 -0
  141. package/dist/organisms/AppShell/index.d.ts +1 -0
  142. package/dist/organisms/AppShell/index.js +1 -0
  143. package/dist/organisms/AuthForms/AuthForms.d.ts +83 -0
  144. package/dist/organisms/AuthForms/AuthForms.js +57 -0
  145. package/dist/organisms/AuthForms/index.d.ts +2 -0
  146. package/dist/organisms/AuthForms/index.js +1 -0
  147. package/dist/organisms/AuthForms/shared.d.ts +36 -0
  148. package/dist/organisms/AuthForms/shared.js +36 -0
  149. package/dist/organisms/BulkActionBar/BulkActionBar.d.ts +25 -0
  150. package/dist/organisms/BulkActionBar/BulkActionBar.js +18 -0
  151. package/dist/organisms/BulkActionBar/index.d.ts +1 -0
  152. package/dist/organisms/BulkActionBar/index.js +1 -0
  153. package/dist/organisms/Chart/CategoryCharts.d.ts +34 -0
  154. package/dist/organisms/Chart/CategoryCharts.js +93 -0
  155. package/dist/organisms/Chart/ChartFrame.d.ts +26 -0
  156. package/dist/organisms/Chart/ChartFrame.js +18 -0
  157. package/dist/organisms/Chart/DonutChart.d.ts +25 -0
  158. package/dist/organisms/Chart/DonutChart.js +53 -0
  159. package/dist/organisms/Chart/Sparkline.d.ts +15 -0
  160. package/dist/organisms/Chart/Sparkline.js +18 -0
  161. package/dist/organisms/Chart/index.d.ts +5 -0
  162. package/dist/organisms/Chart/index.js +5 -0
  163. package/dist/organisms/Chart/shared.d.ts +51 -0
  164. package/dist/organisms/Chart/shared.js +113 -0
  165. package/dist/organisms/DataTable/DataTable.d.ts +63 -0
  166. package/dist/organisms/DataTable/DataTable.js +119 -0
  167. package/dist/organisms/DataTable/index.d.ts +3 -0
  168. package/dist/organisms/DataTable/index.js +3 -0
  169. package/dist/organisms/DataTable/types.d.ts +39 -0
  170. package/dist/organisms/DataTable/types.js +1 -0
  171. package/dist/organisms/DataTable/useClientTable.d.ts +27 -0
  172. package/dist/organisms/DataTable/useClientTable.js +51 -0
  173. package/dist/organisms/DateRangePicker/DateRangePicker.d.ts +43 -0
  174. package/dist/organisms/DateRangePicker/DateRangePicker.js +54 -0
  175. package/dist/organisms/DateRangePicker/index.d.ts +1 -0
  176. package/dist/organisms/DateRangePicker/index.js +1 -0
  177. package/dist/organisms/FilterBar/FilterBar.d.ts +28 -0
  178. package/dist/organisms/FilterBar/FilterBar.js +16 -0
  179. package/dist/organisms/FilterBar/index.d.ts +1 -0
  180. package/dist/organisms/FilterBar/index.js +1 -0
  181. package/dist/organisms/PageHeader/PageHeader.d.ts +31 -0
  182. package/dist/organisms/PageHeader/PageHeader.js +19 -0
  183. package/dist/organisms/PageHeader/index.d.ts +1 -0
  184. package/dist/organisms/PageHeader/index.js +1 -0
  185. package/dist/organisms/PageTabs/PageTabs.d.ts +27 -0
  186. package/dist/organisms/PageTabs/PageTabs.js +31 -0
  187. package/dist/organisms/PageTabs/index.d.ts +1 -0
  188. package/dist/organisms/PageTabs/index.js +1 -0
  189. package/dist/organisms/Sidebar/Sidebar.d.ts +48 -0
  190. package/dist/organisms/Sidebar/Sidebar.js +61 -0
  191. package/dist/organisms/Sidebar/index.d.ts +1 -0
  192. package/dist/organisms/Sidebar/index.js +1 -0
  193. package/dist/organisms/Topbar/Topbar.d.ts +24 -0
  194. package/dist/organisms/Topbar/Topbar.js +18 -0
  195. package/dist/organisms/Topbar/index.d.ts +1 -0
  196. package/dist/organisms/Topbar/index.js +1 -0
  197. package/dist/organisms/index.d.ts +11 -0
  198. package/dist/organisms/index.js +11 -0
  199. package/dist/strings.d.ts +108 -15
  200. package/dist/strings.js +73 -7
  201. package/dist/templates/AdminLayout/AdminLayout.d.ts +14 -0
  202. package/dist/templates/AdminLayout/AdminLayout.js +9 -0
  203. package/dist/templates/AdminLayout/index.d.ts +1 -0
  204. package/dist/templates/AdminLayout/index.js +1 -0
  205. package/dist/templates/AuthLayout/AuthLayout.d.ts +28 -0
  206. package/dist/templates/AuthLayout/AuthLayout.js +11 -0
  207. package/dist/templates/AuthLayout/index.d.ts +1 -0
  208. package/dist/templates/AuthLayout/index.js +1 -0
  209. package/dist/templates/DashboardPage/DashboardPage.d.ts +25 -0
  210. package/dist/templates/DashboardPage/DashboardPage.js +12 -0
  211. package/dist/templates/DashboardPage/index.d.ts +1 -0
  212. package/dist/templates/DashboardPage/index.js +1 -0
  213. package/dist/templates/DetailPage/DetailPage.d.ts +20 -0
  214. package/dist/templates/DetailPage/DetailPage.js +11 -0
  215. package/dist/templates/DetailPage/index.d.ts +1 -0
  216. package/dist/templates/DetailPage/index.js +1 -0
  217. package/dist/templates/FormPage/FormPage.d.ts +26 -0
  218. package/dist/templates/FormPage/FormPage.js +11 -0
  219. package/dist/templates/FormPage/index.d.ts +1 -0
  220. package/dist/templates/FormPage/index.js +1 -0
  221. package/dist/templates/ListPage/ListPage.d.ts +17 -0
  222. package/dist/templates/ListPage/ListPage.js +8 -0
  223. package/dist/templates/ListPage/index.d.ts +1 -0
  224. package/dist/templates/ListPage/index.js +1 -0
  225. package/dist/templates/SettingsPage/SettingsPage.d.ts +32 -0
  226. package/dist/templates/SettingsPage/SettingsPage.js +13 -0
  227. package/dist/templates/SettingsPage/index.d.ts +1 -0
  228. package/dist/templates/SettingsPage/index.js +1 -0
  229. package/dist/templates/StatusPage/StatusPage.d.ts +18 -0
  230. package/dist/templates/StatusPage/StatusPage.js +8 -0
  231. package/dist/templates/StatusPage/index.d.ts +1 -0
  232. package/dist/templates/StatusPage/index.js +1 -0
  233. package/dist/templates/index.d.ts +8 -0
  234. package/dist/templates/index.js +8 -0
  235. package/dist/utils/dates.d.ts +67 -0
  236. package/dist/utils/dates.js +154 -0
  237. package/dist/utils/index.d.ts +1 -0
  238. package/dist/utils/index.js +1 -0
  239. package/dist/utils/theme.d.ts +4 -0
  240. package/dist/utils/theme.js +7 -3
  241. package/package.json +4 -1
  242. package/tokens.css +494 -21
@@ -0,0 +1,8 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * A page that is mostly one list: header, toolbar, the list, and its bulk-action bar, in that
4
+ * order and spacing. Slots only; the data and its state belong to the app.
5
+ */
6
+ export function ListPage({ header, toolbar, children, bulkActions, className }) {
7
+ return (_jsxs("div", { className: ['ui-list-page', className].filter(Boolean).join(' '), children: [header, toolbar, children, bulkActions] }));
8
+ }
@@ -0,0 +1 @@
1
+ export * from './ListPage.js';
@@ -0,0 +1 @@
1
+ export * from './ListPage.js';
@@ -0,0 +1,32 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { RenderLink } from '../../atoms/TextLink/TextLink.js';
3
+ export interface SettingsSection {
4
+ id: string;
5
+ label: string;
6
+ icon?: ReactNode;
7
+ href?: string;
8
+ render?: RenderLink;
9
+ }
10
+ export interface SettingsPageProps {
11
+ /** A PageHeader. */
12
+ header?: ReactNode;
13
+ sections: SettingsSection[];
14
+ /** The current section's id. */
15
+ value: string;
16
+ /**
17
+ * Called with a section id. Required for small screens, where the section list is a select
18
+ * and there is no link to follow.
19
+ */
20
+ onValueChange: (id: string) => void;
21
+ /** Names the section navigation ("Settings sections"). */
22
+ navLabel: string;
23
+ /** The current section's content. */
24
+ children: ReactNode;
25
+ className?: string;
26
+ }
27
+ /**
28
+ * Settings split into sections. From 768px of page width: a sticky list of sections beside the
29
+ * content. Narrower: a select above it, which costs one row instead of a screenful of links.
30
+ * Both are rendered and CSS shows one; the hidden one is out of the accessibility tree.
31
+ */
32
+ export declare function SettingsPage({ header, sections, value, onValueChange, navLabel, children, className, }: SettingsPageProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from 'react';
3
+ import { Select } from '../../atoms/Select/Select.js';
4
+ import { NavItem } from '../../molecules/NavItem/NavItem.js';
5
+ /**
6
+ * Settings split into sections. From 768px of page width: a sticky list of sections beside the
7
+ * content. Narrower: a select above it, which costs one row instead of a screenful of links.
8
+ * Both are rendered and CSS shows one; the hidden one is out of the accessibility tree.
9
+ */
10
+ export function SettingsPage({ header, sections, value, onValueChange, navLabel, children, className, }) {
11
+ const selectId = useId();
12
+ return (_jsxs("div", { className: ['ui-settings ui-list-page', className].filter(Boolean).join(' '), children: [header, _jsxs("div", { className: "ui-settings__grid", children: [_jsxs("nav", { "aria-label": navLabel, children: [_jsx("ul", { className: "ui-settings__list", children: sections.map((s) => (_jsx(NavItem, { label: s.label, icon: s.icon, href: s.href, render: s.render, active: s.id === value, onClick: () => onValueChange(s.id) }, s.id))) }), _jsxs("div", { className: "ui-settings__select", children: [_jsx("label", { htmlFor: selectId, className: "ui-sr-only", children: navLabel }), _jsx(Select, { id: selectId, value: value, onValueChange: onValueChange, options: sections.map((s) => ({ value: s.id, label: s.label })) })] })] }), _jsx("div", { className: "min-w-0", children: children })] })] }));
13
+ }
@@ -0,0 +1 @@
1
+ export * from './SettingsPage.js';
@@ -0,0 +1 @@
1
+ export * from './SettingsPage.js';
@@ -0,0 +1,18 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface StatusPageProps {
3
+ /** "404", "403", "500". Decorative: the title says what happened. */
4
+ code?: string;
5
+ /** The page's `h1`: "Page not found". */
6
+ title: ReactNode;
7
+ description?: ReactNode;
8
+ /** The way out: a link home, a sign-in button. */
9
+ action?: ReactNode;
10
+ /** A logo above everything. */
11
+ brand?: ReactNode;
12
+ className?: string;
13
+ }
14
+ /**
15
+ * A full-screen page for not-found, forbidden, server-error and maintenance. Stands on its own,
16
+ * outside the AppShell, since the shell may be what failed.
17
+ */
18
+ export declare function StatusPage({ code, title, description, action, brand, className, }: StatusPageProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * A full-screen page for not-found, forbidden, server-error and maintenance. Stands on its own,
4
+ * outside the AppShell, since the shell may be what failed.
5
+ */
6
+ export function StatusPage({ code, title, description, action, brand, className, }) {
7
+ return (_jsx("main", { className: ['ui-status-page', className].filter(Boolean).join(' '), children: _jsxs("div", { className: "ui-state", children: [brand, code ? (_jsx("p", { className: "ui-status-page__code", "aria-hidden": "true", children: code })) : null, _jsx("h1", { className: "ui-state__title", children: title }), description ? _jsx("p", { className: "ui-state__description", children: description }) : null, action ? _jsx("div", { className: "ui-state__actions", children: action }) : null] }) }));
8
+ }
@@ -0,0 +1 @@
1
+ export * from './StatusPage.js';
@@ -0,0 +1 @@
1
+ export * from './StatusPage.js';
@@ -0,0 +1,8 @@
1
+ export * from './AdminLayout/index.js';
2
+ export * from './AuthLayout/index.js';
3
+ export * from './DashboardPage/index.js';
4
+ export * from './DetailPage/index.js';
5
+ export * from './FormPage/index.js';
6
+ export * from './ListPage/index.js';
7
+ export * from './SettingsPage/index.js';
8
+ export * from './StatusPage/index.js';
@@ -0,0 +1,8 @@
1
+ export * from './AdminLayout/index.js';
2
+ export * from './AuthLayout/index.js';
3
+ export * from './DashboardPage/index.js';
4
+ export * from './DetailPage/index.js';
5
+ export * from './FormPage/index.js';
6
+ export * from './ListPage/index.js';
7
+ export * from './SettingsPage/index.js';
8
+ export * from './StatusPage/index.js';
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Calendar-date arithmetic for the date components.
3
+ *
4
+ * **Dates, not instants.** A birthday or a due date is a day on a calendar, the same day in
5
+ * every time zone, so it travels as an ISO `YYYY-MM-DD` string and all arithmetic happens in
6
+ * UTC, where days are always 24 hours. That is what keeps a date from shifting by one when the
7
+ * clocks change or when the browser is east or west of Greenwich. Formatting goes through
8
+ * `Intl.DateTimeFormat` with `timeZone: 'UTC'` for the same reason.
9
+ *
10
+ * ISO date strings also sort and compare correctly as plain strings.
11
+ */
12
+ /** A calendar date as `YYYY-MM-DD`. */
13
+ export type IsoDate = string;
14
+ export interface DateRange {
15
+ from: IsoDate;
16
+ /** `null` while only the first end has been chosen. */
17
+ to: IsoDate | null;
18
+ }
19
+ /** 0 = Sunday … 6 = Saturday, as `Date.getUTCDay()`. */
20
+ export type Weekday = 0 | 1 | 2 | 3 | 4 | 5 | 6;
21
+ /** The parts of a valid ISO date, or `null` (including for impossible dates like 2026-02-30). */
22
+ export declare function parseIsoDate(value: string): {
23
+ year: number;
24
+ month: number;
25
+ day: number;
26
+ } | null;
27
+ export declare function isIsoDate(value: unknown): value is IsoDate;
28
+ /** `month` is 1–12. */
29
+ export declare function toIsoDate(year: number, month: number, day: number): IsoDate;
30
+ /** `month` is 1–12. */
31
+ export declare function daysInMonth(year: number, month: number): number;
32
+ export declare function addDays(iso: IsoDate, days: number): IsoDate;
33
+ /** Adds whole months, clamping the day: 31 January plus one month is 28 or 29 February. */
34
+ export declare function addMonths(iso: IsoDate, months: number): IsoDate;
35
+ export declare function weekdayOf(iso: IsoDate): Weekday;
36
+ export declare function startOfMonth(iso: IsoDate): IsoDate;
37
+ export declare function endOfMonth(iso: IsoDate): IsoDate;
38
+ export declare function startOfWeek(iso: IsoDate, weekStartsOn: Weekday): IsoDate;
39
+ export declare function endOfWeek(iso: IsoDate, weekStartsOn: Weekday): IsoDate;
40
+ /** Same month and year. */
41
+ export declare function isSameMonth(a: IsoDate, b: IsoDate): boolean;
42
+ /** `value` clamped into `[min, max]`; either bound may be absent. */
43
+ export declare function clampDate(value: IsoDate, min?: IsoDate | null, max?: IsoDate | null): IsoDate;
44
+ /** Whether `iso` lies in the range, ends included. An open range covers only its start. */
45
+ export declare function isInRange(iso: IsoDate, range: DateRange | null | undefined): boolean;
46
+ /**
47
+ * The weeks of a month for a calendar grid: always six rows of seven, so a calendar does not
48
+ * change height between months. Days outside the month are `null`.
49
+ */
50
+ export declare function monthGrid(year: number, month: number, weekStartsOn: Weekday): (IsoDate | null)[][];
51
+ /** The local date today, as the person at the screen sees it. */
52
+ export declare function todayIso(now?: Date): IsoDate;
53
+ /**
54
+ * The first day of the week where `locale` is used, from the platform's CLDR data
55
+ * (`Intl.Locale#getWeekInfo`, or the older `weekInfo` getter). Monday, the ISO 8601 week,
56
+ * where neither exists.
57
+ */
58
+ export declare function firstDayOfWeek(locale?: string): Weekday;
59
+ /** Formats a calendar date in `locale`, without any time-zone shift. */
60
+ export declare function formatIsoDate(iso: IsoDate, locale?: string, options?: Intl.DateTimeFormatOptions): string;
61
+ /** "1–30 Sep 2026", in `locale`'s own way of writing a range. */
62
+ export declare function formatDateRange(range: DateRange, locale?: string, options?: Intl.DateTimeFormatOptions): string;
63
+ /** Weekday names in grid order, e.g. `['Mon', …]`, plus their full forms for `abbr`. */
64
+ export declare function weekdayNames(locale: string | undefined, weekStartsOn: Weekday): {
65
+ short: string;
66
+ long: string;
67
+ }[];
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Calendar-date arithmetic for the date components.
3
+ *
4
+ * **Dates, not instants.** A birthday or a due date is a day on a calendar, the same day in
5
+ * every time zone, so it travels as an ISO `YYYY-MM-DD` string and all arithmetic happens in
6
+ * UTC, where days are always 24 hours. That is what keeps a date from shifting by one when the
7
+ * clocks change or when the browser is east or west of Greenwich. Formatting goes through
8
+ * `Intl.DateTimeFormat` with `timeZone: 'UTC'` for the same reason.
9
+ *
10
+ * ISO date strings also sort and compare correctly as plain strings.
11
+ */
12
+ const ISO = /^(\d{4})-(\d{2})-(\d{2})$/;
13
+ /** The parts of a valid ISO date, or `null` (including for impossible dates like 2026-02-30). */
14
+ export function parseIsoDate(value) {
15
+ const m = ISO.exec(value);
16
+ if (!m)
17
+ return null;
18
+ const year = Number(m[1]);
19
+ const month = Number(m[2]);
20
+ const day = Number(m[3]);
21
+ if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month))
22
+ return null;
23
+ return { year, month, day };
24
+ }
25
+ export function isIsoDate(value) {
26
+ return typeof value === 'string' && parseIsoDate(value) !== null;
27
+ }
28
+ /** `month` is 1–12. */
29
+ export function toIsoDate(year, month, day) {
30
+ const d = new Date(Date.UTC(year, month - 1, day));
31
+ return d.toISOString().slice(0, 10);
32
+ }
33
+ /** `month` is 1–12. */
34
+ export function daysInMonth(year, month) {
35
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
36
+ }
37
+ function toUtc(iso) {
38
+ const p = parseIsoDate(iso);
39
+ if (!p)
40
+ throw new RangeError(`Not an ISO date: ${iso}`);
41
+ return new Date(Date.UTC(p.year, p.month - 1, p.day));
42
+ }
43
+ export function addDays(iso, days) {
44
+ const d = toUtc(iso);
45
+ d.setUTCDate(d.getUTCDate() + days);
46
+ return d.toISOString().slice(0, 10);
47
+ }
48
+ /** Adds whole months, clamping the day: 31 January plus one month is 28 or 29 February. */
49
+ export function addMonths(iso, months) {
50
+ const p = parseIsoDate(iso);
51
+ if (!p)
52
+ throw new RangeError(`Not an ISO date: ${iso}`);
53
+ const index = p.year * 12 + (p.month - 1) + months;
54
+ const year = Math.floor(index / 12);
55
+ const month = (((index % 12) + 12) % 12) + 1;
56
+ return toIsoDate(year, month, Math.min(p.day, daysInMonth(year, month)));
57
+ }
58
+ export function weekdayOf(iso) {
59
+ return toUtc(iso).getUTCDay();
60
+ }
61
+ export function startOfMonth(iso) {
62
+ return `${iso.slice(0, 7)}-01`;
63
+ }
64
+ export function endOfMonth(iso) {
65
+ const p = parseIsoDate(iso);
66
+ if (!p)
67
+ throw new RangeError(`Not an ISO date: ${iso}`);
68
+ return toIsoDate(p.year, p.month, daysInMonth(p.year, p.month));
69
+ }
70
+ export function startOfWeek(iso, weekStartsOn) {
71
+ return addDays(iso, -((weekdayOf(iso) - weekStartsOn + 7) % 7));
72
+ }
73
+ export function endOfWeek(iso, weekStartsOn) {
74
+ return addDays(startOfWeek(iso, weekStartsOn), 6);
75
+ }
76
+ /** Same month and year. */
77
+ export function isSameMonth(a, b) {
78
+ return a.slice(0, 7) === b.slice(0, 7);
79
+ }
80
+ /** `value` clamped into `[min, max]`; either bound may be absent. */
81
+ export function clampDate(value, min, max) {
82
+ if (min && value < min)
83
+ return min;
84
+ if (max && value > max)
85
+ return max;
86
+ return value;
87
+ }
88
+ /** Whether `iso` lies in the range, ends included. An open range covers only its start. */
89
+ export function isInRange(iso, range) {
90
+ if (!range)
91
+ return false;
92
+ const to = range.to ?? range.from;
93
+ return iso >= range.from && iso <= to;
94
+ }
95
+ /**
96
+ * The weeks of a month for a calendar grid: always six rows of seven, so a calendar does not
97
+ * change height between months. Days outside the month are `null`.
98
+ */
99
+ export function monthGrid(year, month, weekStartsOn) {
100
+ const first = toIsoDate(year, month, 1);
101
+ let cursor = startOfWeek(first, weekStartsOn);
102
+ const weeks = [];
103
+ for (let w = 0; w < 6; w++) {
104
+ const week = [];
105
+ for (let d = 0; d < 7; d++) {
106
+ week.push(isSameMonth(cursor, first) ? cursor : null);
107
+ cursor = addDays(cursor, 1);
108
+ }
109
+ weeks.push(week);
110
+ }
111
+ return weeks;
112
+ }
113
+ /** The local date today, as the person at the screen sees it. */
114
+ export function todayIso(now = new Date()) {
115
+ return toIsoDate(now.getFullYear(), now.getMonth() + 1, now.getDate());
116
+ }
117
+ /**
118
+ * The first day of the week where `locale` is used, from the platform's CLDR data
119
+ * (`Intl.Locale#getWeekInfo`, or the older `weekInfo` getter). Monday, the ISO 8601 week,
120
+ * where neither exists.
121
+ */
122
+ export function firstDayOfWeek(locale) {
123
+ try {
124
+ const loc = new Intl.Locale(locale ?? new Intl.DateTimeFormat().resolvedOptions().locale);
125
+ const info = loc.getWeekInfo?.() ?? loc.weekInfo;
126
+ if (info?.firstDay)
127
+ return (info.firstDay % 7);
128
+ }
129
+ catch {
130
+ // An unknown tag falls through to the ISO week.
131
+ }
132
+ return 1;
133
+ }
134
+ /** Formats a calendar date in `locale`, without any time-zone shift. */
135
+ export function formatIsoDate(iso, locale, options = { dateStyle: 'medium' }) {
136
+ return new Intl.DateTimeFormat(locale, { ...options, timeZone: 'UTC' }).format(toUtc(iso));
137
+ }
138
+ /** "1–30 Sep 2026", in `locale`'s own way of writing a range. */
139
+ export function formatDateRange(range, locale, options = { dateStyle: 'medium' }) {
140
+ const fmt = new Intl.DateTimeFormat(locale, { ...options, timeZone: 'UTC' });
141
+ if (!range.to || range.to === range.from)
142
+ return fmt.format(toUtc(range.from));
143
+ return fmt.formatRange(toUtc(range.from), toUtc(range.to));
144
+ }
145
+ /** Weekday names in grid order, e.g. `['Mon', …]`, plus their full forms for `abbr`. */
146
+ export function weekdayNames(locale, weekStartsOn) {
147
+ const short = new Intl.DateTimeFormat(locale, { weekday: 'short', timeZone: 'UTC' });
148
+ const long = new Intl.DateTimeFormat(locale, { weekday: 'long', timeZone: 'UTC' });
149
+ // 2023-01-01 was a Sunday.
150
+ return Array.from({ length: 7 }, (_, i) => {
151
+ const d = new Date(Date.UTC(2023, 0, 1 + ((weekStartsOn + i) % 7)));
152
+ return { short: short.format(d), long: long.format(d) };
153
+ });
154
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './cn.js';
2
+ export * from './dates.js';
2
3
  export * from './theme.js';
@@ -1,2 +1,3 @@
1
1
  export * from './cn.js';
2
+ export * from './dates.js';
2
3
  export * from './theme.js';
@@ -95,7 +95,11 @@ export interface Theming<A extends readonly string[]> {
95
95
  * a tuple and will be rejected: either inline it or write `as const` there.
96
96
  */
97
97
  export declare function createTheming<const A extends readonly [string, ...string[]]>(config: ThemingConfig<A>): Theming<A>;
98
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `readTheme`. Removed in 2.0. */
98
99
  export declare const readTheme: () => Theme;
100
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `storeTheme`. Removed in 2.0. */
99
101
  export declare const storeTheme: (theme: Theme) => void;
102
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `readAccent`. Removed in 2.0. */
100
103
  export declare const readAccent: () => "red" | "yellow" | "orange" | "purple" | "blue" | "jade";
104
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `storeAccent`. Removed in 2.0. */
101
105
  export declare const storeAccent: (accent: "red" | "yellow" | "orange" | "purple" | "blue" | "jade") => void;
@@ -118,18 +118,22 @@ export function createTheming(config) {
118
118
  }
119
119
  /**
120
120
  * The instance the original free functions are bound to: the six default accents, jade, and the
121
- * `upfront.*` storage keys the apps that predate `createTheming` already wrote.
121
+ * storage prefix that apps written before `createTheming` already have keys under.
122
122
  *
123
123
  * **One implementation, not two.** These exports exist so no call site had to change when the
124
- * factory landed, and keeping the prefix is what stops an existing user losing the theme they
125
- * picked. A new product should call `createTheming` with its own name instead.
124
+ * factory landed. The prefix is legacy and must not change in 1.x, because changing it would
125
+ * lose every existing user's saved theme. New code calls `createTheming` with its own prefix.
126
126
  */
127
127
  const legacy = createTheming({
128
128
  accents: DEFAULT_ACCENTS,
129
129
  defaultAccent: 'jade',
130
130
  storagePrefix: 'upfront',
131
131
  });
132
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `readTheme`. Removed in 2.0. */
132
133
  export const readTheme = legacy.readTheme;
134
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `storeTheme`. Removed in 2.0. */
133
135
  export const storeTheme = legacy.storeTheme;
136
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `readAccent`. Removed in 2.0. */
134
137
  export const readAccent = legacy.readAccent;
138
+ /** @deprecated Use `createTheming({ storagePrefix })` and its `storeAccent`. Removed in 2.0. */
135
139
  export const storeAccent = legacy.storeAccent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kennycorrea/ui",
3
- "version": "0.11.4",
3
+ "version": "1.6.1",
4
4
  "description": "A React + TypeScript component library built on Radix Themes: atoms, a Tailwind token bridge and theming.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -13,6 +13,9 @@
13
13
  ],
14
14
  "main": "./dist/index.js",
15
15
  "types": "./dist/index.d.ts",
16
+ "sideEffects": [
17
+ "*.css"
18
+ ],
16
19
  "exports": {
17
20
  ".": {
18
21
  "types": "./dist/index.d.ts",