@dreamtree-org/twreact-ui 1.2.1 → 1.3.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.
- package/DESIGN.md +118 -0
- package/README.md +231 -44
- package/ai-skills/dreamtree-ui.md +98 -12
- package/dist/ai-schema.json +452 -17
- package/dist/components/blocks/AppShell.d.ts +4 -0
- package/dist/components/blocks/AppShell.d.ts.map +1 -0
- package/dist/components/blocks/ConfirmDialog.d.ts +4 -0
- package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/blocks/EmptyState.d.ts +4 -0
- package/dist/components/blocks/EmptyState.d.ts.map +1 -0
- package/dist/components/blocks/ErrorState.d.ts +4 -0
- package/dist/components/blocks/ErrorState.d.ts.map +1 -0
- package/dist/components/blocks/LoadingState.d.ts +9 -0
- package/dist/components/blocks/LoadingState.d.ts.map +1 -0
- package/dist/components/blocks/PageHeader.d.ts +4 -0
- package/dist/components/blocks/PageHeader.d.ts.map +1 -0
- package/dist/components/blocks/StatCard.d.ts +4 -0
- package/dist/components/blocks/StatCard.d.ts.map +1 -0
- package/dist/components/blocks/StatusPill.d.ts +5 -0
- package/dist/components/blocks/StatusPill.d.ts.map +1 -0
- package/dist/components/core/Accordion.d.ts.map +1 -1
- package/dist/components/core/Button.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/ColorPicker.d.ts.map +1 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.d.ts.map +1 -1
- package/dist/components/core/Form.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/Popover.d.ts +4 -0
- package/dist/components/core/Popover.d.ts.map +1 -0
- package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Radio.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts +4 -0
- package/dist/components/core/Slider.d.ts.map +1 -0
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
- package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +2 -2
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +4 -2
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts +4 -0
- package/dist/components/core/Textarea.d.ts.map +1 -0
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts +4 -0
- package/dist/components/feedback/Drawer.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +14 -5
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/Tour.d.ts +4 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -0
- package/dist/components/feedback/TourSpotlight.d.ts +9 -0
- package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +8 -2
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts +4 -0
- package/dist/components/utility/Sortable.d.ts.map +1 -0
- package/dist/esm/_vendor/object-assign/index.js +99 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
- package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
- package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
- package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
- package/dist/esm/_vendor/prop-types/index.js +30 -0
- package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
- package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
- package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/index.js +3 -0
- package/dist/esm/_virtual/index2.js +3 -0
- package/dist/esm/_virtual/react-is.development.js +3 -0
- package/dist/esm/_virtual/react-is.production.min.js +3 -0
- package/dist/esm/components/blocks/AppShell.js +205 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
- package/dist/esm/components/blocks/EmptyState.js +44 -0
- package/dist/esm/components/blocks/ErrorState.js +53 -0
- package/dist/esm/components/blocks/LoadingState.js +134 -0
- package/dist/esm/components/blocks/PageHeader.js +51 -0
- package/dist/esm/components/blocks/StatCard.js +79 -0
- package/dist/esm/components/blocks/StatusPill.js +55 -0
- package/dist/esm/components/core/Accordion.js +260 -0
- package/dist/esm/components/core/Button.js +59 -0
- package/dist/esm/components/core/Checkbox.js +188 -0
- package/dist/esm/components/core/ColorPicker.js +348 -0
- package/dist/esm/components/core/DatePicker.js +436 -0
- package/dist/esm/components/core/DateRangePicker.js +494 -0
- package/dist/esm/components/core/Form.js +522 -0
- package/dist/esm/components/core/Input.js +179 -0
- package/dist/esm/components/core/Loader.js +141 -0
- package/dist/esm/components/core/LocationPicker.js +161 -0
- package/dist/esm/components/core/Popover.js +171 -0
- package/dist/esm/components/core/PriceRangePicker.js +376 -0
- package/dist/esm/components/core/ProgressBar.js +152 -0
- package/dist/esm/components/core/Radio.js +156 -0
- package/dist/esm/components/core/Rate.js +197 -0
- package/dist/esm/components/core/RoundedTag.js +118 -0
- package/dist/esm/components/core/Select.js +857 -0
- package/dist/esm/components/core/Skeleton.js +100 -0
- package/dist/esm/components/core/Slider.js +134 -0
- package/dist/esm/components/core/SpeechToText.js +226 -0
- package/dist/esm/components/core/Switch.js +207 -0
- package/dist/esm/components/core/Table/ActionMenu.js +251 -0
- package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
- package/dist/esm/components/core/Table/FieldInput.js +157 -0
- package/dist/esm/components/core/Table/MobileCard.js +187 -0
- package/dist/esm/components/core/Table/MobileFilters.js +72 -0
- package/dist/esm/components/core/Table/Pagination.js +157 -0
- package/dist/esm/components/core/Table/Table.js +1533 -0
- package/dist/esm/components/core/Table/TableRow.js +254 -0
- package/dist/esm/components/core/Table/constants.js +35 -0
- package/dist/esm/components/core/Table/helpers.js +124 -0
- package/dist/esm/components/core/Table/useClickOutside.js +26 -0
- package/dist/esm/components/core/Tabs.js +289 -0
- package/dist/esm/components/core/TextToSpeech.js +52 -0
- package/dist/esm/components/core/Textarea.js +125 -0
- package/dist/esm/components/core/ThreeDotPopover.js +160 -0
- package/dist/esm/components/core/Tooltip.js +372 -0
- package/dist/esm/components/feedback/Alert.js +96 -0
- package/dist/esm/components/feedback/Dialog.js +200 -0
- package/dist/esm/components/feedback/Drawer.js +171 -0
- package/dist/esm/components/feedback/Toast.js +362 -0
- package/dist/esm/components/feedback/Tour.js +214 -0
- package/dist/esm/components/feedback/TourSpotlight.js +71 -0
- package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
- package/dist/esm/components/navigation/Dropdown.js +53 -0
- package/dist/esm/components/navigation/FootNav.js +51 -0
- package/dist/esm/components/navigation/Navbar.js +437 -0
- package/dist/esm/components/navigation/Sidebar.js +567 -0
- package/dist/esm/components/utility/Avatar.js +89 -0
- package/dist/esm/components/utility/Badge.js +47 -0
- package/dist/esm/components/utility/Card.js +85 -0
- package/dist/esm/components/utility/Carousel.js +97 -0
- package/dist/esm/components/utility/Condition.js +9 -0
- package/dist/esm/components/utility/FileUpload.js +177 -0
- package/dist/esm/components/utility/Pagination.js +111 -0
- package/dist/esm/components/utility/Sortable.js +190 -0
- package/dist/esm/components/utility/Stepper.js +101 -0
- package/dist/esm/hooks/useApi.js +169 -0
- package/dist/esm/hooks/useControllableState.js +32 -0
- package/dist/esm/hooks/useFocusTrap.js +85 -0
- package/dist/esm/hooks/useLatestRef.js +20 -0
- package/dist/esm/hooks/useMixins.js +100 -0
- package/dist/esm/hooks/useScrollLock.js +26 -0
- package/dist/esm/hooks/useSliderValues.js +135 -0
- package/dist/esm/hooks/useSortable.js +188 -0
- package/dist/esm/hooks/useTheme.js +53 -0
- package/dist/esm/hooks/useTourTarget.js +92 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/store/index.js +26 -0
- package/dist/esm/store/store.js +107 -0
- package/dist/esm/store/storeSlice.js +45 -0
- package/dist/esm/utils/cn.js +11 -0
- package/dist/esm/utils/emitter.js +169 -0
- package/dist/esm/utils/helpers.js +161 -0
- package/dist/esm/utils/position.js +134 -0
- package/dist/hooks/useApi.d.ts +2 -1
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useControllableState.d.ts +11 -0
- package/dist/hooks/useControllableState.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +15 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/hooks/useLatestRef.d.ts +8 -0
- package/dist/hooks/useLatestRef.d.ts.map +1 -0
- package/dist/hooks/useMixins.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.d.ts +2 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -0
- package/dist/hooks/useSliderValues.d.ts +43 -0
- package/dist/hooks/useSliderValues.d.ts.map +1 -0
- package/dist/hooks/useSortable.d.ts +32 -0
- package/dist/hooks/useSortable.d.ts.map +1 -0
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTourTarget.d.ts +15 -0
- package/dist/hooks/useTourTarget.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +55 -39
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +7937 -4659
- package/dist/index.js +7950 -4657
- package/dist/tokens/brands/default.css +1 -0
- package/dist/tokens/brands/default.json +5 -0
- package/dist/tokens/brands/practicepro.css +17 -0
- package/dist/tokens/brands/practicepro.json +27 -0
- package/dist/tokens/tailwind3-preset.cjs +214 -0
- package/dist/tokens/theme.css +193 -0
- package/dist/tokens/tokens.json +373 -0
- package/dist/tokens/vars.css +98 -0
- package/dist/types/blocks.d.ts +109 -0
- package/dist/types/blocks.d.ts.map +1 -0
- package/dist/types/index.d.ts +194 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/position.d.ts +30 -0
- package/dist/utils/position.d.ts.map +1 -0
- package/doc/README.md +26 -1
- package/mcp/catalog.snapshot.json +1643 -549
- package/package.json +24 -6
- package/tokens/brands/default.json +5 -0
- package/tokens/brands/practicepro.json +27 -0
- package/tokens/lib.cjs +128 -0
- package/tokens/tokens.json +133 -0
|
@@ -63,6 +63,14 @@ module.exports = {
|
|
|
63
63
|
};
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
Import from the package root only (`import { Button } from '@dreamtree-org/twreact-ui'`).
|
|
67
|
+
The root import tree-shakes, so do not suggest deep paths into `dist/` or `src/` for components.
|
|
68
|
+
|
|
69
|
+
**Next.js App Router:** components ship with `'use client'`, so a Server Component can import
|
|
70
|
+
them directly. Do not generate a `"use client"` wrapper file that re-exports the library.
|
|
71
|
+
Compound members (`Card.Header`, `Tabs.List`, `Dialog.Footer`) and function props (`onClick`)
|
|
72
|
+
still require a `'use client'` file. `cn`, `Helpers` and `Emitter` also work on the server.
|
|
73
|
+
|
|
66
74
|
## Live prop contracts via MCP (prefer this over guessing)
|
|
67
75
|
|
|
68
76
|
An **MCP server bundled in this package** serves the authoritative prop
|
|
@@ -99,10 +107,11 @@ The library exports four kinds of things from `@dreamtree-org/twreact-ui`:
|
|
|
99
107
|
|
|
100
108
|
| Group | Components |
|
|
101
109
|
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
-
| **Core** | `Input`, `Button`, `Select`, `Table`, `Form`, `Accordion`, `Checkbox`, `ColorPicker`, `DatePicker`, `DateRangePicker`, `Loader`, `LocationPicker`, `PriceRangePicker`, `ProgressBar`, `Radio`, `Rate`, `RoundedTag`, `Skeleton`, `Switch`, `Tabs`, `ThreeDotPopover`, `Tooltip`, `SpeechToText`, `TextToSpeech` |
|
|
110
|
+
| **Core** | `Input`, `Button`, `Select`, `Table`, `Form`, `Accordion`, `Checkbox`, `ColorPicker`, `DatePicker`, `DateRangePicker`, `Loader`, `LocationPicker`, `PriceRangePicker`, `ProgressBar`, `Radio`, `Rate`, `RoundedTag`, `Skeleton`, `Switch`, `Tabs`, `ThreeDotPopover`, `Tooltip`, `SpeechToText`, `TextToSpeech`, `Textarea`, `Slider`, `Popover` |
|
|
103
111
|
| **Navigation** | `Sidebar`, `Navbar`, `FootNav`, `Breadcrumbs` |
|
|
104
|
-
| **Feedback** | `Dialog`, `Toast` (+ `ToastContainer`, `useToast`), `Alert`
|
|
105
|
-
| **Utility** | `Badge`, `Avatar`, `Card`, `Pagination`, `Stepper`, `FileUpload`, `Condition`, `Carousel`
|
|
112
|
+
| **Feedback** | `Dialog`, `Toast` (+ `ToastProvider`, `ToastContainer`, `useToast`), `Alert`, `Drawer` (side sheet; `isOpen`/`onClose` like Dialog), `Tour` (onboarding spotlight) |
|
|
113
|
+
| **Utility** | `Badge`, `Avatar`, `Card`, `Pagination`, `Stepper`, `FileUpload`, `Condition`, `Carousel`, `Sortable` (drag + keyboard reorder) |
|
|
114
|
+
| **Blocks** | `AppShell`, `PageHeader`, `StatCard`, `StatusPill`, `EmptyState`, `ErrorState`, `LoadingState`, `ConfirmDialog` — page-level patterns; build pages from these before composing layouts by hand |
|
|
106
115
|
|
|
107
116
|
### Hooks
|
|
108
117
|
|
|
@@ -110,7 +119,7 @@ The library exports four kinds of things from `@dreamtree-org/twreact-ui`:
|
|
|
110
119
|
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
111
120
|
| `useTheme` | Read/write the current theme (`light | dark`); pairs with `<ThemeProvider>`. Throws if used outside the provider. |
|
|
112
121
|
| `ThemeProvider` | Provider that persists theme to `localStorage` (`dreamtree-theme`) and toggles `data-theme` on `<html>`. |
|
|
113
|
-
| `useApi` | Thin axios wrapper. Returns `{data, error, loading,
|
|
122
|
+
| `useApi` | Thin axios wrapper. Returns `{data, error, loading, lastRequest, fetchData, fetchApi, fetchApiWith}`. Accepts `BASE_URL`, `DEFAULT_HEADERS`, `apiMap`. |
|
|
114
123
|
| `useMixins` | Bridge between component state, Redux store, and an in-memory cache. Power-user hook — prefer local React state for new code. |
|
|
115
124
|
|
|
116
125
|
### Store
|
|
@@ -148,14 +157,51 @@ Components use a **shared variant/size/focus vocabulary**:
|
|
|
148
157
|
|
|
149
158
|
- **Variants:** `primary | secondary | outline | ghost | destructive | success | warning`
|
|
150
159
|
(component-specific extras like `Badge: info` and `Alert: neutral` are documented per-component).
|
|
151
|
-
- **Sizes:** `xs | sm | md | lg | xl` mapping to heights `h-7 / h-8 / h-10 / h-12 / h-14`
|
|
152
|
-
and padding `px-2 / px-3 / px-4 / px-6 / px-8` (
|
|
160
|
+
- **Sizes:** `xs | sm | md | lg | xl | 2xl` mapping to heights `h-7 / h-8 / h-10 / h-12 / h-14 / h-16`
|
|
161
|
+
and padding `px-2 / px-3 / px-4 / px-6 / px-8 / px-10` (`Button` implements all six;
|
|
162
|
+
other components MAY support a subset and fall back to `md`).
|
|
153
163
|
- **Focus ring:** `focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500`
|
|
154
164
|
(the color token swaps for destructive / etc.).
|
|
155
165
|
- **Dark mode:** Tailwind `darkMode: 'class'`. Every color choice has a `dark:` counterpart.
|
|
156
166
|
|
|
157
167
|
When suggesting a component or new variant value, use this exact vocabulary.
|
|
158
168
|
|
|
169
|
+
## Page blocks and design tokens
|
|
170
|
+
|
|
171
|
+
**Blocks** are page-level patterns extracted from the products, so screens stop re-inventing them:
|
|
172
|
+
|
|
173
|
+
- `AppShell` — sidebar + top bar + mobile drawer; pass `nav` items and `linkAs={Link}` in Next.js.
|
|
174
|
+
- `Sidebar` — every item renders as an `<a>`; give items an `href` (and `linkAs={Link}` in Next.js) so Ctrl/Cmd-click opens a new tab. Parents with `href` navigate + expand; the chevron toggles. Mark the current page `active: true` and its group opens on load (control groups with `expandedIds`/`defaultExpandedIds`/`onExpandedChange`). Top-level `group: 'Name'` adds section headings; `badge` (+ `badgeLabel: '3 unread'`) shows counts; `footer` pins links above the user block; `stickyOffset={64}` when a top bar sits above it. The mobile drawer (`isMobileOpen`/`setIsMobileOpen`) is inert when shut and closes on Escape.
|
|
175
|
+
- `PageHeader` — the page's only `h1`, subtitle, one primary action, optional `back` link.
|
|
176
|
+
- `StatCard` — KPI tile (`label`, `value`, `icon`, `tone`, `change`).
|
|
177
|
+
- `StatusPill` — map domain states to `{ label, tone }` once; unknown states are humanized, never raw.
|
|
178
|
+
- `EmptyState`, `ErrorState`, `LoadingState` — every data card needs all three.
|
|
179
|
+
- `ConfirmDialog` — use instead of `window.confirm()`; title is the question, button is the verb.
|
|
180
|
+
|
|
181
|
+
**Interaction primitives** — reach for these before hand-rolling the pattern:
|
|
182
|
+
|
|
183
|
+
- `Drawer` — side/edge sheet for record peeks and editors (`isOpen`, `onClose`, `title`, `placement`, `size`, `footer`); don't fake one with `Dialog size="lg"`.
|
|
184
|
+
- `Popover` — click-triggered panel with controls (`trigger={<Button>…</Button>}`, children or `({ close }) => …`); `Tooltip` is for read-only hover text only.
|
|
185
|
+
- `Textarea` — same API as `Input` plus `autoResize`/`maxRows`; never a raw `<textarea>`.
|
|
186
|
+
- `Slider` — `defaultValue={40}` for one thumb, `[low, high]` for a range; `onChangeEnd` to save after a drag.
|
|
187
|
+
- `Sortable` — `items` + `onReorder(newItems)` + `renderItem`; keyboard reordering and announcements are built in. Pass `handle` and spread `handleProps` on a grip for touch screens.
|
|
188
|
+
- `Tour` — onboarding coach marks: `steps=[{ target: '[data-tour="x"]', title, content, placement }]`, `open`, `onClose(reason)`; a missing target falls back to a centred card.
|
|
189
|
+
|
|
190
|
+
**Tokens:** colours are CSS variables (`--dt-primary-600`, `--dt-surface`, …) generated from
|
|
191
|
+
`tokens/tokens.json`. Use semantic classes (`bg-primary-600`, `bg-surface`, `text-foreground`,
|
|
192
|
+
`text-muted`, `border-line`, `text-micro`, `rounded-card`) — never hex values or Tailwind's raw
|
|
193
|
+
palette (`bg-blue-500`). A product re-themes by loading `dist/tokens/brands/<brand>.css`.
|
|
194
|
+
The full rule set for screens is `DESIGN.md` in the package root.
|
|
195
|
+
|
|
196
|
+
```jsx
|
|
197
|
+
<PageHeader title="Compliance calendar" actions={<Button>Add obligation</Button>} />
|
|
198
|
+
<div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
|
199
|
+
<StatCard label="Due this week" value={18} icon={<CalendarDays className="h-6 w-6" />} />
|
|
200
|
+
<StatCard label="Overdue" value={3} tone="error" icon={<AlertCircle className="h-6 w-6" />} />
|
|
201
|
+
</div>
|
|
202
|
+
<Card>{loading ? <LoadingState /> : error ? <ErrorState onRetry={retry} /> : rows.length ? <Table … /> : <EmptyState title="No obligations yet" />}</Card>
|
|
203
|
+
```
|
|
204
|
+
|
|
159
205
|
## Canonical examples
|
|
160
206
|
|
|
161
207
|
### Button
|
|
@@ -189,17 +235,48 @@ import { Input } from '@dreamtree-org/twreact-ui';
|
|
|
189
235
|
`Form` integrates with `react-hook-form` + `yup` (`@hookform/resolvers`).
|
|
190
236
|
Validation rules live in consumer code.
|
|
191
237
|
|
|
238
|
+
**Helper text:** `Input`, `Select`, `DatePicker`, `DateRangePicker` and every
|
|
239
|
+
`Form` field take `helperText` (rendered below, linked via `aria-describedby`).
|
|
240
|
+
While `error` is set it **replaces** the helper text — don't render both. Don't
|
|
241
|
+
hand-roll a `<p>` hint under a field.
|
|
242
|
+
|
|
243
|
+
```jsx
|
|
244
|
+
<Select label="Role" helperText="Controls access." options={roles} value={role} onChange={setRole} />
|
|
245
|
+
<Form fields={[
|
|
246
|
+
{ type: 'email', name: 'email', label: 'Email', helperText: 'Receipts only.' },
|
|
247
|
+
{ type: 'color', name: 'brand', label: 'Brand colour', swatches: ['#2563eb'] }, // ColorPicker
|
|
248
|
+
]} />
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`Form` field types: `text | email | password | number | tel | url | select |
|
|
252
|
+
date | textarea | checkbox | radio | file | switch | color | custom`. Use
|
|
253
|
+
`type: 'color'` rather than a `custom` field wrapping `ColorPicker`.
|
|
254
|
+
|
|
255
|
+
**Select `grouped`** accepts `[{ label, options }]` groups **or** flat options
|
|
256
|
+
with a `group` key (`{ value, label, group: 'Code' }`) — no need to pre-group.
|
|
257
|
+
|
|
258
|
+
**Navbar** takes a `center` slot (search field / primary action) and shows
|
|
259
|
+
`user.name` initials when `user.avatar` is missing; it fits a 390px phone.
|
|
260
|
+
|
|
261
|
+
**Tooltip** around a component (e.g. `<Button>`) in a row/grid: use
|
|
262
|
+
`customTrigger={<Button>…</Button>}` so there is one tab stop, not two. A lone
|
|
263
|
+
native `<button>` / `<a href>` / `<input>` child is detected automatically.
|
|
264
|
+
|
|
192
265
|
### Toast
|
|
193
266
|
|
|
267
|
+
Wrap the app ONCE in `ToastProvider`; every `useToast()` below it shares one
|
|
268
|
+
queue and the provider renders it. (Without a provider each `useToast()` owns a
|
|
269
|
+
private queue that only shows where that same hook's `toasts` are passed to a
|
|
270
|
+
`<ToastContainer toasts={toasts} onRemove={removeToast} />`.)
|
|
271
|
+
|
|
194
272
|
```jsx
|
|
195
|
-
import {
|
|
273
|
+
import { ToastProvider, useToast } from '@dreamtree-org/twreact-ui';
|
|
196
274
|
|
|
197
275
|
function App() {
|
|
198
276
|
return (
|
|
199
|
-
|
|
200
|
-
<ToastContainer />
|
|
277
|
+
<ToastProvider position="top-right">
|
|
201
278
|
<YourApp />
|
|
202
|
-
|
|
279
|
+
</ToastProvider>
|
|
203
280
|
);
|
|
204
281
|
}
|
|
205
282
|
|
|
@@ -229,14 +306,23 @@ toggles `data-theme` on `<html>`.
|
|
|
229
306
|
```jsx
|
|
230
307
|
import { useApi } from '@dreamtree-org/twreact-ui';
|
|
231
308
|
|
|
232
|
-
const { data, error, loading,
|
|
309
|
+
const { data, error, loading, fetchData, fetchApi, fetchApiWith } = useApi({
|
|
233
310
|
BASE_URL: 'https://api.example.com',
|
|
234
311
|
DEFAULT_HEADERS: { Authorization: `Bearer ${token}` },
|
|
312
|
+
apiMap: {
|
|
313
|
+
getUser: (id) => ({ url: `/users/${id}`, method: 'GET' }),
|
|
314
|
+
updateUser: (id, body) => ({ url: `/users/${id}`, method: 'PUT', data: body }),
|
|
315
|
+
},
|
|
235
316
|
});
|
|
236
317
|
|
|
237
|
-
useEffect(() => {
|
|
318
|
+
useEffect(() => { fetchData('/users', 'GET'); }, []);
|
|
319
|
+
fetchApi('getUser', 7); // apiMap.getUser(7) — ONE argument
|
|
320
|
+
fetchApiWith('updateUser', [7, { name: 'A' }]); // apiMap.updateUser(7, {...}) — spread
|
|
238
321
|
```
|
|
239
322
|
|
|
323
|
+
`fetchApi(key, data)` always passes the map entry exactly one argument; use
|
|
324
|
+
`fetchApiWith(key, [a, b])` for multi-argument entries.
|
|
325
|
+
|
|
240
326
|
Treat `useApi` as a thin axios wrapper, not a caching/dedup layer. For
|
|
241
327
|
cache, the consumer brings their own (React Query, SWR, etc.).
|
|
242
328
|
|