@matteoaliano/forest-ui 0.5.0 → 0.5.2
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/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/skills/forest-agency/SKILL.md +1 -1
- package/skills/forest-agency/references/components.md +2 -2
- package/skills/forest-agency/references/patterns.md +79 -0
- package/skills/forest-alkemy-plus/SKILL.md +1 -1
- package/skills/forest-alkemy-plus/references/components.md +2 -2
- package/skills/forest-alkemy-plus/references/patterns.md +79 -0
- package/skills/forest-external/SKILL.md +1 -1
- package/skills/forest-external/references/components.md +2 -2
- package/skills/forest-external/references/patterns.md +79 -0
- package/skills/forest-internal/SKILL.md +1 -1
- package/skills/forest-internal/references/components.md +2 -2
- package/skills/forest-internal/references/patterns.md +79 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ name: forest-agency
|
|
|
3
3
|
description: Forest UI Design System rules for the Agency (charcoal/red) preset. Enforces correct imports, component usage, and theming with @matteoaliano/forest-ui. Use when the project uses forest-ui, forest-agency preset, or when user builds UI components in a forest-ui project. Triggers on "forest", "forest-ui", "forest agency", "@matteoaliano/forest-ui".
|
|
4
4
|
metadata:
|
|
5
5
|
author: Forest Design System
|
|
6
|
-
version: 0.5.
|
|
6
|
+
version: 0.5.2
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Forest UI — Agency Preset
|
|
@@ -75,7 +75,7 @@ import Button from "@mui/material/Button";
|
|
|
75
75
|
| `Logo` | `import { Logo } from "@matteoaliano/forest-ui"` | `product: "wsuite" \| "studio" \| "feedati"`, `variant: "logo" \| "logomark"`, `sx` | `product="wsuite"`, `variant="logo"`, `height={32}` |
|
|
76
76
|
| `Rating` | `import { Rating } from "@matteoaliano/forest-ui"` | `value`, `onChange`, `precision`, `max`, `size`, `readOnly`, `disabled` |
|
|
77
77
|
| `Table` family | `import { Table, TableHead, TableBody, TableRow, TableCell, TableContainer } from "@matteoaliano/forest-ui"` | Table: `size: "small" \| "medium"`, `stickyHeader`; TableCell: `align`, `padding`, `sortDirection`, `variant`; TableRow: `hover`, `selected` | — |
|
|
78
|
-
| `DataGrid` | `import { DataGrid, type GridColDef } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density` | — |
|
|
78
|
+
| `DataGrid` | `import { DataGrid, type GridColDef, type GridRenderCellParams, type GridRowSelectionModel } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density`. Types: `GridColDef`, `GridRowsProp`, `GridRowParams`, `GridCellParams`, `GridRenderCellParams`, `GridRowSelectionModel`, `GridSortModel`, `GridFilterModel`, `GridPaginationModel` | — |
|
|
79
79
|
| `List` family | `import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, ListItemAvatar, ListSubheader } from "@matteoaliano/forest-ui"` | `dense`, `disablePadding`; ListItemButton: `selected`, `disabled`; ListItemText: `primary`, `secondary` | — |
|
|
80
80
|
| `TableFooter` | `import { TableFooter } from "@matteoaliano/forest-ui"` | `component`, `children` |
|
|
81
81
|
| `TablePagination` | `import { TablePagination } from "@matteoaliano/forest-ui"` | `count`, `page`, `rowsPerPage`, `onPageChange`, `onRowsPerPageChange` |
|
|
@@ -93,7 +93,7 @@ import Button from "@mui/material/Button";
|
|
|
93
93
|
| `Card` family | `import { Card, CardContent, CardHeader, CardActions, CardMedia } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation`, `raised`; CardHeader: `title`, `subheader`, `avatar`, `action` | — |
|
|
94
94
|
| `Paper` | `import { Paper } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation` (0-24), `square` | — |
|
|
95
95
|
| `CardActionArea` | `import { CardActionArea } from "@matteoaliano/forest-ui"` | `onClick`, `href`, `disabled` |
|
|
96
|
-
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"` |
|
|
96
|
+
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"`, `hideBackdrop` | `anchor="right"`, `hideBackdrop={true}` |
|
|
97
97
|
| `SwipeableDrawer` | `import { SwipeableDrawer } from "@matteoaliano/forest-ui"` | `onOpen` (required), `onClose` (required), `open`, `anchor`, `swipeAreaWidth` |
|
|
98
98
|
|
|
99
99
|
## Feedback
|
|
@@ -223,6 +223,66 @@ function AppShell({ children }) {
|
|
|
223
223
|
- `height: "100%"` on SidebarNav — sidebar border extends full height
|
|
224
224
|
- `backgroundColor: "background.paper"` on content — contrasts with sidebar/AppBar background
|
|
225
225
|
|
|
226
|
+
### Detail Drawer
|
|
227
|
+
|
|
228
|
+
Use the `Drawer` component when a user clicks an item (table row, card, list entry) to view or edit its details in a side panel. The Drawer defaults to `anchor="right"` and `hideBackdrop={true}`, so it opens on the right without dimming the page — the user retains full visibility of the content behind it.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { useState } from "react";
|
|
232
|
+
import {
|
|
233
|
+
Drawer, Box, Typography, IconButton, Divider, Chip, Stack,
|
|
234
|
+
DataGrid, type GridColDef,
|
|
235
|
+
} from "@matteoaliano/forest-ui";
|
|
236
|
+
import CloseOutlined from "@mui/icons-material/CloseOutlined";
|
|
237
|
+
|
|
238
|
+
function KeywordTable({ rows, columns }: { rows: any[]; columns: GridColDef[] }) {
|
|
239
|
+
const [selected, setSelected] = useState<any | null>(null);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<Box sx={{ display: "flex", height: "100%" }}>
|
|
243
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
244
|
+
<DataGrid
|
|
245
|
+
rows={rows}
|
|
246
|
+
columns={columns}
|
|
247
|
+
onRowClick={(params) => setSelected(params.row)}
|
|
248
|
+
/>
|
|
249
|
+
</Box>
|
|
250
|
+
|
|
251
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
252
|
+
{selected && (
|
|
253
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
254
|
+
{/* Header */}
|
|
255
|
+
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2 }}>
|
|
256
|
+
<Typography variant="h6">{selected.name}</Typography>
|
|
257
|
+
<IconButton size="small" onClick={() => setSelected(null)}>
|
|
258
|
+
<CloseOutlined />
|
|
259
|
+
</IconButton>
|
|
260
|
+
</Box>
|
|
261
|
+
<Divider sx={{ mb: 2 }} />
|
|
262
|
+
|
|
263
|
+
{/* Detail content */}
|
|
264
|
+
<Stack direction="row" spacing={1} sx={{ mb: 3 }}>
|
|
265
|
+
<Chip label={`${selected.volume} vol`} size="small" />
|
|
266
|
+
<Chip label={selected.category} size="small" variant="outlined" />
|
|
267
|
+
</Stack>
|
|
268
|
+
<Typography variant="body2" color="text.secondary">
|
|
269
|
+
{selected.description}
|
|
270
|
+
</Typography>
|
|
271
|
+
</Box>
|
|
272
|
+
)}
|
|
273
|
+
</Drawer>
|
|
274
|
+
</Box>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Key points:**
|
|
280
|
+
- `anchor="right"` and `hideBackdrop={true}` are the Forest defaults — no need to set them
|
|
281
|
+
- The Drawer takes full viewport height and overlays the right side of the page
|
|
282
|
+
- Always include a close button in the Drawer header
|
|
283
|
+
- Set a fixed `width` on the Drawer content (e.g. 400px)
|
|
284
|
+
- The content behind the Drawer remains fully visible and interactive
|
|
285
|
+
|
|
226
286
|
### Charts
|
|
227
287
|
|
|
228
288
|
Colors are automatically assigned from the theme's 12-series palette. Override with the `colors` prop if needed.
|
|
@@ -311,6 +371,25 @@ import CloseIcon from "@mui/icons-material/CloseOutlined";
|
|
|
311
371
|
// WRONG: manually building multi-select with Select + Checkbox
|
|
312
372
|
// CORRECT: use the MultiSelect component
|
|
313
373
|
<MultiSelect options={options} value={value} onChange={setValue} />
|
|
374
|
+
|
|
375
|
+
// WRONG: inline detail panel — a flex Box that sits inside the content area
|
|
376
|
+
// This is not a design system pattern and creates inconsistent layouts
|
|
377
|
+
<Box sx={{ display: "flex" }}>
|
|
378
|
+
<Box sx={{ flex: 1 }}><DataGrid ... /></Box>
|
|
379
|
+
{selected && (
|
|
380
|
+
<Box sx={{ width: 400, borderLeft: 1, borderColor: "divider", p: 2 }}>
|
|
381
|
+
{/* detail content sitting next to the table */}
|
|
382
|
+
</Box>
|
|
383
|
+
)}
|
|
384
|
+
</Box>
|
|
385
|
+
|
|
386
|
+
// CORRECT: use the Drawer component for detail panels
|
|
387
|
+
// It opens full viewport height on the right, without a backdrop
|
|
388
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
389
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
390
|
+
{/* detail content */}
|
|
391
|
+
</Box>
|
|
392
|
+
</Drawer>
|
|
314
393
|
```
|
|
315
394
|
|
|
316
395
|
## TypeScript Props
|
|
@@ -3,7 +3,7 @@ name: forest-alkemy-plus
|
|
|
3
3
|
description: Forest UI Design System rules for the Alkemy+ (charcoal/red) preset. Enforces correct imports, component usage, and theming with @matteoaliano/forest-ui. Use when the project uses forest-ui, forest-alkemy-plus preset, or when user builds UI components in a forest-ui project. Triggers on "forest", "forest-ui", "forest alkemy", "forest alkemy+", "@matteoaliano/forest-ui".
|
|
4
4
|
metadata:
|
|
5
5
|
author: Forest Design System
|
|
6
|
-
version: 0.5.
|
|
6
|
+
version: 0.5.2
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Forest UI — Alkemy+ Preset
|
|
@@ -75,7 +75,7 @@ import Button from "@mui/material/Button";
|
|
|
75
75
|
| `Logo` | `import { Logo } from "@matteoaliano/forest-ui"` | `product: "wsuite" \| "studio" \| "feedati"`, `variant: "logo" \| "logomark"`, `sx` | `product="wsuite"`, `variant="logo"`, `height={32}` |
|
|
76
76
|
| `Rating` | `import { Rating } from "@matteoaliano/forest-ui"` | `value`, `onChange`, `precision`, `max`, `size`, `readOnly`, `disabled` |
|
|
77
77
|
| `Table` family | `import { Table, TableHead, TableBody, TableRow, TableCell, TableContainer } from "@matteoaliano/forest-ui"` | Table: `size: "small" \| "medium"`, `stickyHeader`; TableCell: `align`, `padding`, `sortDirection`, `variant`; TableRow: `hover`, `selected` | — |
|
|
78
|
-
| `DataGrid` | `import { DataGrid, type GridColDef } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density` | — |
|
|
78
|
+
| `DataGrid` | `import { DataGrid, type GridColDef, type GridRenderCellParams, type GridRowSelectionModel } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density`. Types: `GridColDef`, `GridRowsProp`, `GridRowParams`, `GridCellParams`, `GridRenderCellParams`, `GridRowSelectionModel`, `GridSortModel`, `GridFilterModel`, `GridPaginationModel` | — |
|
|
79
79
|
| `List` family | `import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, ListItemAvatar, ListSubheader } from "@matteoaliano/forest-ui"` | `dense`, `disablePadding`; ListItemButton: `selected`, `disabled`; ListItemText: `primary`, `secondary` | — |
|
|
80
80
|
| `TableFooter` | `import { TableFooter } from "@matteoaliano/forest-ui"` | `component`, `children` |
|
|
81
81
|
| `TablePagination` | `import { TablePagination } from "@matteoaliano/forest-ui"` | `count`, `page`, `rowsPerPage`, `onPageChange`, `onRowsPerPageChange` |
|
|
@@ -93,7 +93,7 @@ import Button from "@mui/material/Button";
|
|
|
93
93
|
| `Card` family | `import { Card, CardContent, CardHeader, CardActions, CardMedia } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation`, `raised`; CardHeader: `title`, `subheader`, `avatar`, `action` | — |
|
|
94
94
|
| `Paper` | `import { Paper } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation` (0-24), `square` | — |
|
|
95
95
|
| `CardActionArea` | `import { CardActionArea } from "@matteoaliano/forest-ui"` | `onClick`, `href`, `disabled` |
|
|
96
|
-
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"` |
|
|
96
|
+
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"`, `hideBackdrop` | `anchor="right"`, `hideBackdrop={true}` |
|
|
97
97
|
| `SwipeableDrawer` | `import { SwipeableDrawer } from "@matteoaliano/forest-ui"` | `onOpen` (required), `onClose` (required), `open`, `anchor`, `swipeAreaWidth` |
|
|
98
98
|
|
|
99
99
|
## Feedback
|
|
@@ -223,6 +223,66 @@ function AppShell({ children }) {
|
|
|
223
223
|
- `height: "100%"` on SidebarNav — sidebar border extends full height
|
|
224
224
|
- `backgroundColor: "background.paper"` on content — contrasts with sidebar/AppBar background
|
|
225
225
|
|
|
226
|
+
### Detail Drawer
|
|
227
|
+
|
|
228
|
+
Use the `Drawer` component when a user clicks an item (table row, card, list entry) to view or edit its details in a side panel. The Drawer defaults to `anchor="right"` and `hideBackdrop={true}`, so it opens on the right without dimming the page — the user retains full visibility of the content behind it.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { useState } from "react";
|
|
232
|
+
import {
|
|
233
|
+
Drawer, Box, Typography, IconButton, Divider, Chip, Stack,
|
|
234
|
+
DataGrid, type GridColDef,
|
|
235
|
+
} from "@matteoaliano/forest-ui";
|
|
236
|
+
import CloseOutlined from "@mui/icons-material/CloseOutlined";
|
|
237
|
+
|
|
238
|
+
function KeywordTable({ rows, columns }: { rows: any[]; columns: GridColDef[] }) {
|
|
239
|
+
const [selected, setSelected] = useState<any | null>(null);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<Box sx={{ display: "flex", height: "100%" }}>
|
|
243
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
244
|
+
<DataGrid
|
|
245
|
+
rows={rows}
|
|
246
|
+
columns={columns}
|
|
247
|
+
onRowClick={(params) => setSelected(params.row)}
|
|
248
|
+
/>
|
|
249
|
+
</Box>
|
|
250
|
+
|
|
251
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
252
|
+
{selected && (
|
|
253
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
254
|
+
{/* Header */}
|
|
255
|
+
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2 }}>
|
|
256
|
+
<Typography variant="h6">{selected.name}</Typography>
|
|
257
|
+
<IconButton size="small" onClick={() => setSelected(null)}>
|
|
258
|
+
<CloseOutlined />
|
|
259
|
+
</IconButton>
|
|
260
|
+
</Box>
|
|
261
|
+
<Divider sx={{ mb: 2 }} />
|
|
262
|
+
|
|
263
|
+
{/* Detail content */}
|
|
264
|
+
<Stack direction="row" spacing={1} sx={{ mb: 3 }}>
|
|
265
|
+
<Chip label={`${selected.volume} vol`} size="small" />
|
|
266
|
+
<Chip label={selected.category} size="small" variant="outlined" />
|
|
267
|
+
</Stack>
|
|
268
|
+
<Typography variant="body2" color="text.secondary">
|
|
269
|
+
{selected.description}
|
|
270
|
+
</Typography>
|
|
271
|
+
</Box>
|
|
272
|
+
)}
|
|
273
|
+
</Drawer>
|
|
274
|
+
</Box>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Key points:**
|
|
280
|
+
- `anchor="right"` and `hideBackdrop={true}` are the Forest defaults — no need to set them
|
|
281
|
+
- The Drawer takes full viewport height and overlays the right side of the page
|
|
282
|
+
- Always include a close button in the Drawer header
|
|
283
|
+
- Set a fixed `width` on the Drawer content (e.g. 400px)
|
|
284
|
+
- The content behind the Drawer remains fully visible and interactive
|
|
285
|
+
|
|
226
286
|
### Charts
|
|
227
287
|
|
|
228
288
|
Colors are automatically assigned from the theme's 12-series palette. Override with the `colors` prop if needed.
|
|
@@ -311,6 +371,25 @@ import CloseIcon from "@mui/icons-material/CloseOutlined";
|
|
|
311
371
|
// WRONG: manually building multi-select with Select + Checkbox
|
|
312
372
|
// CORRECT: use the MultiSelect component
|
|
313
373
|
<MultiSelect options={options} value={value} onChange={setValue} />
|
|
374
|
+
|
|
375
|
+
// WRONG: inline detail panel — a flex Box that sits inside the content area
|
|
376
|
+
// This is not a design system pattern and creates inconsistent layouts
|
|
377
|
+
<Box sx={{ display: "flex" }}>
|
|
378
|
+
<Box sx={{ flex: 1 }}><DataGrid ... /></Box>
|
|
379
|
+
{selected && (
|
|
380
|
+
<Box sx={{ width: 400, borderLeft: 1, borderColor: "divider", p: 2 }}>
|
|
381
|
+
{/* detail content sitting next to the table */}
|
|
382
|
+
</Box>
|
|
383
|
+
)}
|
|
384
|
+
</Box>
|
|
385
|
+
|
|
386
|
+
// CORRECT: use the Drawer component for detail panels
|
|
387
|
+
// It opens full viewport height on the right, without a backdrop
|
|
388
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
389
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
390
|
+
{/* detail content */}
|
|
391
|
+
</Box>
|
|
392
|
+
</Drawer>
|
|
314
393
|
```
|
|
315
394
|
|
|
316
395
|
## TypeScript Props
|
|
@@ -3,7 +3,7 @@ name: forest-external
|
|
|
3
3
|
description: Forest UI Design System rules for the External (violet) preset. Enforces correct imports, component usage, and theming with @matteoaliano/forest-ui. Use when the project uses forest-ui, forest-external preset, or when user builds UI components in a forest-ui project. Triggers on "forest", "forest-ui", "forest external", "@matteoaliano/forest-ui".
|
|
4
4
|
metadata:
|
|
5
5
|
author: Forest Design System
|
|
6
|
-
version: 0.5.
|
|
6
|
+
version: 0.5.2
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Forest UI — External Preset
|
|
@@ -75,7 +75,7 @@ import Button from "@mui/material/Button";
|
|
|
75
75
|
| `Logo` | `import { Logo } from "@matteoaliano/forest-ui"` | `product: "wsuite" \| "studio" \| "feedati"`, `variant: "logo" \| "logomark"`, `sx` | `product="wsuite"`, `variant="logo"`, `height={32}` |
|
|
76
76
|
| `Rating` | `import { Rating } from "@matteoaliano/forest-ui"` | `value`, `onChange`, `precision`, `max`, `size`, `readOnly`, `disabled` |
|
|
77
77
|
| `Table` family | `import { Table, TableHead, TableBody, TableRow, TableCell, TableContainer } from "@matteoaliano/forest-ui"` | Table: `size: "small" \| "medium"`, `stickyHeader`; TableCell: `align`, `padding`, `sortDirection`, `variant`; TableRow: `hover`, `selected` | — |
|
|
78
|
-
| `DataGrid` | `import { DataGrid, type GridColDef } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density` | — |
|
|
78
|
+
| `DataGrid` | `import { DataGrid, type GridColDef, type GridRenderCellParams, type GridRowSelectionModel } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density`. Types: `GridColDef`, `GridRowsProp`, `GridRowParams`, `GridCellParams`, `GridRenderCellParams`, `GridRowSelectionModel`, `GridSortModel`, `GridFilterModel`, `GridPaginationModel` | — |
|
|
79
79
|
| `List` family | `import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, ListItemAvatar, ListSubheader } from "@matteoaliano/forest-ui"` | `dense`, `disablePadding`; ListItemButton: `selected`, `disabled`; ListItemText: `primary`, `secondary` | — |
|
|
80
80
|
| `TableFooter` | `import { TableFooter } from "@matteoaliano/forest-ui"` | `component`, `children` |
|
|
81
81
|
| `TablePagination` | `import { TablePagination } from "@matteoaliano/forest-ui"` | `count`, `page`, `rowsPerPage`, `onPageChange`, `onRowsPerPageChange` |
|
|
@@ -93,7 +93,7 @@ import Button from "@mui/material/Button";
|
|
|
93
93
|
| `Card` family | `import { Card, CardContent, CardHeader, CardActions, CardMedia } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation`, `raised`; CardHeader: `title`, `subheader`, `avatar`, `action` | — |
|
|
94
94
|
| `Paper` | `import { Paper } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation` (0-24), `square` | — |
|
|
95
95
|
| `CardActionArea` | `import { CardActionArea } from "@matteoaliano/forest-ui"` | `onClick`, `href`, `disabled` |
|
|
96
|
-
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"` |
|
|
96
|
+
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"`, `hideBackdrop` | `anchor="right"`, `hideBackdrop={true}` |
|
|
97
97
|
| `SwipeableDrawer` | `import { SwipeableDrawer } from "@matteoaliano/forest-ui"` | `onOpen` (required), `onClose` (required), `open`, `anchor`, `swipeAreaWidth` |
|
|
98
98
|
|
|
99
99
|
## Feedback
|
|
@@ -223,6 +223,66 @@ function AppShell({ children }) {
|
|
|
223
223
|
- `height: "100%"` on SidebarNav — sidebar border extends full height
|
|
224
224
|
- `backgroundColor: "background.paper"` on content — contrasts with sidebar/AppBar background
|
|
225
225
|
|
|
226
|
+
### Detail Drawer
|
|
227
|
+
|
|
228
|
+
Use the `Drawer` component when a user clicks an item (table row, card, list entry) to view or edit its details in a side panel. The Drawer defaults to `anchor="right"` and `hideBackdrop={true}`, so it opens on the right without dimming the page — the user retains full visibility of the content behind it.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { useState } from "react";
|
|
232
|
+
import {
|
|
233
|
+
Drawer, Box, Typography, IconButton, Divider, Chip, Stack,
|
|
234
|
+
DataGrid, type GridColDef,
|
|
235
|
+
} from "@matteoaliano/forest-ui";
|
|
236
|
+
import CloseOutlined from "@mui/icons-material/CloseOutlined";
|
|
237
|
+
|
|
238
|
+
function KeywordTable({ rows, columns }: { rows: any[]; columns: GridColDef[] }) {
|
|
239
|
+
const [selected, setSelected] = useState<any | null>(null);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<Box sx={{ display: "flex", height: "100%" }}>
|
|
243
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
244
|
+
<DataGrid
|
|
245
|
+
rows={rows}
|
|
246
|
+
columns={columns}
|
|
247
|
+
onRowClick={(params) => setSelected(params.row)}
|
|
248
|
+
/>
|
|
249
|
+
</Box>
|
|
250
|
+
|
|
251
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
252
|
+
{selected && (
|
|
253
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
254
|
+
{/* Header */}
|
|
255
|
+
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2 }}>
|
|
256
|
+
<Typography variant="h6">{selected.name}</Typography>
|
|
257
|
+
<IconButton size="small" onClick={() => setSelected(null)}>
|
|
258
|
+
<CloseOutlined />
|
|
259
|
+
</IconButton>
|
|
260
|
+
</Box>
|
|
261
|
+
<Divider sx={{ mb: 2 }} />
|
|
262
|
+
|
|
263
|
+
{/* Detail content */}
|
|
264
|
+
<Stack direction="row" spacing={1} sx={{ mb: 3 }}>
|
|
265
|
+
<Chip label={`${selected.volume} vol`} size="small" />
|
|
266
|
+
<Chip label={selected.category} size="small" variant="outlined" />
|
|
267
|
+
</Stack>
|
|
268
|
+
<Typography variant="body2" color="text.secondary">
|
|
269
|
+
{selected.description}
|
|
270
|
+
</Typography>
|
|
271
|
+
</Box>
|
|
272
|
+
)}
|
|
273
|
+
</Drawer>
|
|
274
|
+
</Box>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Key points:**
|
|
280
|
+
- `anchor="right"` and `hideBackdrop={true}` are the Forest defaults — no need to set them
|
|
281
|
+
- The Drawer takes full viewport height and overlays the right side of the page
|
|
282
|
+
- Always include a close button in the Drawer header
|
|
283
|
+
- Set a fixed `width` on the Drawer content (e.g. 400px)
|
|
284
|
+
- The content behind the Drawer remains fully visible and interactive
|
|
285
|
+
|
|
226
286
|
### Charts
|
|
227
287
|
|
|
228
288
|
Colors are automatically assigned from the theme's 12-series palette. Override with the `colors` prop if needed.
|
|
@@ -311,6 +371,25 @@ import CloseIcon from "@mui/icons-material/CloseOutlined";
|
|
|
311
371
|
// WRONG: manually building multi-select with Select + Checkbox
|
|
312
372
|
// CORRECT: use the MultiSelect component
|
|
313
373
|
<MultiSelect options={options} value={value} onChange={setValue} />
|
|
374
|
+
|
|
375
|
+
// WRONG: inline detail panel — a flex Box that sits inside the content area
|
|
376
|
+
// This is not a design system pattern and creates inconsistent layouts
|
|
377
|
+
<Box sx={{ display: "flex" }}>
|
|
378
|
+
<Box sx={{ flex: 1 }}><DataGrid ... /></Box>
|
|
379
|
+
{selected && (
|
|
380
|
+
<Box sx={{ width: 400, borderLeft: 1, borderColor: "divider", p: 2 }}>
|
|
381
|
+
{/* detail content sitting next to the table */}
|
|
382
|
+
</Box>
|
|
383
|
+
)}
|
|
384
|
+
</Box>
|
|
385
|
+
|
|
386
|
+
// CORRECT: use the Drawer component for detail panels
|
|
387
|
+
// It opens full viewport height on the right, without a backdrop
|
|
388
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
389
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
390
|
+
{/* detail content */}
|
|
391
|
+
</Box>
|
|
392
|
+
</Drawer>
|
|
314
393
|
```
|
|
315
394
|
|
|
316
395
|
## TypeScript Props
|
|
@@ -3,7 +3,7 @@ name: forest-internal
|
|
|
3
3
|
description: Forest UI Design System rules for the Internal (magenta) preset. Enforces correct imports, component usage, and theming with @matteoaliano/forest-ui. Use when the project uses forest-ui, forest-internal preset, or when user builds UI components in a forest-ui project. Triggers on "forest", "forest-ui", "forest internal", "@matteoaliano/forest-ui".
|
|
4
4
|
metadata:
|
|
5
5
|
author: Forest Design System
|
|
6
|
-
version: 0.5.
|
|
6
|
+
version: 0.5.2
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Forest UI — Internal Preset
|
|
@@ -75,7 +75,7 @@ import Button from "@mui/material/Button";
|
|
|
75
75
|
| `Logo` | `import { Logo } from "@matteoaliano/forest-ui"` | `product: "wsuite" \| "studio" \| "feedati"`, `variant: "logo" \| "logomark"`, `sx` | `product="wsuite"`, `variant="logo"`, `height={32}` |
|
|
76
76
|
| `Rating` | `import { Rating } from "@matteoaliano/forest-ui"` | `value`, `onChange`, `precision`, `max`, `size`, `readOnly`, `disabled` |
|
|
77
77
|
| `Table` family | `import { Table, TableHead, TableBody, TableRow, TableCell, TableContainer } from "@matteoaliano/forest-ui"` | Table: `size: "small" \| "medium"`, `stickyHeader`; TableCell: `align`, `padding`, `sortDirection`, `variant`; TableRow: `hover`, `selected` | — |
|
|
78
|
-
| `DataGrid` | `import { DataGrid, type GridColDef } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density` | — |
|
|
78
|
+
| `DataGrid` | `import { DataGrid, type GridColDef, type GridRenderCellParams, type GridRowSelectionModel } from "@matteoaliano/forest-ui"` | `rows`, `columns`, `paginationModel`, `sortModel`, `filterModel`, `checkboxSelection`, `loading`, `density`. Types: `GridColDef`, `GridRowsProp`, `GridRowParams`, `GridCellParams`, `GridRenderCellParams`, `GridRowSelectionModel`, `GridSortModel`, `GridFilterModel`, `GridPaginationModel` | — |
|
|
79
79
|
| `List` family | `import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, ListItemAvatar, ListSubheader } from "@matteoaliano/forest-ui"` | `dense`, `disablePadding`; ListItemButton: `selected`, `disabled`; ListItemText: `primary`, `secondary` | — |
|
|
80
80
|
| `TableFooter` | `import { TableFooter } from "@matteoaliano/forest-ui"` | `component`, `children` |
|
|
81
81
|
| `TablePagination` | `import { TablePagination } from "@matteoaliano/forest-ui"` | `count`, `page`, `rowsPerPage`, `onPageChange`, `onRowsPerPageChange` |
|
|
@@ -93,7 +93,7 @@ import Button from "@mui/material/Button";
|
|
|
93
93
|
| `Card` family | `import { Card, CardContent, CardHeader, CardActions, CardMedia } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation`, `raised`; CardHeader: `title`, `subheader`, `avatar`, `action` | — |
|
|
94
94
|
| `Paper` | `import { Paper } from "@matteoaliano/forest-ui"` | `variant: "elevation" \| "outlined"`, `elevation` (0-24), `square` | — |
|
|
95
95
|
| `CardActionArea` | `import { CardActionArea } from "@matteoaliano/forest-ui"` | `onClick`, `href`, `disabled` |
|
|
96
|
-
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"` |
|
|
96
|
+
| `Drawer` | `import { Drawer } from "@matteoaliano/forest-ui"` | `open`, `onClose`, `anchor: "left" \| "right" \| "top" \| "bottom"`, `variant: "permanent" \| "persistent" \| "temporary"`, `hideBackdrop` | `anchor="right"`, `hideBackdrop={true}` |
|
|
97
97
|
| `SwipeableDrawer` | `import { SwipeableDrawer } from "@matteoaliano/forest-ui"` | `onOpen` (required), `onClose` (required), `open`, `anchor`, `swipeAreaWidth` |
|
|
98
98
|
|
|
99
99
|
## Feedback
|
|
@@ -223,6 +223,66 @@ function AppShell({ children }) {
|
|
|
223
223
|
- `height: "100%"` on SidebarNav — sidebar border extends full height
|
|
224
224
|
- `backgroundColor: "background.paper"` on content — contrasts with sidebar/AppBar background
|
|
225
225
|
|
|
226
|
+
### Detail Drawer
|
|
227
|
+
|
|
228
|
+
Use the `Drawer` component when a user clicks an item (table row, card, list entry) to view or edit its details in a side panel. The Drawer defaults to `anchor="right"` and `hideBackdrop={true}`, so it opens on the right without dimming the page — the user retains full visibility of the content behind it.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { useState } from "react";
|
|
232
|
+
import {
|
|
233
|
+
Drawer, Box, Typography, IconButton, Divider, Chip, Stack,
|
|
234
|
+
DataGrid, type GridColDef,
|
|
235
|
+
} from "@matteoaliano/forest-ui";
|
|
236
|
+
import CloseOutlined from "@mui/icons-material/CloseOutlined";
|
|
237
|
+
|
|
238
|
+
function KeywordTable({ rows, columns }: { rows: any[]; columns: GridColDef[] }) {
|
|
239
|
+
const [selected, setSelected] = useState<any | null>(null);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<Box sx={{ display: "flex", height: "100%" }}>
|
|
243
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
244
|
+
<DataGrid
|
|
245
|
+
rows={rows}
|
|
246
|
+
columns={columns}
|
|
247
|
+
onRowClick={(params) => setSelected(params.row)}
|
|
248
|
+
/>
|
|
249
|
+
</Box>
|
|
250
|
+
|
|
251
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
252
|
+
{selected && (
|
|
253
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
254
|
+
{/* Header */}
|
|
255
|
+
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2 }}>
|
|
256
|
+
<Typography variant="h6">{selected.name}</Typography>
|
|
257
|
+
<IconButton size="small" onClick={() => setSelected(null)}>
|
|
258
|
+
<CloseOutlined />
|
|
259
|
+
</IconButton>
|
|
260
|
+
</Box>
|
|
261
|
+
<Divider sx={{ mb: 2 }} />
|
|
262
|
+
|
|
263
|
+
{/* Detail content */}
|
|
264
|
+
<Stack direction="row" spacing={1} sx={{ mb: 3 }}>
|
|
265
|
+
<Chip label={`${selected.volume} vol`} size="small" />
|
|
266
|
+
<Chip label={selected.category} size="small" variant="outlined" />
|
|
267
|
+
</Stack>
|
|
268
|
+
<Typography variant="body2" color="text.secondary">
|
|
269
|
+
{selected.description}
|
|
270
|
+
</Typography>
|
|
271
|
+
</Box>
|
|
272
|
+
)}
|
|
273
|
+
</Drawer>
|
|
274
|
+
</Box>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Key points:**
|
|
280
|
+
- `anchor="right"` and `hideBackdrop={true}` are the Forest defaults — no need to set them
|
|
281
|
+
- The Drawer takes full viewport height and overlays the right side of the page
|
|
282
|
+
- Always include a close button in the Drawer header
|
|
283
|
+
- Set a fixed `width` on the Drawer content (e.g. 400px)
|
|
284
|
+
- The content behind the Drawer remains fully visible and interactive
|
|
285
|
+
|
|
226
286
|
### Charts
|
|
227
287
|
|
|
228
288
|
Colors are automatically assigned from the theme's 12-series palette. Override with the `colors` prop if needed.
|
|
@@ -311,6 +371,25 @@ import CloseIcon from "@mui/icons-material/CloseOutlined";
|
|
|
311
371
|
// WRONG: manually building multi-select with Select + Checkbox
|
|
312
372
|
// CORRECT: use the MultiSelect component
|
|
313
373
|
<MultiSelect options={options} value={value} onChange={setValue} />
|
|
374
|
+
|
|
375
|
+
// WRONG: inline detail panel — a flex Box that sits inside the content area
|
|
376
|
+
// This is not a design system pattern and creates inconsistent layouts
|
|
377
|
+
<Box sx={{ display: "flex" }}>
|
|
378
|
+
<Box sx={{ flex: 1 }}><DataGrid ... /></Box>
|
|
379
|
+
{selected && (
|
|
380
|
+
<Box sx={{ width: 400, borderLeft: 1, borderColor: "divider", p: 2 }}>
|
|
381
|
+
{/* detail content sitting next to the table */}
|
|
382
|
+
</Box>
|
|
383
|
+
)}
|
|
384
|
+
</Box>
|
|
385
|
+
|
|
386
|
+
// CORRECT: use the Drawer component for detail panels
|
|
387
|
+
// It opens full viewport height on the right, without a backdrop
|
|
388
|
+
<Drawer open={!!selected} onClose={() => setSelected(null)}>
|
|
389
|
+
<Box sx={{ width: 400, p: 3 }}>
|
|
390
|
+
{/* detail content */}
|
|
391
|
+
</Box>
|
|
392
|
+
</Drawer>
|
|
314
393
|
```
|
|
315
394
|
|
|
316
395
|
## TypeScript Props
|