@nxgt/material 1.0.4 → 1.1.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +447 -51
  3. package/dist/components.js +3 -2
  4. package/dist/{dist-BVcMAlfA.js → dist-CwhEp6Y-.js} +4 -4
  5. package/dist/dnd.js +2 -2
  6. package/dist/{hooks-BPv0i6YN.js → hooks-CHmfdtMs.js} +81 -47
  7. package/dist/hooks.js +3 -3
  8. package/dist/{i18n-1Eg35q8-.js → i18n-D4R3sSqT.js} +102 -0
  9. package/dist/i18n.js +1 -1
  10. package/dist/lib/components/index.d.ts +15 -0
  11. package/dist/lib/components/ui/anchor-heading.d.ts +9 -0
  12. package/dist/lib/components/ui/anchor-heading.stories.d.ts +13 -0
  13. package/dist/lib/components/ui/anchor-heading.utils.d.ts +2 -0
  14. package/dist/lib/components/ui/api-endpoint.d.ts +9 -0
  15. package/dist/lib/components/ui/api-endpoint.stories.d.ts +14 -0
  16. package/dist/lib/components/ui/api-operation.d.ts +13 -0
  17. package/dist/lib/components/ui/api-operation.stories.d.ts +13 -0
  18. package/dist/lib/components/ui/cards/cards.stories.d.ts +20 -0
  19. package/dist/lib/components/ui/cards/cards.stories.data.d.ts +8 -0
  20. package/dist/lib/components/ui/cards/index.d.ts +9 -0
  21. package/dist/lib/components/ui/cards/partials/crew-card.d.ts +2 -0
  22. package/dist/lib/components/ui/cards/partials/feature-card.d.ts +2 -0
  23. package/dist/lib/components/ui/cards/partials/media-card.d.ts +2 -0
  24. package/dist/lib/components/ui/cards/partials/overlay-card.d.ts +2 -0
  25. package/dist/lib/components/ui/cards/partials/pricing-card.d.ts +2 -0
  26. package/dist/lib/components/ui/cards/partials/profile-card.d.ts +2 -0
  27. package/dist/lib/components/ui/cards/partials/quote-card.d.ts +2 -0
  28. package/dist/lib/components/ui/cards/partials/spotlight-card.d.ts +2 -0
  29. package/dist/lib/components/ui/cards/types.d.ts +56 -0
  30. package/dist/lib/components/ui/code/code-group.d.ts +13 -0
  31. package/dist/lib/components/ui/code/code-group.stories.d.ts +14 -0
  32. package/dist/lib/components/ui/code/index.d.ts +2 -0
  33. package/dist/lib/components/ui/copy-button/copy-button.d.ts +5 -3
  34. package/dist/lib/components/ui/doc/doc-api.stories.d.ts +13 -0
  35. package/dist/lib/components/ui/doc/doc-blocks.stories.d.ts +13 -0
  36. package/dist/lib/components/ui/doc/doc-context.d.ts +61 -0
  37. package/dist/lib/components/ui/doc/doc.d.ts +11 -0
  38. package/dist/lib/components/ui/doc/doc.keyboard.d.ts +20 -0
  39. package/dist/lib/components/ui/doc/doc.keyboard.test.d.ts +1 -0
  40. package/dist/lib/components/ui/doc/doc.slice.d.ts +97 -0
  41. package/dist/lib/components/ui/doc/doc.stories.d.ts +15 -0
  42. package/dist/lib/components/ui/doc/doc.stories.data.d.ts +7 -0
  43. package/dist/lib/components/ui/doc/doc.utils.d.ts +29 -0
  44. package/dist/lib/components/ui/doc/doc.utils.test.d.ts +1 -0
  45. package/dist/lib/components/ui/doc/index.d.ts +36 -0
  46. package/dist/lib/components/ui/doc/partials/doc-article.d.ts +6 -0
  47. package/dist/lib/components/ui/doc/partials/doc-child-cards.d.ts +4 -0
  48. package/dist/lib/components/ui/doc/partials/doc-copy-actions.d.ts +7 -0
  49. package/dist/lib/components/ui/doc/partials/doc-empty.d.ts +3 -0
  50. package/dist/lib/components/ui/doc/partials/doc-header.d.ts +18 -0
  51. package/dist/lib/components/ui/doc/partials/doc-link.d.ts +3 -0
  52. package/dist/lib/components/ui/doc/partials/doc-nav.d.ts +4 -0
  53. package/dist/lib/components/ui/doc/partials/doc-page.d.ts +6 -0
  54. package/dist/lib/components/ui/doc/partials/doc-pager.d.ts +4 -0
  55. package/dist/lib/components/ui/doc/partials/doc-progress.d.ts +3 -0
  56. package/dist/lib/components/ui/doc/partials/doc-search.d.ts +1 -0
  57. package/dist/lib/components/ui/doc/partials/doc-see-also.d.ts +4 -0
  58. package/dist/lib/components/ui/doc/partials/doc-sidebar.d.ts +4 -0
  59. package/dist/lib/components/ui/doc/partials/doc-skip-link.d.ts +2 -0
  60. package/dist/lib/components/ui/doc/partials/doc-toc.d.ts +6 -0
  61. package/dist/lib/components/ui/doc/partials/doc-topbar.d.ts +4 -0
  62. package/dist/lib/components/ui/doc/types.d.ts +46 -0
  63. package/dist/lib/components/ui/doc/use-doc.d.ts +43 -0
  64. package/dist/lib/components/ui/feedback/empty-state.stories.d.ts +1 -0
  65. package/dist/lib/components/ui/feedback/index.d.ts +1 -0
  66. package/dist/lib/components/ui/feedback/scroll-progress.d.ts +6 -0
  67. package/dist/lib/components/ui/feedback/scroll-progress.stories.d.ts +13 -0
  68. package/dist/lib/components/ui/figure.d.ts +7 -0
  69. package/dist/lib/components/ui/figure.stories.d.ts +13 -0
  70. package/dist/lib/components/ui/forms/index.d.ts +1 -0
  71. package/dist/lib/components/ui/hero.d.ts +10 -0
  72. package/dist/lib/components/ui/hero.stories.d.ts +13 -0
  73. package/dist/lib/components/ui/highlight-text.d.ts +6 -0
  74. package/dist/lib/components/ui/highlight-text.stories.d.ts +12 -0
  75. package/dist/lib/components/ui/list-tile.d.ts +2 -1
  76. package/dist/lib/components/ui/list-tile.stories.d.ts +1 -0
  77. package/dist/lib/components/ui/metrics/index.d.ts +6 -0
  78. package/dist/lib/components/ui/metrics/metrics.stories.d.ts +16 -0
  79. package/dist/lib/components/ui/metrics/metrics.stories.data.d.ts +5 -0
  80. package/dist/lib/components/ui/metrics/partials/breakdown-card.d.ts +2 -0
  81. package/dist/lib/components/ui/metrics/partials/goal-card.d.ts +2 -0
  82. package/dist/lib/components/ui/metrics/partials/rank-card.d.ts +2 -0
  83. package/dist/lib/components/ui/metrics/partials/sparkline.d.ts +5 -0
  84. package/dist/lib/components/ui/metrics/partials/trend-card.d.ts +2 -0
  85. package/dist/lib/components/ui/metrics/types.d.ts +35 -0
  86. package/dist/lib/components/ui/pager.d.ts +20 -0
  87. package/dist/lib/components/ui/pager.stories.d.ts +13 -0
  88. package/dist/lib/components/ui/param-table.d.ts +13 -0
  89. package/dist/lib/components/ui/param-table.stories.d.ts +13 -0
  90. package/dist/lib/components/ui/see-also.d.ts +17 -0
  91. package/dist/lib/components/ui/see-also.stories.d.ts +12 -0
  92. package/dist/lib/components/ui/skip-link.d.ts +3 -0
  93. package/dist/lib/components/ui/skip-link.stories.d.ts +12 -0
  94. package/dist/lib/components/ui/steps.d.ts +13 -0
  95. package/dist/lib/components/ui/steps.stories.d.ts +13 -0
  96. package/dist/lib/components/ui/tabs.d.ts +4 -1
  97. package/dist/lib/components/ui/tabs.stories.d.ts +1 -0
  98. package/dist/lib/components/ui/toc.d.ts +21 -0
  99. package/dist/lib/components/ui/toc.stories.d.ts +13 -0
  100. package/dist/lib/hooks/index.d.ts +1 -0
  101. package/dist/lib/hooks/use-heading-spy.d.ts +6 -0
  102. package/dist/lib/i18n/resources/en/index.d.ts +57 -0
  103. package/dist/lib/i18n/resources/en/material.json.d.ts +57 -0
  104. package/dist/lib/i18n/resources/fr/index.d.ts +57 -0
  105. package/dist/lib/i18n/resources/fr/material.json.d.ts +57 -0
  106. package/dist/lib/i18n/resources/index.d.ts +114 -0
  107. package/dist/lib/i18n/translator.d.ts +1 -1
  108. package/dist/lib/lib/string.utils.d.ts +9 -0
  109. package/dist/lib/lib/url.utils.d.ts +2 -0
  110. package/dist/{lib-CaKARQ-7.js → lib-Rq5clPUe.js} +620 -584
  111. package/dist/lib.js +3 -3
  112. package/dist/{main-B-cRR76_.js → main-D7WtUVbv.js} +35341 -33380
  113. package/dist/main.js +6 -6
  114. package/dist/material.css +1 -1
  115. package/package.json +2 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Steve Tsala
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -3,14 +3,48 @@
3
3
  React component library: primitives, form fields, layout shell, `DataTable`,
4
4
  drag-and-drop, i18n, and `Icon`. Tailwind CSS v4 + Base UI.
5
5
 
6
+ ## At a glance
7
+
8
+ - **155 catalogue entries in 12 categories** ([Components](#components)).
9
+ They cover primitives and overlays as well as data tables, filters, kanban,
10
+ calendars, charts, chat, documentation pages, rich-text and code editors,
11
+ PDF and media players.
12
+ - **Form fields ship in pairs.** Each one has a standalone component
13
+ (`TextField`) and a React Hook Form wrapper (`TextFormField`). Both are in
14
+ the same barrel.
15
+ - **Helpers** ([Helpers](#helpers)): `cn`, `clientOnly`, date, number,
16
+ storage and URL utilities, a Zod error map, and Redux Toolkit slice
17
+ factories in `/lib`. Theme, i18n-aware formatting and option hooks are in
18
+ `/hooks`.
19
+ - **i18n** ([i18n](#i18n)): an `I18nProvider` with ICU messages and shipped
20
+ `en` / `fr` strings. Your app merges in its own resources.
21
+ - **SSR-safe barrels** ([SSR](#ssr)): no browser globals at import, and
22
+ browser-only widgets are wrapped in `clientOnly`.
23
+ - **Vue sister**: `@nxgt/material-vue` uses the same names. The catalogue's
24
+ last column gives the Vue export for each entry.
25
+
26
+ ## Contents
27
+
28
+ - [Install](#install)
29
+ - [Setup](#setup)
30
+ - [Subpaths](#subpaths)
31
+ - [Usage](#usage)
32
+ - [Components](#components)
33
+ - [Helpers](#helpers)
34
+ - [SSR](#ssr)
35
+ - [Traps](#traps)
36
+ - [Development](#development)
37
+ - [License](#license)
38
+
6
39
  ## Install
7
40
 
8
41
  ```bash
9
42
  bun add @nxgt/material
10
43
  ```
11
44
 
12
- Public on npmjs; no token. **Required peers** the app must resolve the same
13
- copy, or hooks throw and tokens come from two builds:
45
+ It is public on npmjs, so no token is needed. **Required peers**: the app must
46
+ resolve the same copy of each, otherwise hooks throw and tokens come from two
47
+ builds.
14
48
 
15
49
  ```bash
16
50
  bun add react react-dom react-hook-form react-redux @reduxjs/toolkit @tanstack/react-table react-use
@@ -19,10 +53,10 @@ bun add react react-dom react-hook-form react-redux @reduxjs/toolkit @tanstack/r
19
53
  | Peer | Used by |
20
54
  | --- | --- |
21
55
  | `react`, `react-dom` `^19` | everything |
22
- | `react-hook-form` | every `*FormField` |
23
- | `react-redux`, `@reduxjs/toolkit` | `DataTable`, filter, gallery, kanban, player |
56
+ | `react-hook-form` `^7` | every `*FormField` |
57
+ | `react-redux` `^9`, `@reduxjs/toolkit` `^2` | `DataTable`, filter, gallery, kanban, player, slice helpers |
24
58
  | `@tanstack/react-table` `^9` | `DataTable` |
25
- | `react-use` | assorted hooks |
59
+ | `react-use` `^17` | `useTheme`, `useIsMobile`, `ScrollProgress` (`useScroll` / `useWindowScroll`), `CopyButton` (`useCopyToClipboard`), other hooks |
26
60
 
27
61
  The tarball is `dist/`, not `lib/`. There is no `postinstall` build.
28
62
 
@@ -39,17 +73,18 @@ In the app's root stylesheet, in this order:
39
73
  ```
40
74
 
41
75
  `styles.css` is the **source** `@theme` layer (colours, `--radius`, `dark`,
42
- fonts) so it runs through *your* Tailwind build. `@source` is required and
43
- silent when missing: Tailwind v4 does not scan `node_modules`, so without it
44
- every utility used *inside* a component is absent and the UI renders unstyled.
76
+ fonts), so it runs through *your* Tailwind build. The `@source` line is
77
+ required, and nothing warns you when it is missing. Tailwind v4 does not scan
78
+ `node_modules`, so without it every utility used *inside* a component is
79
+ missing and the UI renders unstyled.
45
80
 
46
- Import it **explicitly**, nothing injects it: Tailwind v4 builds one `@theme`
47
- from a single CSS graph, and Tailwind CSS IntelliSense reads the tokens from
48
- this entry file to autocomplete them in your components.
81
+ Import it **explicitly**, because nothing injects it. Tailwind v4 builds one
82
+ `@theme` from a single CSS graph, and Tailwind CSS IntelliSense reads the
83
+ tokens from this entry file to autocomplete them in your components.
49
84
 
50
85
  In a Tailwind app, do not also import the compiled `style` condition on
51
- `@nxgt/material` (`dist/material.css`). Take the tokens; let the app produce
52
- the utilities. The compiled file is for apps without Tailwind.
86
+ `@nxgt/material` (`dist/material.css`). Take the tokens and let the app
87
+ generate the utilities. The compiled file is for apps without Tailwind.
53
88
 
54
89
  ### Icons
55
90
 
@@ -62,25 +97,26 @@ import { Icon } from '@nxgt/material/components';
62
97
  // → /assets/icons/sprites/duotone.svg#atom
63
98
  ```
64
99
 
65
- Serve Font Awesome Pro sheets from `public/assets/icons/sprites/<style>.svg`.
66
- This package does **not** ship them: the FA Pro licence covers use in your
67
- own products, not redistribution inside a library. `files` includes
68
- `"!dist/assets"` so a local build cannot leak them into a tarball. A missing
69
- sheet renders as nothing no error, no fallback.
100
+ Serve the Font Awesome Pro sprite sheets from
101
+ `public/assets/icons/sprites/<style>.svg`. This package does **not** ship them:
102
+ the FA Pro licence covers use in your own products, not redistribution inside
103
+ a library. `files` includes `"!dist/assets"` so a local build cannot leak them
104
+ into a tarball. A missing sheet renders nothing, with no error and no fallback.
70
105
 
71
106
  ## Subpaths
72
107
 
73
108
  | Specifier | What is in it |
74
109
  | --- | --- |
75
- | `@nxgt/material` | default barrel + compiled `style` condition (`dist/material.css`, for apps without Tailwind) |
76
- | `@nxgt/material/components` | UI components and `*FormField` wrappers |
77
- | `@nxgt/material/hooks` | `useTheme`, `useIsClient`, `useMobile`, `useSearchParam`, … |
78
- | `@nxgt/material/dnd` | `@dnd-kit` primitives |
79
- | `@nxgt/material/i18n` | `I18nProvider`, `mergeResources`, `createTranslator` |
80
- | `@nxgt/material/lib` | `cn`, `clientOnly`, date/number/upload, `useSliceReducer` |
81
- | `@nxgt/material/models` | status types |
82
- | `@nxgt/material/types` | shared function types |
83
- | `@nxgt/material/styles.css` | source Tailwind v4 tokens **this** is what the app imports |
110
+ | `@nxgt/material` | Everything below in one barrel, plus the compiled `style` condition (`dist/material.css`, for apps without Tailwind) |
111
+ | `@nxgt/material/components` | UI components and `*FormField` wrappers ([Components](#components)) |
112
+ | `@nxgt/material/hooks` | `useTheme`, `useIsClient`, `useIsMobile`, `useLocalizedDate`, … ([hooks](#nxgtmaterialhooks)) |
113
+ | `@nxgt/material/dnd` | `@dnd-kit` primitives ([dnd](#nxgtmaterialdnd)) |
114
+ | `@nxgt/material/i18n` | `I18nProvider`, `mergeResources`, `createTranslator` ([i18n](#nxgtmateriali18n)) |
115
+ | `@nxgt/material/lib` | `cn`, `clientOnly`, date, number and storage utilities, `useSliceReducer` ([lib](#nxgtmateriallib)) |
116
+ | `@nxgt/material/models` | `Status<T>` |
117
+ | `@nxgt/material/types` | shared function types (`PromiseOr`, `FunctionOr`, …) |
118
+ | `@nxgt/material/styles.css` | source Tailwind v4 tokens. **This** is the file the app imports |
119
+
84
120
  ## Usage
85
121
 
86
122
  ### Components
@@ -96,8 +132,9 @@ import { Button, Icon } from '@nxgt/material/components';
96
132
 
97
133
  ### Form fields
98
134
 
99
- Every field has a standalone (`TextField`) and a React Hook Form wrapper
100
- (`TextFormField`) in the same barrel. Wrappers take `control` + `name`.
135
+ Each field has a standalone component (`TextField`) and a React Hook Form
136
+ wrapper (`TextFormField`) in the same barrel. The wrappers take `control` and
137
+ `name`.
101
138
 
102
139
  ```tsx
103
140
  import { TextFormField, Button } from '@nxgt/material/components';
@@ -113,9 +150,11 @@ const form = useForm({ defaultValues: { email: '' } });
113
150
 
114
151
  ### i18n
115
152
 
116
- This package owns the **mechanism**; the app owns resource **content**. The
117
- reserved namespace is `material` `mergeResources` is a shallow per-language
118
- merge, so an app-side `material` key silently shadows every string we ship.
153
+ This package owns the i18n **mechanism**, and the app owns the resource
154
+ **content**. This package's strings live under the `material` namespace.
155
+ `mergeResources` deep-merges your bundle over it per language, so you can
156
+ override one string (`material.command.title`) without losing the rest. Every
157
+ overridden key is reported with `console.warn` outside production.
119
158
 
120
159
  ```ts
121
160
  import {
@@ -140,16 +179,20 @@ export const useTranslation = createTypedTranslation<LocaleKey>(translate);
140
179
  </I18nProvider>
141
180
  ```
142
181
 
143
- Language state lives only in `I18nProvider`. Components in this package fall
144
- back to their English copy if the provider is not mounted. Messages are ICU
145
- MessageFormat; a missing key is returned verbatim.
182
+ Language state lives only in `I18nProvider`. If the provider is not mounted,
183
+ the components in this package fall back to their English copy. Messages use
184
+ ICU MessageFormat, and a missing key is returned as-is.
185
+
186
+ To translate Zod messages as well, add
187
+ `z.config({ customError: zodLocaleError() })`, with `zodLocaleError` from
188
+ `@nxgt/material/lib`.
146
189
 
147
190
  ### App shell
148
191
 
149
- `items` is a prop the shell does not build or filter the menu. `label` is
150
- already translated (`ReactNode`), not a key. `footer: true` pins an entry;
151
- do not rely on "last item". `avatar` and `headerActions` are props: the shell
152
- holds no session.
192
+ `items` is a prop: the shell does not build or filter the menu. Each `label`
193
+ is already translated (a `ReactNode`), not a key. Set `footer: true` to pin an
194
+ entry to the footer; being last in the list does not do it. `avatar` and
195
+ `headerActions` are props too, because the shell holds no session.
153
196
 
154
197
  ```tsx
155
198
  import { ActivityLayout, ActivityContent } from '@nxgt/material/components';
@@ -164,24 +207,372 @@ const items = [
164
207
  </ActivityLayout>
165
208
  ```
166
209
 
167
- The active entry is the **longest** match across the whole menu, segment-aware
168
- (`/admin` does not cover `/administrators`). `AppBreadcrumb` reads
169
- `handle.breadcrumb` off `useMatches()` and needs a data router
210
+ The active entry is the **longest** match across the whole menu. Matching is
211
+ segment-aware, so `/admin` does not cover `/administrators`. `AppBreadcrumb`
212
+ reads `handle.breadcrumb` from `useMatches()`, so it needs a data router
170
213
  (`createMemoryRouter` + `RouterProvider`, not `MemoryRouter`).
171
214
 
215
+ ## Components
216
+
217
+ Everything below is imported from `@nxgt/material/components`. In the
218
+ *Component* column, `·` separates a field from its React Hook Form wrapper.
219
+ The last column gives the matching export in `@nxgt/material-vue`, or `—` when
220
+ Vue has none. "(same parts)" means Vue exports the same sub-components.
221
+
222
+ ### Primitives
223
+
224
+ | Component | What it does | @nxgt/material-vue |
225
+ | --- | --- | --- |
226
+ | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` | Collapsible sections with a rotating chevron and animated content. | `Accordion` (same parts) |
227
+ | `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` | A single show / hide region and its trigger. | `Collapsible` (same parts) |
228
+ | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter` | Card surface with header, action slot, content and footer. | `Card` (same parts) |
229
+ | `Typography` | Text in the Material type scale (headline, title, body, caption…). | `Typography` |
230
+ | `AnchorHeading` | Heading with a hover copy-link (always visible on the phone). | `AnchorHeading` |
231
+ | `Label` | Form label with an optional required asterisk. | `Label` |
232
+ | `HelperText` | Hint or error message under a field. | `HelperText` |
233
+ | `ExtendedLabel` | Section title with an animated accent underline and a trailing slot. | `ExtendedLabel` |
234
+ | `Input` | Styled native `<input>`. | `Input` |
235
+ | `Textarea` | Styled native `<textarea>`. | `Textarea` |
236
+ | `InputGroup`, `InputGroupAddon`, `InputGroupInput`, `InputGroupButton`, `InputGroupText`, `InputGroupTextarea` | Input with inline or block addons, buttons and text. | `InputGroup` (same parts) |
237
+ | `Icon` | Font Awesome sprite icon by name and style (duotone by default), labelled with `role="img"`. | `Icon` |
238
+ | `Kbd`, `KbdShortcut` | One keyboard key, or a key combination with platform glyphs. | `Kbd`, `KbdShortcut` |
239
+ | `Separator` | Horizontal or vertical divider. | `Separator` |
240
+ | `Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption` | Styled semantic table inside a scrollable wrapper. | `Table` (same parts), `TableEmpty` |
241
+ | `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent` | Tabs whose triggers can take an icon. `variant="line"` is the quieter pill style. | `Tabs` (same parts) |
242
+ | `Toggle` | Pressable on / off button: default or outlined, three sizes. | `Toggle` |
243
+ | `ToggleGroup`, `ToggleGroupItem`, `ToggleGroupSeparator` | Single or multiple toggle group sharing variant and size. | `ToggleGroup`, `ToggleGroupItem` |
244
+ | `Activity` | React `<Activity>` switched by a boolean `visible`. | `Activity` |
245
+
246
+ ### Buttons & actions
247
+
248
+ | Component | What it does | @nxgt/material-vue |
249
+ | --- | --- | --- |
250
+ | `Button` | Filled, tonal, outlined, ghost or link button in seven colours, with a loading state. | `Button` |
251
+ | `IconButton` | Icon-only button with an optional tooltip. | `IconButton` |
252
+ | `ButtonGroup` | Joins adjacent buttons into one control. | `ButtonGroup` |
253
+ | `SplitButton` | Main action plus a dropdown menu of secondary actions. | `SplitButton` |
254
+ | `ResponsiveButton` | Shows its label on desktop and collapses to icon-only on mobile. | `ResponsiveButton` |
255
+ | `LinkButton`, `IconLinkButton`, `ResponsiveLinkButton` | The button styles rendered as `react-router` links. | `LinkButton`, `IconLinkButton`, `ResponsiveLinkButton` |
256
+ | `CopyButton`, `CopyValue` | Copies a value to the clipboard and briefly shows a check mark. `CopyValue` displays the value next to the button. | `CopyButton` |
257
+ | `HighlightText` | Marks case-insensitive matches of a query inside a string (`splitMatch`). | `HighlightText` |
258
+ | `LoadMoreButton` | "Load more" button for cursor pagination; icon-only with a tooltip unless `expanded`. | `LoadMoreButton` |
259
+ | `ScrollToTop` | Floating button that appears past a scroll threshold. | `ScrollToTop` |
260
+ | `ActionCard` | Clickable card with icon, title, description and active indicator. | `ActionCard` |
261
+ | `ThemeToggle` | Light / dark / system switch that stores and applies the choice. | `ThemeToggle` |
262
+ | `LanguageSwitcher` | Globe button with a menu of the `I18nProvider` languages. | `LanguageSwitcher` |
263
+
264
+ ### Form fields
265
+
266
+ | Component | What it does | @nxgt/material-vue |
267
+ | --- | --- | --- |
268
+ | `Field` · `FormField` | Renders the field matching a config `type` (text, select, date, upload, otp…). | `Field` |
269
+ | `TextField` · `TextFormField` | Labelled input with leading / trailing adornments and helper text. | `TextField`, `TextFormField` |
270
+ | `TextareaField` · `TextareaFormField` | Labelled textarea with row sizing and a `maxLength` counter. | `TextareaField`, `TextareaFormField` |
271
+ | `EmailField` · `EmailFormField` | Validates on blur; shows a `mailto:` button once the address is valid. | `EmailField`, `EmailFormField` |
272
+ | `PasswordField` · `PasswordFormField` | Show / hide toggle and an optional strength meter (`scorePassword`). | `PasswordField`, `PasswordFormField` |
273
+ | `NumberField` · `NumberFormField` | Emits `number \| null`, with min / max / step clamping, +/− buttons and a suffix. | `NumberField`, `NumberFormField` |
274
+ | `PercentField` · `PercentFormField` | `NumberField` with a `%` suffix. | `PercentField`, `PercentFormField` |
275
+ | `CurrencyField` · `CurrencyFormField` | Amount formatted to the locale on blur, with a currency suffix (EUR by default). | `CurrencyField`, `CurrencyFormField` |
276
+ | `PhoneField` · `PhoneFormField` | International number with a country picker; emits E.164. | `PhoneField`, `PhoneFormField` |
277
+ | `UrlField` · `UrlFormField` | Validates on blur; open-in-new-tab and copy buttons. | `UrlField`, `UrlFormField` |
278
+ | `SearchField` · `SearchFormField` | Search icon, clear button and spinner, with a debounced `onValueChange`. | `SearchField`, `SearchFormField` |
279
+ | `ColorField` · `ColorFormField` | Hex input with a colour picker in a popover. | `ColorField`, `ColorFormField` |
280
+ | `OtpField` · `OtpFormField` | One-time code input of configurable length. | `OtpField`, `OtpFormField`, `InputOTP` |
281
+ | `InputGroupField` · `InputGroupFormField` | Labelled `InputGroup` with addons and helper text. | `InputGroupField`, `InputGroupFormField` |
282
+ | `InlineEdit` · `InlineEditFormField` | Click-to-edit text with save and cancel. | `InlineEdit` |
283
+ | `CountryField` · `CountryFormField` | Single or multiple country picker with flags. | `CountryField`, `CountryFormField` |
284
+ | `TimezoneField` · `TimezoneFormField` | Searchable IANA timezone picker with localised labels. | `TimezoneField`, `TimezoneFormField` |
285
+ | `RatingField` · `RatingFormField` | Star rating with hover preview, click-to-clear and a read-only mode. | `RatingField`, `RatingFormField` |
286
+ | `Slider` · `SliderFormField` | Labelled single or range slider with an editable value and ticks. | `Slider`, `SliderField`, `SliderFormField` |
287
+ | `Switch` · `SwitchFormField` | Toggle switch, optionally in a labelled, bordered row. | `Switch`, `SwitchField`, `SwitchFormField` |
288
+ | `AttributesField`, `AttributesList`, `AttributeDialog`, `AttributeForm`, `AttributeValuesForm` · `AttributesFormField`, `AttributeValuesFormFieldSet`, `AttributeValueFormField` | Editor for typed custom attributes (string, number, date, select, rich text…). | `AttributesField`, `AttributesList`, `AttributeDialog`, `AttributeForm`, `AttributeValuesForm`, `AttributesFormField`, `AttributeValuesFormFieldSet`, `AttributeValueFormField` |
289
+ | `Contacts`, `ContactItem`, `ContactDialog` · `ContactsFormField` | Typed contact list (phone, email, URL…) with an add / edit dialog. | `Contacts`, `ContactItem`, `ContactDialog`, `ContactsFormField` |
290
+ | `PostalAddress`, `PostalAddressDialog` · `PostalAddressFormField` | Address card with an edit dialog. | `PostalAddress`, `PostalAddressDialog`, `PostalAddressFormField` |
291
+ | `OpeningHours`, `OpeningHoursDialog`, `OpeningHoursItem` · `OpeningHoursFormField` | Weekly opening hours with an add / edit dialog. | `OpeningHours`, `OpeningHoursDialog`, `OpeningHoursItem`, `OpeningHoursFormField` |
292
+
293
+ ### Date & time
294
+
295
+ | Component | What it does | @nxgt/material-vue |
296
+ | --- | --- | --- |
297
+ | `Calendar`, `CalendarDayButton` | Day-picker calendar with a year view, a today shortcut and `disablePast` / `disableFuture`. | `Calendar` (Reka parts) |
298
+ | `DateField` · `DateFormField` | Labelled trigger that opens a calendar popover, with an optional time picker. | `DateField`, `DateFormField` |
299
+ | `DateRangeField` · `DateRangeFormField` | From / to range picked in a popover calendar. | `DateRangeField`, `DateRangeFormField` |
300
+ | `TimeField` · `TimeFormField` | Opens a `TimePicker` in a popover, or in a dialog on mobile. | `TimeField`, `TimeFormField` |
301
+ | `TimePicker` | Hour and minute inputs with AM / PM and auto-advancing focus. | `TimePicker` |
302
+ | `DurationField` · `DurationFormField` | Hours and minutes combined into a total in minutes. | `DurationField`, `DurationFormField` |
303
+
304
+ ### Selection & choice
305
+
306
+ | Component | What it does | @nxgt/material-vue |
307
+ | --- | --- | --- |
308
+ | `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`… | Select primitives with groups, labels and scroll buttons. | `Select` (same parts), `NativeSelect` |
309
+ | `SelectField` · `SelectFormField` | Labelled select built from `options`, with `renderOption`. | `SelectField`, `SelectFormField` |
310
+ | `Combobox`, `ComboboxInput`, `ComboboxContent`, `ComboboxList`, `ComboboxItem`, `ComboboxChips`… | Base UI combobox primitives: input, popup list, groups and chips. | — |
311
+ | `ComboboxField` · `ComboboxFormField` | Labelled, searchable single select over `{ value, label }` options. | `ComboboxField`, `ComboboxFormField` |
312
+ | `Autocomplete`, `AutocompleteChips` · `AutocompleteFormField` | Single or multiple (chips) autocomplete with free-solo values and a query callback. | `Autocomplete`, `AutocompleteFormField` |
313
+ | `Checkbox` · `CheckboxFormField` | Checkbox with label, helper text and an indeterminate state. | `Checkbox` |
314
+ | `CheckboxGroup` · `CheckboxGroupFormField` | Checkbox list built from `options`, valued as `string[]`. | `CheckboxGroup`, `CheckboxGroupFormField` |
315
+ | `RadioGroup`, `RadioGroupItem` · `RadioGroupFormField` | Labelled radio group built from `options`, horizontal or vertical. | `RadioGroupField`, `RadioGroup`, `RadioGroupFormField` |
316
+ | `CheckCardField` · `CheckCardFormField` | A yes / no choice shown as two selectable cards. | `CheckCardField`, `CheckCardFormField` |
317
+ | `SelectCardField` · `SelectCardFormField` | Single or multiple choice shown as `ActionCard`s. | `SelectCardField`, `SelectCardFormField` |
318
+ | `SelectChipField` · `SelectChipFormField` | Single or multiple choice shown as toggleable chips. | `SelectChipField`, `SelectChipFormField` |
319
+ | `TransferList` · `TransferListFormField` | Two-pane picker with search, drag-and-drop, reordering and a `max`. | `TransferList`, `TransferListFormField` |
320
+ | `SortableList` · `SortableListFormField` | Searchable list of strings you reorder by dragging or with the keyboard. | `SortableList`, `SortableListFormField` |
321
+ | `Switcher` | Dropdown for switching the active workspace or account, with an avatar. | `Switcher` |
322
+
323
+ ### Data display
324
+
325
+ | Component | What it does | @nxgt/material-vue |
326
+ | --- | --- | --- |
327
+ | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarBase` | Image with a fallback and an optional online / offline dot. | `Avatar`, `AvatarImage`, `AvatarFallback` |
328
+ | `AvatarGroup` | Overlapping avatars with a `+N` overflow. | `AvatarGroup` |
329
+ | `Badge` | Pill label: default, secondary, error, success, info, warning, outlined. | `Badge` |
330
+ | `CountBadge` | Count in the corner of its children, capped at `99+` and hidden at 0. | `CountBadge` |
331
+ | `Chip` | Pill with leading, avatar and trailing slots, an active state and a dismiss button. | `Chip` |
332
+ | `StatCard` | KPI tile with value, hint, icon, toned delta and a loading skeleton. | `StatCard` |
333
+ | `TrendCard`, `GoalCard`, `BreakdownCard`, `RankCard` | Dashboard tiles: trend + sparkline, goal vs target, share breakdown, ranked list. Container queries. | `TrendCard`, `GoalCard`, `BreakdownCard`, `RankCard` |
334
+ | `FeatureCard`, `MediaCard`, `PricingCard`, `ProfileCard`, `QuoteCard`, `OverlayCard`, `SpotlightCard`, `CrewCard` | Card presets: product, media, pricing, profile, quote, cinematic overlay, bento spotlight, crew with avatars. Container queries. | `FeatureCard`, `MediaCard`, `PricingCard`, `ProfileCard`, `QuoteCard`, `OverlayCard`, `SpotlightCard`, `CrewCard` |
335
+ | `StatusIndicator` | Coloured status dot with an optional pulse and label. | `StatusIndicator` |
336
+ | `SummaryData` | Label / value pairs as a grid or inline; hides empty values. | `SummaryData` |
337
+ | `Description` | Read-only label / value pair that renders nothing when empty. | `Description` |
338
+ | `EntityHeader` | Page header with icon, title, status, metadata and actions. | `EntityHeader` |
339
+ | `ListTile` | Row with leading / trailing slots, title and subtitle; becomes a link or button when interactive. `size="sm"` is the dense row. | `ListTile` |
340
+ | `AccordionCard` | Renders `items` (title, content) as a styled accordion. | `AccordionCard` |
341
+ | `Timeline`, `TimelineItem`, `RelativeTime` | Vertical event timeline with toned icons and relative times. | `Timeline`, `TimelineItem`, `RelativeTime` |
342
+ | `EventChip` | Calendar event pill with time, all-day and continuation edges. | `EventChip` |
343
+ | `CodeBlock`, `CodeDiff`, `JsonViewer`, `CodeGroup` | Highlighted code with line numbers and copy, a Monaco diff, a collapsible JSON tree, and tabbed samples (`Tabs variant="line"`). | `CodeBlock`, `CodeDiff`, `JsonViewer`, `CodeGroup` |
344
+ | `Figure` | Framed media with an optional caption. | `Figure` |
345
+ | `ApiEndpoint`, `ApiOperation` | HTTP method badge, path and copy; `ApiOperation` adds a param table and example `CodeGroup`. | `ApiEndpoint`, `ApiOperation` |
346
+ | `ParamTable` | Name / type / default / description table; stacked cards below `sm`. | `ParamTable` |
347
+ | `QRCode` | QR code on a padded tile, with an optional centred logo. | `QRCode` |
348
+ | `Barecode` | 1D barcode. | `Barecode` |
349
+
350
+ ### Data table, filter & lists
351
+
352
+ | Component | What it does | @nxgt/material-vue |
353
+ | --- | --- | --- |
354
+ | `DataTable`, `DataTableColumnHeader`, `DataTablePagination`, `DataTableViewOptions` | TanStack Table v9 with sorting, filtering, selection, expandable rows, pagination or load-more, and column visibility. | `DataTable`, `DataTableColumnHeader`, `DataTablePagination`, `DataTableViewOptions` |
355
+ | `Filter`, `FilterProvider`, `FilterContent`, `FilterChips`, `FilterPresets` · `FilterFormField` | Schema-driven filters with chips, presets, validation, and URL or storage persistence. | `Filter`, `FilterProvider`, `FilterContent`, `FilterChips`, `FilterPresets`, `FilterFormField` |
356
+ | `FilterInline`, `FilterPopover`, `FilterDialog`, `FilterSheet`, `FilterDrawer` | The filter panel shown inline, or in a popover, dialog, sheet or drawer. | `FilterInline`, `FilterPopover`, `FilterDialog`, `FilterSheet`, `FilterDrawer` |
357
+ | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink`, `PaginationBar`… | Pagination primitives. `PaginationBar` adds a sibling window with ellipses. | `Pagination` (parts), `PaginationFirst`, `PaginationLast` |
358
+ | `Tree`, `TreeItem`, `useTree` | Expandable tree with none, single or multiple selection and keyboard navigation. | `Tree`, `TreeItem`, `useTree` |
359
+ | `DndProvider`, `Draggable`, `Droppable`, `Sortable`, `DragHandle`… | Drag-and-drop primitives; see [dnd](#nxgtmaterialdnd). | `DndProvider`, `Draggable`, `Droppable`, `Sortable`, `DragHandle` |
360
+
361
+ ### Navigation & layout
362
+
363
+ | Component | What it does | @nxgt/material-vue |
364
+ | --- | --- | --- |
365
+ | `ActivityLayout`, `ActivityContent`, `AppSidebar`, `AppHeader`, `AppBreadcrumb` | App shell: sidebar built from `items`, a header with a mobile sheet, route breadcrumbs and a titled page. See [App shell](#app-shell). | `ActivityLayout`, `ActivityContent`, `AppSidebar`, `AppHeader`, `AppBreadcrumb` |
366
+ | `Sidebar`, `SidebarHeader`, `SidebarContent`, `SidebarFooter`, `SidebarMenuItem`, `SidebarMenuLabel` | Collapsible navigation sidebar with icons, tooltips and active items. | `Sidebar` (same parts) |
367
+ | `TopAppBar`, `BottomAppBar` | Top bar surface, and a bottom bar of icon actions with an active state. | `TopAppBar`, `BottomAppBar` |
368
+ | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`, `BreadcrumbEllipsis` | Breadcrumb primitives. | `Breadcrumb` (same parts) |
369
+ | `ListDetailsLayout`, `PaneLayout`, `ThreadLayout` | List / details that collapses to one view on mobile, a side pane that becomes a sheet, and a centred column. | `ListDetailsLayout`, `PaneLayout`, `ThreadLayout` |
370
+ | `ResponsiveGrid` | Container-query grid that grows from 1 to 5 columns. | `ResponsiveGrid` |
371
+ | `ResizableGroup`, `ResizablePanel`, `ResizableSeparator` | Resizable panels with an optional grip handle. | `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle` |
372
+ | `SkipLink` | Skip-to-content control, visible on focus. `DocSkipLink` composes it with `#doc-content`. | `SkipLink` |
373
+ | `Pager` | Previous / next cards for a sequence of pages. `DocPager` composes it. | `Pager` |
374
+ | `SeeAlso` | Related-link list with outbound icons. `DocSeeAlso` composes it. | `SeeAlso` |
375
+ | `Toc` | On-this-page outline with a per-item active bar. Rail from `xl`, collapsible panel below. `DocToc` composes it. | `Toc` |
376
+ | `Stepper`, `StepperIndicator` | Clickable horizontal or vertical steps with status and progress; compact on mobile. | `Stepper` |
377
+ | `Steps`, `StepsItem` | Numbered editorial steps that stay visible on every breakpoint. | `Steps`, `StepsItem` |
378
+ | `Hero` | Landing band with eyebrow, title, supporting copy and actions. | `Hero` |
379
+ | `Doc`, `DocPage`, `DocTopbar`, `DocSidebar`, `DocToc`, `DocPager`, `DocSearch`, `DocChildCards`, `DocSeeAlso`, `DocEmpty`, `DocProgress` | Documentation site shell: sidebar from `md`, TOC rail from `xl`. Reading bar, copy-page / markdown, child cards, see also, and a 404 slot. Storybook `UI/Doc/Api` composes an API page from `DocPage`, `AnchorHeading`, `ApiOperation`, `ParamTable` and `CodeGroup`. | `Doc`, `DocPage`, `DocTopbar`, `DocSidebar`, `DocToc`, `DocPager`, `DocSearch`, `DocChildCards`, `DocSeeAlso`, `DocEmpty`, `DocProgress` |
380
+ | `Background` | Full-viewport gradient with blurred colour blobs; centres its children. | `Background` |
381
+ | `NavigationRail` | Placeholder: renders an empty rail container and takes no props yet. | `NavigationRail` |
382
+
383
+ ### Overlays & menus
384
+
385
+ | Component | What it does | @nxgt/material-vue |
386
+ | --- | --- | --- |
387
+ | `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogTitle`, `DialogDescription`, `DialogFooter`, `DialogClose`… | Modal dialog parts with an icon close button. | `Dialog` (same parts), `DialogScrollContent` |
388
+ | `Sheet`, `SheetTrigger`, `SheetContent`, `SheetHeader`, `SheetTitle`, `SheetFooter`… | Panel that slides in from any edge. | `Sheet` (same parts) |
389
+ | `Drawer`, `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerTitle`, `DrawerFooter`… | Swipeable bottom or side drawer (Vaul). | `Drawer` (same parts) |
390
+ | `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverAnchor` | Floating panel anchored to a trigger. | `Popover` (same parts) |
391
+ | `HoverCard`, `HoverCardTrigger`, `HoverCardContent` | Card shown on pointer hover. | `HoverCard` (same parts) |
392
+ | `Tooltip`, `TooltipProvider`, `TooltipTrigger`, `TooltipContent` | Tooltip. The `Tooltip` shorthand wraps its children and shows `content`. | `Tooltip` (same parts) |
393
+ | `DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuSub`… | Menu with checkbox and radio items, submenus, shortcuts and an error item. | `DropdownMenu` (same parts) |
394
+ | `ContextMenu`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuItem`… | Right-click menu with the same kinds of items. | `ContextMenu` (same parts) |
395
+ | `Menubar`, `MenubarMenu`, `MenubarTrigger`, `MenubarContent`, `MenubarItem`… | Desktop-style menubar. | `Menubar` (same parts) |
396
+ | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandItem`… | Command palette with filtering, groups and shortcuts. `CommandDialog` shows it in a modal. | `Command`, `CommandDialog` (same parts) |
397
+
398
+ ### Feedback & status
399
+
400
+ | Component | What it does | @nxgt/material-vue |
401
+ | --- | --- | --- |
402
+ | `Alert` | Callout with icon, title and description in seven tones. | `Alert` |
403
+ | `Banner` | Dismissible info / success / warning / error banner with an action. | `Banner` |
404
+ | `AlertDialog`, `AlertDialogContent`, `AlertDialogAction`, `AlertDialogCancel`… | Parts for a blocking confirmation dialog. | `AlertDialog` (same parts) |
405
+ | `ConfirmDialog`, `ConfirmationDialog`, `CustomAlertDialog` | Confirm / cancel dialog with async loading. `ConfirmationDialog` adds a trigger and an optional Zod form. | `ConfirmDialog`, `ConfirmationDialog`, `CustomAlertDialog` |
406
+ | `CustomDialog` | Ready-made dialog with trigger, icon, title, body and footer. | `CustomDialog` |
407
+ | `EmptyState` | Icon in a tinted well, title, description and action; not-found, unauthorized, generic and empty presets. | `EmptyState` |
408
+ | `Progress`, `CircularProgress`, `ProgressField` | Linear bar, circular ring with a label, and a labelled progress field. | `Progress`, `CircularProgress`, `ProgressField` |
409
+ | `ScrollProgress` | Hairline that tracks window or a scrollable `target` (`react-use` `useWindowScroll` / `useScroll`). `DocProgress` composes it. | `ScrollProgress` |
410
+ | `Spinner` | Loading spinner in several styles and colours. | `Spinner` |
411
+ | `Toaster`, `toast`, `toasts`, `Toast` | Sonner toasts with icon and action. `toasts` provides `success` / `error` / `warning` / `info` / `loading` presets. | `Toaster`, `toast`, `toasts`, `Toast` |
412
+ | `Skeleton`, `SkeletonAvatar`, `SkeletonCard`, `SkeletonText`, `SkeletonTable` | Loading placeholder and ready-made shapes. | `Skeleton` (same parts) |
413
+ | `HydrateLoading` | Full-area spinner shown while hydrating. | `HydrateLoading` |
414
+ | `Notifications` | Notification centre as a bell popover with an unread count, or as an inline panel, with filters and read / dismiss. | `Notifications` |
415
+
416
+ ### Media & files
417
+
418
+ | Component | What it does | @nxgt/material-vue |
419
+ | --- | --- | --- |
420
+ | `S3UploadField`, `NetworkUploadField` · `S3UploadFormField`, `NetworkUploadFormField` | Drag-and-drop uploader with progress, retry, previews and size / count limits. The S3 variant uploads through a presigned PUT. | `S3UploadField`, `NetworkUploadField`, `S3UploadFormField`, `NetworkUploadFormField` |
421
+ | `UploadField` · `UploadFormField` | Labelled file input showing the chosen file's name. | `UploadField`, `UploadFormField` |
422
+ | `FileList`, `FileListField`, `FileListS3Field` · `FileListFormField`, `FileListS3FormField` | File list with type icons, size, download and remove. The field variants upload with progress. | `FileList`, `FileListField`, `FileListS3Field`, `FileListFormField`, `FileListS3FormField` |
423
+ | `FilesFormField` | Free-solo autocomplete of file URLs, with image thumbnails. | — |
424
+ | `ImageField`, `ImageS3Field` · `ImageFormField`, `ImageS3FormField` | Single image upload with preview and progress. | `ImageField`, `ImageS3Field`, `ImageFormField`, `ImageS3FormField` |
425
+ | `ImageCropper`, `ImageCropperDialog` | Crop with zoom, rotation, aspect presets and a round shape; outputs a `File`. | `ImageCropper`, `ImageCropperDialog` |
426
+ | `Gallery`, `LightboxGallery`, `MiniGallery` | Image / video gallery (grid, masonry, justified, carousel…) with a lightbox and selection. | `Gallery`, `LightboxGallery`, `MiniGallery` |
427
+ | `Carousel`, `CarouselContent`, `CarouselItem`, `CarouselPrevious`, `CarouselNext` | Embla carousel with keyboard navigation. | `Carousel` (same parts) |
428
+ | `PdfReader`, `PdfViewer`, `PdfToolbar`, `PdfSidebar`, `PdfPageList`… | Browser-only PDF reader with zoom, rotation, search, thumbnails, outline and print. | `PdfReader`, `PdfViewer` (same parts) |
429
+ | `StxPlayer`, `StxPlayerProvider`, `StxPlayerMini`, `StxPlayerQueue`… | Video / audio player with a queue, captions, playback rate, PiP, and full or mini layouts. | `StxPlayer` (same parts) |
430
+ | `VideoPlayer` | Deprecated alias of `StxPlayer`. | `VideoPlayer` |
431
+ | `PrintHeader`, `PrintSection`, `PrintTable`, `PrintTotals`, `PrintCard`… | `@react-pdf/renderer` building blocks for printable PDF documents, with a shared `tw`. | `PrintHeader`, `PrintSection`, `PrintTable`, `PrintTotals`, `PrintCard` |
432
+
433
+ ### Rich widgets
434
+
435
+ | Component | What it does | @nxgt/material-vue |
436
+ | --- | --- | --- |
437
+ | `ChatThread`, `ChatMessageList`, `ChatMessage`, `ChatComposer`, `ChatConversationItem`… | Chat kit: auto-scrolling list, streaming and tool messages, a composer with attachments, and markdown. | `ChatThread`, `ChatMessageList`, `ChatMessage`, `ChatComposer` (same parts) |
438
+ | `Kanban` | Board with columns, swimlanes, WIP limits, search, and drag-and-drop cards and columns. | `Kanban` |
439
+ | `EventCalendar` | Month / week / day / agenda calendar with drag, resize and slot creation. | `EventCalendar` |
440
+ | `AreaChart`, `BarChart`, `LineChart`, `PieChart`, `RadarChart`, `ScatterChart`, `FunnelChart`, `HeatmapChart` | Nivo charts themed from the CSS tokens, with loading and empty states (`ChartContainer`). | same names |
441
+ | `RichTextEditor` · `RichTextEditorFormField` | Tiptap editor with toolbar, bubble menu, slash commands, mentions, tables, emoji and images. | `RichTextEditor`, `RichTextEditorFormField` |
442
+ | `CodeEditor` · `CodeEditorFormField` | Monaco editor field with a label and a language switch. | `CodeEditor` |
443
+ | `Quiz`, `QuestionCard` | Multi-step quiz with choice, boolean and text questions, answer reveal and scoring. | `Quiz`, `QuestionCard` |
444
+
445
+ `@nxgt/material-vue` also has components with no React counterpart here:
446
+ `Camera`, `ScrollArea`, `NativeSelect` and the `InputOTP` primitives.
447
+
448
+ ## Helpers
449
+
450
+ Everything below is also re-exported from the root `@nxgt/material` barrel.
451
+ The Vue sister, `@nxgt/material-vue`, uses the **same names** for the plain
452
+ functions; the differences are listed under each table.
453
+
454
+ ### `@nxgt/material/lib`
455
+
456
+ | Export | What it does |
457
+ | --- | --- |
458
+ | `cn(...classes)` | `clsx` + `tailwind-merge`: joins conditional classes, last Tailwind utility wins. |
459
+ | `clientOnly(Component)` | Wraps a component so it renders nothing on the server and mounts only on the client. |
460
+ | `renderSlot(slot, context)` | Resolves a `ContentSlot` — a `ReactNode` or a `(context) => ReactNode`. |
461
+ | `DATE_UTILS` | `format(iso, 'PP', locale?)` (`'-'` when empty), `parseFromTimestring('HH:mm')`, `parseFromISOString`, `formatDateRangeFilter`. |
462
+ | `formatDateRangeFilter(range)` | Turns a day-picker range into `{ from, to }` ISO strings at start / end of day. |
463
+ | `formatNumber(value, { language?, ...Intl.NumberFormatOptions })` | `Intl.NumberFormat` with a language shortcut (`'en-US'` by default). |
464
+ | `ifEmptyString(value, fallback)`, `ifEmptyList(value, fallback)` | Returns the fallback when the string / array is null or empty. |
465
+ | `objectToFormData(obj)`, `formDataToObject(formData)` | Converts a flat object to `FormData` (skipping nullish values) and back. |
466
+ | `convertToFormData(files, fieldName = 'files')` | Appends one file or a list of files to a new `FormData`. |
467
+ | `uniqueArray(array)` | De-duplicates an array. |
468
+ | `findByKey(array, key, value)`, `findByKeyIn(array, key, values)` | Finds the first item / every item whose `key` matches. |
469
+ | `useFindByKey(items, key)`, `useFindById(items)` | Memoised `findByKey` / `findByKeyIn` bound to a list. |
470
+ | `pick(obj, keys)`, `omit(obj, keys)` | Typed pick / omit for one key or a list. |
471
+ | `cleanObject(obj, cleanNulls?)` | Drops `undefined` (and optionally `null`) properties. |
472
+ | `cast<T>(value)`, `castAsync<T>(promise)` | Type-only casts. |
473
+ | `delay(ms)` | Promise that resolves after `ms`. |
474
+ | `safeGetItem(key, default)`, `safeSetItem(key, value)`, `safeRemoveItem(key)` | JSON `localStorage` access that never throws (SSR, private mode). Grouped as `LOCALE_STORE_UTILS`. |
475
+ | `enumToKebabCase(value)`, `joinTruthyParts(parts, sep = ', ')`, `splitMatch(text, query)` | `SOME_ENUM` → `some-enum`; joins the truthy parts only; splits a string around case-insensitive matches. Grouped as `STRING_UTILS`. |
476
+ | `STYLES_UTILS.colorFromVariable(name, alpha?)` | `rgb(from var(--name) r g b / alpha)` for a theme token. |
477
+ | `searchParams(request)`, `searchParam(request, key)` | Reads the query string of a Fetch `Request` (loaders, actions). |
478
+ | `isExternalHref(href)` | True for `http(s):` and `mailto:` — new tab, not in-app. |
479
+ | `buildFieldOptions(values, { valueKey, label })` | Maps records to `{ value, label }` options by path or label function. |
480
+ | `zodLocaleError()` | Zod v4 `customError` that translates issues through `material.zod.*`: `z.config({ customError: zodLocaleError() })`. |
481
+ | `parsedType(data)` | Runtime type name used for Zod's `{received}` placeholder. |
482
+
483
+ **Redux Toolkit helpers** (same subpath) — the state pattern behind filter,
484
+ gallery, kanban and player:
485
+
486
+ | Export | What it does |
487
+ | --- | --- |
488
+ | `useSliceReducer(slice, initialState?)` | Runs an RTK slice as *local* component state via `useReducer`; returns `[state, boundActions]`. |
489
+ | `resolveSliceState(base, overrides?)` | Merges a slice's initial state with partial overrides. |
490
+ | `useSliceSelector(state, selector)` | Memoised selector over local slice state. |
491
+ | `useActions(actionCreators, deps?)` | Binds action creators to the store `dispatch` (`react-redux`). |
492
+ | `createStatusSlice({ name, … })` | Slice over a `Status<T>` with `reset`, `start`, `success(data)` and `error(message)`. |
493
+ | `createStatusesSlice({ name, initialState, … })` | Same for a record of named `Status` entries, addressed by path. |
494
+ | `createStepFormSlice({ name, initialState? })` | Multi-step form: `step`, `values`, `isDirty`, with `updateStep`, `updateFormValues`, `reset`. |
495
+ | `createSliceWithFilter({ name, initialState, … })` | Adds `updateFilter` and `resetFilter` for a `{ filter, sort }` state. |
496
+ | `createAsyncSlice` | `buildCreateSlice` with the `asyncThunk` creator enabled. |
497
+
498
+ Vue: the Redux helpers are Pinia store factories — `defineLocalStore`
499
+ (per-instance store, like `useSliceReducer`), `defineStatusStore`,
500
+ `defineStatusesStore`, `defineStepFormStore`, `defineFilterStore`,
501
+ `resolveStoreState`, plus `runStatus`. `createAsyncSlice`, `useActions` and
502
+ `useSliceSelector` have no Vue counterpart.
503
+
504
+ ### `@nxgt/material/hooks`
505
+
506
+ | Export | What it does |
507
+ | --- | --- |
508
+ | `useTheme()` | `{ theme, preference, updateTheme }`: light / dark / system, stored in `localStorage`, applied as the `dark` class. |
509
+ | `resolveTheme(stored, prefersDark)`, `applyResolvedTheme(theme)` | The pure theme logic behind `useTheme`, usable in an inline boot script. |
510
+ | `useIsClient()` | `false` on the server and first render, `true` after mount — a hydration guard. |
511
+ | `useIsMobile()` | `true` below 768 px. |
512
+ | `useHeadingSpy(ids, onActive, options?)` | IntersectionObserver over heading ids; reports the topmost visible one. |
513
+ | `useLocalizedDate()` | `{ language, locale, format }`: `DATE_UTILS.format` bound to the `I18nProvider` language. |
514
+ | `useNumberFormatter()` | `{ formatNumber, formatCurrency }` bound to the `I18nProvider` language. |
515
+ | `useOptions(items, { value, label, filter?, expanded? })` | Memoised `{ value, label }` options for selects; `buildOptions` is the non-hook version. |
516
+ | `extractNode(connection)` | Unwraps a GraphQL `{ edges: [{ node }] }` connection into an array. |
517
+ | `useSearchParam(name)` | One query-string value from the router (`react-router`). |
518
+ | `useNavigationHandler(to, options?)`, `useNavigationHandlers(routes)` | Stable click handlers that navigate (`react-router`). |
519
+ | `useAllowedTransitions(status, transitions, configs)` | Status-machine actions (icon, colour, label, dialog copy) allowed from the current status. |
520
+
521
+ Vue: `@nxgt/material-vue/composables`, same names.
522
+
523
+ ### `@nxgt/material/i18n`
524
+
525
+ | Export | What it does |
526
+ | --- | --- |
527
+ | `I18nProvider` | Holds the current language (props `defaultLanguage`, `initialLanguage` for SSR, `storageKey`, `supportedLanguages`, `onLanguageChange`). |
528
+ | `useI18nContext()`, `useOptionalI18nContext()` | Reads `{ language, setLanguage, … }`; the first throws outside the provider, the second returns `null`. |
529
+ | `mergeResources(base, app)` | Deep, per-language merge (`lodash.merge`) of the package bundle and yours; your leaf keys win, and each override is warned about outside production. |
530
+ | `resources` | The package's `en` / `fr` bundle, namespace `material`. |
531
+ | `createTranslator(resources, getLanguage?)` | ICU MessageFormat translator; a missing key comes back verbatim. |
532
+ | `createTypedTranslation(translate)` | Turns a translator into a typed `useTranslation()` hook. |
533
+ | `translate`, `useMaterialTranslation()` | Translator / hook bound to the package's own `material.*` keys. |
534
+ | `getLanguage()` | Language read from `localStorage`, else `FALLBACK_LANGUAGE`. |
535
+ | `LANGUAGE_KEY`, `FALLBACK_LANGUAGE`, `SUPPORTED_LANGUAGES` | Storage key (`'language'`), fallback and supported languages (`en`, `fr`). |
536
+
537
+ Types: `FlatObject`, `Path`, `Language`, `MaterialLocaleKey`, `Translate`,
538
+ `TranslationContext`, `ResourceBundle`. Vue adds `provideI18n()` for apps that
539
+ provide the context from `setup()` instead of the component.
540
+
541
+ ### `@nxgt/material/models`, `/types`
542
+
543
+ | Export | What it does |
544
+ | --- | --- |
545
+ | `Status<T>` | `{ data?, status: 'idle' \| 'loading' \| 'success' \| 'error', error? }` — the shape the status slices manage. |
546
+ | `PromiseOr<T>`, `FunctionOr<T, R>`, `AsyncFunctionOr<T, R>` | A value or a promise; a value or a function computing it. |
547
+ | `Predicate<T>`, `AsyncPredicate<T>` | `(arg) => boolean` and its async form. |
548
+
549
+ ### `@nxgt/material/dnd`
550
+
551
+ The drag-and-drop layer on `@dnd-kit`, also in `/components`:
552
+
553
+ | Export | What it does |
554
+ | --- | --- |
555
+ | `DndProvider`, `DndOverlay` | The `DndContext` (sensors, collision detection) and the floating drag preview. |
556
+ | `Draggable`, `Droppable`, `DraggableDroppable`, `DragHandle` | Primitives for free drag, drop zones, nested boards and handles. |
557
+ | `Sortable`, `SortableProvider` | A sortable item and its list context. |
558
+ | `useDndItem`, `useDndActiveId` | The item's drag state; the id being dragged. |
559
+ | `insertIds`, `arrayMove`, `composeRefs` | Pure list and ref helpers. |
560
+ | `closestCenter`, `pointerWithin`, `rectIntersection`, `verticalListSortingStrategy`, `horizontalListSortingStrategy`, `CSS` | Re-exported from `@dnd-kit`. |
561
+
172
562
  ## SSR
173
563
 
174
564
  An SSR app that bundles this package (`ssr.noExternal: ['@nxgt/material']`)
175
- evaluates every module the barrels reach at **boot**, whether or not a page
176
- renders the component.
565
+ runs every module the barrels reach when the server **boots**, whether or not
566
+ a page renders the component.
177
567
 
178
- - **Nothing browser-only at module scope.** `pdfjs-dist` runs `new DOMMatrix()`
179
- at import. Reach it through `import()` and wrap the component with
180
- `clientOnly` from `@nxgt/material/lib`. A `typeof window` guard around a
181
- statement does nothing when the *import* is the side effect.
568
+ - **Nothing browser-only at module scope.** `pdfjs-dist` runs
569
+ `new DOMMatrix()` at import. Load it with `import()` and wrap the component
570
+ in `clientOnly` from `@nxgt/material/lib`. A `typeof window` guard around a
571
+ statement does nothing when the *import* itself is the side effect.
182
572
  - **Never `<svg><title>`.** React 19 hoists `<title>` as document metadata:
183
- server emits `<title></title>`, client renders the text, hydration discards
184
- the whole tree. Use `role="img"` + `aria-label` (`Icon` already does).
573
+ the server emits `<title></title>` while the client renders the text, and
574
+ the hydration mismatch makes React discard the whole tree. Use
575
+ `role="img"` + `aria-label` instead (`Icon` already does).
185
576
 
186
577
  ## Traps
187
578
 
@@ -189,7 +580,7 @@ renders the component.
189
580
  | --- | --- | --- |
190
581
  | Components render unstyled, no console error | Tailwind did not scan the package | `@source "../node_modules/@nxgt/material/"` |
191
582
  | `<Icon>` is blank | sprite sheet not served | `public/assets/icons/sprites/<style>.svg` |
192
- | Package strings vanish after adding i18n | app declared `material` | never a top-level `material` key in app resources |
583
+ | Package strings change after adding i18n | your resources define keys under `material` | keep app strings in your own namespaces; `console.warn` lists each override in development |
193
584
  | Hydration mismatch on every page | `<svg><title>` | `role="img"` + `aria-label` |
194
585
  | `ReferenceError: DOMMatrix` at server boot | static `react-pdf` import | `import()` + `clientOnly` |
195
586
 
@@ -201,3 +592,8 @@ bun run build # what consumers read
201
592
  bun run storybook
202
593
  bun run test
203
594
  ```
595
+
596
+ ## License
597
+
598
+ [MIT](https://opensource.org/license/mit). The `LICENSE` file ships in the
599
+ package.