@jirawatpyk/aura-react 4.15.0 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,13 +41,15 @@ npm i @jirawatpyk/aura-react @jirawatpyk/aura-tokens # React 18 or 19; import
41
41
  npm i @aura/react@npm:@jirawatpyk/aura-react @aura/tokens@npm:@jirawatpyk/aura-tokens
42
42
  ```
43
43
 
44
+ React 18.3 and 19 are both tested: the dev dependencies pin 18, and CI switches the whole workspace to 19 (`node scripts/use-react.mjs 19 && npm install`) and runs every suite again — contrast, token lint, SSR, types, build, hydration with 0 warnings, layout before hydration, the three pilot pages and Storybook (axe + behaviour).
45
+
44
46
  Public on npmjs; internal projects can use GitHub Packages instead ([repository README](https://github.com/Jirawatpyk/Aura-design#use-it-in-a-project)).
45
47
 
46
48
  ```tsx
47
49
  // app root (once)
48
50
  import '@aura/tokens/aura.css'; // tokens (light + dark)
49
51
  import '@aura/react/styles.css'; // component styles
50
- // fonts: Google Fonts <link> tags in <head>, or '@aura/tokens/aura-fonts.css'
52
+ // fonts: '@jirawatpyk/aura-tokens/aura-fonts.local.css' (self-hosted, CSP font-src 'self'), next/font, or Google Fonts — see the tokens README
51
53
 
52
54
  import { AuraProvider, AppShell, SideNav, DataTable, DatePicker } from '@aura/react';
53
55
 
@@ -74,16 +76,31 @@ export default function Root() {
74
76
 
75
77
  ## Components (49)
76
78
 
77
- Actions: Button, IconButton, Menu, DropdownMenu, Tag · Forms: TextField, PasswordField, Textarea, NumberField, Select, RadioGroup, Checkbox, Switch, SegmentedControl, Combobox (one value, or `multiple`), FileUpload (+ `formatBytes`) · Dates & times: DatePicker, DateRangePicker, Calendar, TimePicker (+ `useFormatDate`, `formatDate`, `parseDate`, `parseTime`) · Feedback: Alert, FormErrorSummary, Toaster/`toast()` (+ `.success/.error/.warning/.info/.loading`), Tooltip, StatusPill, Badge, Progress, Skeleton, EmptyState · Overlays: Dialog, Drawer, Popover · Data: DataTable, FilterBar, Stat · Navigation: Command (⌘K palette) · Layout: AppShell, Container, Stack, Grid, Accordion, Pagination, Card, Tabs, Stepper, SideNav, Breadcrumb, Avatar, Surface, Icon · Theme: ColorSchemeToggle, ColorSchemeScript, `useColorScheme`, ThemeStyle/`createTheme` · Hooks: `useBreakpoint`, `useResponsive`, `breakpoints`, `useAuraLocale`, `useDensity`.
79
+ Actions: Button (`ghost`, `size="sm"`), IconButton, Menu, DropdownMenu, Tag · Forms: TextField, PasswordField, Textarea, NumberField, Select, RadioGroup, Checkbox, Switch, SegmentedControl, Combobox (one value, or `multiple`), FileUpload (+ `formatBytes`) · Dates & times: DatePicker, DateRangePicker, Calendar, TimePicker (+ `useFormatDate`, `formatDate`, `parseDate`, `parseTime`) · Feedback: Alert, FormErrorSummary, Toaster/`toast()` (+ `.success/.error/.warning/.info/.loading`), Tooltip, StatusPill, Badge, Progress, Skeleton, EmptyState · Overlays: Dialog, Drawer, Popover · Data: DataTable, FilterBar, Stat · Navigation: Command (⌘K palette) · Layout: AppShell, Container, Stack, Grid, Accordion, Pagination, Card, Tabs, Stepper, SideNav, Breadcrumb, Avatar, Surface, Icon · Theme: ColorSchemeToggle, ColorSchemeScript, `useColorScheme`, ThemeStyle/`createTheme` · Hooks: `useBreakpoint`, `useResponsive`, `breakpoints`, `useAuraLocale`, `useDensity`.
78
80
 
79
81
  ## Router links, Swedish, motion
80
82
 
83
+ Next.js App Router: `next/link` is a function, and a Server Component (your layout) can't pass functions to a client component. Put the provider in a small `'use client'` file:
84
+
81
85
  ```tsx
86
+ // app/providers.tsx
87
+ 'use client';
82
88
  import Link from 'next/link';
83
- <AuraProvider locale="sv" linkComponent={Link}> {/* th | en | sv */}
89
+ import { AuraProvider } from '@jirawatpyk/aura-react';
90
+ export function Providers({ children, locale }: { children: React.ReactNode; locale: 'th' | 'en' | 'sv' }) {
91
+ return (
92
+ <AuraProvider locale={locale} linkComponent={Link}>
93
+ {children}
94
+ </AuraProvider>
95
+ );
96
+ {
97
+ /* th | en | sv */
98
+ }
99
+ }
100
+ // app/layout.tsx (a Server Component): <body><Providers locale="th">{children}</Providers></body>
84
101
  ```
85
102
 
86
- `linkComponent` is used by Button `href`, Breadcrumb, Pagination `getHref`, Stat `href`, SideNav and DataTable row/pager links. Only `th` shows Buddhist-era years; `en` and `sv` are Gregorian (`sv` weeks start Monday). **Without a provider, components are English with Gregorian dates** — wrap Thai apps in `<AuraProvider locale="th">`. For dates in your own components use `useFormatDate()` — it follows the provider (`const fmt = useFormatDate(); fmt(iso, { format: 'long' })`). Plain `formatDate()` has no provider to read and stays Thai unless you pass `locale`. Values are always Gregorian ISO dates.
103
+ `linkComponent` is used by Button `href`, Breadcrumb, Pagination `getHref` (page numbers and, since 4.17, the previous / next arrows), Stat `href`, SideNav and DataTable row/pager links. Each of them also takes its own `linkComponent`, which wins over the provider's. Pass `getHref` from a client component (it's a function too). The Next.js starter does all of this, and CI clicks every AURA link in it to check none triggers a full page load. Only `th` shows Buddhist-era years; `en` and `sv` are Gregorian (`sv` weeks start Monday). **Without a provider, components are English with Gregorian dates** — wrap Thai apps in `<AuraProvider locale="th">`. For dates in your own components use `useFormatDate()` — it follows the provider (`const fmt = useFormatDate(); fmt(iso, { format: 'long' })`). Plain `formatDate()` from the package root has no provider to read and stays Thai unless you pass `locale` (until 5.0); the one in `@jirawatpyk/aura-react/server` defaults to English and Gregorian. Values are always Gregorian ISO dates.
87
104
 
88
105
  ## Compact density
89
106
 
@@ -121,9 +138,30 @@ toast.error('Could not save'); // danger = role="alert"; the rest
121
138
  <Command open={open} onOpenChange={setOpen} items={commands} /> {/* ⌘K / Ctrl+K toggles it */}
122
139
  ```
123
140
 
141
+ Server search in the palette (4.17): control the query and hand over what the server found. The active item is kept by id while results change, and `loading` announces "Searching…" and then the count.
142
+
143
+ ```tsx
144
+ <Command
145
+ open={open}
146
+ onOpenChange={setOpen}
147
+ query={q}
148
+ onQueryChange={setQ} // fetch results for q (debounced)
149
+ items={results}
150
+ filter={false}
151
+ loading={isFetching}
152
+ empty={
153
+ <Button size="sm" icon="plus">
154
+ Create member
155
+ </Button>
156
+ }
157
+ />
158
+ ```
159
+
160
+ DataTable with sort and page in the URL (4.17): `onStateChange={({ sort, page }) => router.push(…)}` reports a sort click once, as `{ sort, page: 1 }`, instead of `onSortChange` and then `onPageChange(1)`. That's one history entry and one server render.
161
+
124
162
  ## Phones and touch
125
163
 
126
- Under 640px every text control uses 16px text (iOS Safari doesn't zoom). On touch screens (`pointer: coarse`) IconButton keeps its 32px look with a 44px hit area, and Radio, Checkbox and Switch rows are at least 44px with the whole row as the target. `<Button fullWidth>` fills its row and wraps long Thai or Swedish labels.
164
+ Under 640px every text control uses 16px text (iOS Safari doesn't zoom). On touch screens (`pointer: coarse`) IconButton and `<Button size="sm">` keep their 32px look with a 44px hit area, and Radio, Checkbox and Switch rows are at least 44px with the whole row as the target. Since 4.17 so are menu items, page numbers, segments and calendar days (44px); Combobox and DatePicker toggles and the Tag remove button get 44px hit areas. A Dialog sheet on a phone is capped at `92dvh`, so the browser toolbar never hides its footer. `<Button fullWidth>` fills its row and wraps long Thai or Swedish labels.
127
165
 
128
166
  ## Light and dark
129
167
 
@@ -159,6 +197,39 @@ Values are ISO strings (`2026-09-18`); with `locale="th"` display is Thai with B
159
197
 
160
198
  Portals (Dialog, Drawer, menus, pickers, toasts) wait until after hydration; `useBreakpoint()` returns `lg` on the server and corrects on the client through `useSyncExternalStore`, so there are no hydration mismatches. `npm run test:ssr` renders every component with `react-dom/server` (ESM and CJS builds).
161
199
 
200
+ Layout is right before hydration (4.16). AppShell's sidebar-or-drawer switch is CSS (a 1024px media query), so a phone gets the menu button from the server's HTML. A DataTable with `stackBelow` renders cards and grid together until it has measured itself, and a container query shows the right one. It supports `stackBelow` 360, 400, 480, 520, 560, 600, 640, 720, 768, 800, 900, 960 and 1024; other widths stack once JavaScript runs. `npm run test:layout` loads both at 390 and 1280px with JavaScript off, then hydrated, and requires CLS 0. Columns with `hideBelow` still settle after hydration.
201
+
202
+ ## Next to another Tailwind theme (shadcn), page by page
203
+
204
+ `styles.css` is unlayered, so it beats utilities. For a migration next to an existing theme, use the layered stylesheet and the prefixed Tailwind theme (4.17):
205
+
206
+ ```css
207
+ @layer aura-tokens, theme, base, aura, components, utilities;
208
+ @import 'tailwindcss';
209
+ @import '@jirawatpyk/aura-tokens/aura.css' layer(aura-tokens); /* your theme wins for --font-sans / --font-mono */
210
+ @import '@jirawatpyk/aura-tokens/tailwind.prefixed.css'; /* bg-aura-bg-surface, font-aura-sans … no @custom-variant */
211
+ @import '@jirawatpyk/aura-react/styles.layer.css'; /* components in @layer aura: a utility className wins */
212
+ ```
213
+
214
+ Nothing an existing page uses is redefined: `npm run check:tailwind4` compiles a shadcn-style page alone and next to this setup, with AURA imported first and last. It checks that the computed styles are identical, and that `rounded-none` overrides `.aura-btn` with no `!important`. While both run, AURA components use your `--font-sans` / `--font-mono`; set them to AURA's stacks in your token bridge when a page moves over.
215
+
216
+ ## Server Components
217
+
218
+ Everything in the package root is a client module (`'use client'`), so a Server Component can render AURA components but can't call AURA functions. The pure helpers have their own entry with no `'use client'` and no React (4.17):
219
+
220
+ ```tsx
221
+ // app/invoices/[id]/page.tsx — a Server Component
222
+ import { formatDate, createTheme, statusTone, STRINGS } from '@jirawatpyk/aura-react/server';
223
+ formatDate('2026-09-24'); // "24 Sept 2026" — English and Gregorian by default
224
+ formatDate('2026-09-24', { locale: 'th' }); // "24 ก.ย. 2569"
225
+ ```
226
+
227
+ It exports `formatDate`, `parseDate`, `toISO`, `fromISO`, `parseTime`, `formatBytes`, `statusTone`, `STRINGS`, `createTheme`, `contrast`, `brandScale`, `colorSchemeScript` and `breakpoints`. `npm run test:ssr` loads it under Node's `react-server` condition, and the Next.js starter formats a date with it in a Server Component.
228
+
229
+ ## TypeScript
230
+
231
+ Every optional prop takes `undefined` (4.16), so apps on `exactOptionalPropertyTypes` can write `hint={t.hint}` or `icon={x ?? undefined}`. `types-test/exact-optional.tsx` checks every exported component against the published declarations under `strict`, `exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`.
232
+
162
233
  ## Scripts
163
234
 
164
235
  ```bash