@matteoaliano/forest-ui 1.0.0 โ†’ 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.
package/bin/sync.mjs CHANGED
@@ -3,94 +3,59 @@
3
3
  /**
4
4
  * forest-ui sync
5
5
  *
6
- * Copies skill folders into the consuming project's .claude/skills/
7
- * directory so Claude Code automatically discovers Forest UI preset rules.
6
+ * DEPRECATED for consumers โ€” documentation + enforcement now ship as a Claude
7
+ * Code plugin. Copying loose skill files is no longer supported because stale
8
+ * copies drift from the plugin's hook.
9
+ *
10
+ * `--internal` (used by the monorepo's `npm run sync`) still propagates the
11
+ * skill source to the dogfood `.claude/skills/` copy and the plugin bundle.
8
12
  */
9
13
 
10
- import { readFileSync, mkdirSync, existsSync, readdirSync, cpSync, rmSync } from "node:fs";
14
+ import { mkdirSync, readdirSync, cpSync } from "node:fs";
11
15
  import { resolve, dirname } from "node:path";
12
16
  import { fileURLToPath } from "node:url";
13
17
 
14
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
15
19
  const skillsDir = resolve(__dirname, "..", "skills");
16
20
 
17
- // Find the consuming project root (walk up until we find package.json)
18
- function findProjectRoot(startDir) {
19
- let dir = startDir;
20
- while (dir !== dirname(dir)) {
21
- if (existsSync(resolve(dir, "package.json"))) {
22
- try {
23
- const pkg = JSON.parse(readFileSync(resolve(dir, "package.json"), "utf-8"));
24
- if (pkg.name !== "@matteoaliano/forest-ui") return dir;
25
- } catch {
26
- return dir;
27
- }
28
- }
29
- dir = dirname(dir);
30
- }
31
- return process.cwd();
32
- }
33
-
34
- const projectRoot = findProjectRoot(process.cwd());
21
+ if (!process.argv.includes("--internal")) {
22
+ console.log(`
23
+ ๐ŸŒฒ Forest UI โ€” \`sync\` is deprecated
35
24
 
36
- console.log(`\n๐ŸŒฒ Forest UI โ€” Syncing skills\n`);
37
- console.log(` Project root: ${projectRoot}\n`);
25
+ Skills are now delivered through the Forest Design System Claude Code
26
+ plugin, which also ships design-system enforcement hooks. Install it:
38
27
 
39
- // Clean up legacy guideline files from pre-v0.4.1
40
- const legacyPaths = [
41
- resolve(projectRoot, ".claude", "forest-ui.md"),
42
- resolve(projectRoot, ".cursor", "rules", "forest-ui.mdc"),
43
- resolve(projectRoot, ".gemini", "forest-ui.md"),
44
- resolve(projectRoot, ".antigravity", "rules.md"),
45
- ];
28
+ /plugin marketplace add Witailer/wtl-design-system-forest
29
+ /plugin install forest-ui@forest-design-system
46
30
 
47
- let cleaned = 0;
48
- for (const legacyPath of legacyPaths) {
49
- if (existsSync(legacyPath)) {
50
- try {
51
- rmSync(legacyPath);
52
- const rel = legacyPath.replace(projectRoot + "/", "");
53
- console.log(` ๐Ÿงน Removed legacy ${rel}`);
54
- cleaned++;
55
- } catch (err) {
56
- const rel = legacyPath.replace(projectRoot + "/", "");
57
- console.log(` โš ๏ธ Could not remove ${rel} (${err.message})`);
58
- }
59
- }
31
+ No files were copied. If you previously synced, you can delete
32
+ .claude/skills/forest-alkemy-plus/ โ€” the plugin replaces it.
33
+ `);
34
+ process.exit(0);
60
35
  }
61
- if (cleaned > 0) console.log();
62
36
 
63
- let synced = 0;
64
- let total = 0;
37
+ // โ”€โ”€ Internal monorepo sync: skills/ โ†’ dogfood + plugin bundle โ”€โ”€
38
+ const repoRoot = resolve(__dirname, "..", "..", "..");
39
+ const targets = [
40
+ resolve(repoRoot, ".claude", "skills"),
41
+ resolve(repoRoot, "plugins", "forest-ui", "skills"),
42
+ ];
65
43
 
66
- if (!existsSync(skillsDir)) {
67
- console.log(` โš ๏ธ No skills directory found, nothing to sync.\n`);
68
- process.exit(0);
69
- }
44
+ console.log(`\n๐ŸŒฒ Forest UI โ€” Syncing skills (internal)\n`);
70
45
 
71
46
  const skillFolders = readdirSync(skillsDir, { withFileTypes: true })
72
- .filter((d) => d.isDirectory())
73
- .map((d) => d.name);
74
-
75
- if (skillFolders.length === 0) {
76
- console.log(` โš ๏ธ No skill folders found, nothing to sync.\n`);
77
- process.exit(0);
78
- }
47
+ .filter((d) => d.isDirectory())
48
+ .map((d) => d.name);
79
49
 
80
- const claudeSkillsDir = resolve(projectRoot, ".claude", "skills");
81
-
82
- for (const folder of skillFolders) {
83
- const src = resolve(skillsDir, folder);
84
- const dest = resolve(claudeSkillsDir, folder);
85
- total++;
86
- try {
87
- mkdirSync(dest, { recursive: true });
88
- cpSync(src, dest, { recursive: true });
89
- console.log(` โœ… .claude/skills/${folder}/`);
90
- synced++;
91
- } catch (err) {
92
- console.log(` โš ๏ธ .claude/skills/${folder}/ skipped (${err.message})`);
93
- }
50
+ let synced = 0;
51
+ for (const target of targets) {
52
+ for (const folder of skillFolders) {
53
+ const dest = resolve(target, folder);
54
+ mkdirSync(dest, { recursive: true });
55
+ cpSync(resolve(skillsDir, folder), dest, { recursive: true });
56
+ console.log(` โœ… ${dest.replace(repoRoot + "/", "")}/`);
57
+ synced++;
58
+ }
94
59
  }
95
60
 
96
- console.log(`\n Synced ${synced}/${total} skills.\n`);
61
+ console.log(`\n Synced ${skillFolders.length} skill(s) to ${targets.length} target(s) (${synced} copies).\n`);
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Theme } from '@mui/material/styles';
2
+ import { Theme, SxProps } from '@mui/material/styles';
3
3
  export { useColorScheme } from '@mui/material/styles';
4
4
  import * as _mui_material from '@mui/material';
5
5
  import { BoxProps } from '@mui/material';
@@ -369,6 +369,78 @@ interface SidebarItemProps extends ListItemButtonProps {
369
369
  }
370
370
  declare function SidebarItem({ icon, label, endAdornment, sx, ...rest }: SidebarItemProps): react_jsx_runtime.JSX.Element;
371
371
 
372
+ interface AppShellNavItem {
373
+ label: string;
374
+ icon: React__default.ReactNode;
375
+ active?: boolean;
376
+ href?: string;
377
+ onClick?: () => void;
378
+ /** Router escape โ€” e.g. Next.js Link or React Router Link. */
379
+ component?: React__default.ElementType;
380
+ /** Rendered after the label when expanded (e.g. a count Chip). */
381
+ endAdornment?: React__default.ReactNode;
382
+ }
383
+ interface AppShellProps {
384
+ /** Data-driven sidebar nav. */
385
+ navItems?: AppShellNavItem[];
386
+ /** Escape hatch: full control over sidebar content. Overrides navItems. */
387
+ nav?: React__default.ReactNode;
388
+ /** Product brand passed to <Logo>. Default "studio". */
389
+ product?: LogoProduct;
390
+ /** Logomark (default) or the full wordmark logo. */
391
+ logoVariant?: "logomark" | "full";
392
+ /** Escape hatch: fully custom brand node (overrides product/logoVariant). */
393
+ brand?: React__default.ReactNode;
394
+ /** Center search: true โ†’ default <Search>; node โ†’ custom; omit โ†’ none. */
395
+ search?: React__default.ReactNode | boolean;
396
+ /** Right-side AppBar actions. The mandatory color-mode toggle is rendered
397
+ * by AppShell itself, before these. */
398
+ actions?: React__default.ReactNode;
399
+ sidebarBehavior?: "permanent" | "hover";
400
+ defaultSidebarOpen?: boolean;
401
+ /** The page content โ€” expected to be a <Page>. */
402
+ children: React__default.ReactNode;
403
+ }
404
+ /**
405
+ * The mandatory top-level layout for authenticated Forest UI surfaces: a
406
+ * sticky AppBar (brand / search / actions + the color-mode toggle) over a
407
+ * SidebarNav and a main content area. Render a <Page> as children.
408
+ *
409
+ * Below the "sm" breakpoint the sidebar becomes a temporary overlay drawer
410
+ * opened by a hamburger button in the AppBar.
411
+ */
412
+ declare function AppShell({ navItems, nav, product, logoVariant, brand, search, actions, sidebarBehavior, defaultSidebarOpen, children, }: AppShellProps): react_jsx_runtime.JSX.Element;
413
+
414
+ interface PageBreadcrumb {
415
+ label: string;
416
+ href?: string;
417
+ onClick?: () => void;
418
+ /** Router escape โ€” e.g. Next.js Link or React Router Link. */
419
+ component?: React__default.ElementType;
420
+ }
421
+ interface PageProps {
422
+ /** Page title. Rendered as Typography variant="h5". */
423
+ title: string;
424
+ /** Breadcrumb trail rendered above the title. Omit for pages without one. */
425
+ breadcrumbs?: PageBreadcrumb[];
426
+ /** Right-aligned header actions (e.g. a primary Button). */
427
+ actions?: React__default.ReactNode;
428
+ /** Drop the default 24px gutters for full-bleed pages. */
429
+ disableGutters?: boolean;
430
+ /** Constrain and center the content column. Default: full width. */
431
+ maxWidth?: number | string;
432
+ sx?: SxProps<Theme>;
433
+ children?: React__default.ReactNode;
434
+ }
435
+ /**
436
+ * The mandatory page-content scaffold rendered inside the App Shell's main
437
+ * slot. Owns the flat `background.paper` surface and the standard gutters, and
438
+ * renders the page header (breadcrumbs โ†’ title + actions). Everything below
439
+ * the header goes in `children` โ€” widgets, charts, and tables belong inside
440
+ * `<Card>`s there.
441
+ */
442
+ declare function Page({ title, breadcrumbs, actions, disableGutters, maxWidth, sx, children, }: PageProps): react_jsx_runtime.JSX.Element;
443
+
372
444
  declare const Box: _mui_types.OverridableComponent<_mui_system.BoxTypeMap<{}, "div", _mui_material.Theme>>;
373
445
 
374
446
  declare const Stack: _mui_material_OverridableComponent.OverridableComponent<_mui_material.StackTypeMap<{}, "div">>;
@@ -408,4 +480,4 @@ declare function ScatterChart({ series, colors, ...props }: ScatterChartProps):
408
480
  type GaugeProps = GaugeProps$1;
409
481
  declare function Gauge(props: GaugeProps): react_jsx_runtime.JSX.Element;
410
482
 
411
- export { AppBarNavItem, type AppBarNavItemProps, BarChart, type BarChartProps, Box, Button, ButtonGroup, type ButtonProps, Card, type CardProps, Chip, Container, DatePicker, type DatePickerProps, Drawer, Fab, type ForestCardColor, type ForestChipColor, type ForestChipProps, ForestProvider, type ForestProviderProps, Gauge, Grid, IconButton, type IconButtonProps, type IconButtonVariant, LineChart, type LineChartProps, Logo, type LogoProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, Paper, PieChart, type PieChartProps, Popover, Portal, ScatterChart, Search, type SearchProps, Select, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarNavProps, Stack, Switch, Tooltip, useChartColors, useSidebar };
483
+ export { AppBarNavItem, type AppBarNavItemProps, AppShell, type AppShellNavItem, type AppShellProps, BarChart, type BarChartProps, Box, Button, ButtonGroup, type ButtonProps, Card, type CardProps, Chip, Container, DatePicker, type DatePickerProps, Drawer, Fab, type ForestCardColor, type ForestChipColor, type ForestChipProps, ForestProvider, type ForestProviderProps, Gauge, Grid, IconButton, type IconButtonProps, type IconButtonVariant, LineChart, type LineChartProps, Logo, type LogoProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, Page, type PageBreadcrumb, type PageProps, Paper, PieChart, type PieChartProps, Popover, Portal, ScatterChart, Search, type SearchProps, Select, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarNavProps, Stack, Switch, Tooltip, useChartColors, useSidebar };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Theme } from '@mui/material/styles';
2
+ import { Theme, SxProps } from '@mui/material/styles';
3
3
  export { useColorScheme } from '@mui/material/styles';
4
4
  import * as _mui_material from '@mui/material';
5
5
  import { BoxProps } from '@mui/material';
@@ -369,6 +369,78 @@ interface SidebarItemProps extends ListItemButtonProps {
369
369
  }
370
370
  declare function SidebarItem({ icon, label, endAdornment, sx, ...rest }: SidebarItemProps): react_jsx_runtime.JSX.Element;
371
371
 
372
+ interface AppShellNavItem {
373
+ label: string;
374
+ icon: React__default.ReactNode;
375
+ active?: boolean;
376
+ href?: string;
377
+ onClick?: () => void;
378
+ /** Router escape โ€” e.g. Next.js Link or React Router Link. */
379
+ component?: React__default.ElementType;
380
+ /** Rendered after the label when expanded (e.g. a count Chip). */
381
+ endAdornment?: React__default.ReactNode;
382
+ }
383
+ interface AppShellProps {
384
+ /** Data-driven sidebar nav. */
385
+ navItems?: AppShellNavItem[];
386
+ /** Escape hatch: full control over sidebar content. Overrides navItems. */
387
+ nav?: React__default.ReactNode;
388
+ /** Product brand passed to <Logo>. Default "studio". */
389
+ product?: LogoProduct;
390
+ /** Logomark (default) or the full wordmark logo. */
391
+ logoVariant?: "logomark" | "full";
392
+ /** Escape hatch: fully custom brand node (overrides product/logoVariant). */
393
+ brand?: React__default.ReactNode;
394
+ /** Center search: true โ†’ default <Search>; node โ†’ custom; omit โ†’ none. */
395
+ search?: React__default.ReactNode | boolean;
396
+ /** Right-side AppBar actions. The mandatory color-mode toggle is rendered
397
+ * by AppShell itself, before these. */
398
+ actions?: React__default.ReactNode;
399
+ sidebarBehavior?: "permanent" | "hover";
400
+ defaultSidebarOpen?: boolean;
401
+ /** The page content โ€” expected to be a <Page>. */
402
+ children: React__default.ReactNode;
403
+ }
404
+ /**
405
+ * The mandatory top-level layout for authenticated Forest UI surfaces: a
406
+ * sticky AppBar (brand / search / actions + the color-mode toggle) over a
407
+ * SidebarNav and a main content area. Render a <Page> as children.
408
+ *
409
+ * Below the "sm" breakpoint the sidebar becomes a temporary overlay drawer
410
+ * opened by a hamburger button in the AppBar.
411
+ */
412
+ declare function AppShell({ navItems, nav, product, logoVariant, brand, search, actions, sidebarBehavior, defaultSidebarOpen, children, }: AppShellProps): react_jsx_runtime.JSX.Element;
413
+
414
+ interface PageBreadcrumb {
415
+ label: string;
416
+ href?: string;
417
+ onClick?: () => void;
418
+ /** Router escape โ€” e.g. Next.js Link or React Router Link. */
419
+ component?: React__default.ElementType;
420
+ }
421
+ interface PageProps {
422
+ /** Page title. Rendered as Typography variant="h5". */
423
+ title: string;
424
+ /** Breadcrumb trail rendered above the title. Omit for pages without one. */
425
+ breadcrumbs?: PageBreadcrumb[];
426
+ /** Right-aligned header actions (e.g. a primary Button). */
427
+ actions?: React__default.ReactNode;
428
+ /** Drop the default 24px gutters for full-bleed pages. */
429
+ disableGutters?: boolean;
430
+ /** Constrain and center the content column. Default: full width. */
431
+ maxWidth?: number | string;
432
+ sx?: SxProps<Theme>;
433
+ children?: React__default.ReactNode;
434
+ }
435
+ /**
436
+ * The mandatory page-content scaffold rendered inside the App Shell's main
437
+ * slot. Owns the flat `background.paper` surface and the standard gutters, and
438
+ * renders the page header (breadcrumbs โ†’ title + actions). Everything below
439
+ * the header goes in `children` โ€” widgets, charts, and tables belong inside
440
+ * `<Card>`s there.
441
+ */
442
+ declare function Page({ title, breadcrumbs, actions, disableGutters, maxWidth, sx, children, }: PageProps): react_jsx_runtime.JSX.Element;
443
+
372
444
  declare const Box: _mui_types.OverridableComponent<_mui_system.BoxTypeMap<{}, "div", _mui_material.Theme>>;
373
445
 
374
446
  declare const Stack: _mui_material_OverridableComponent.OverridableComponent<_mui_material.StackTypeMap<{}, "div">>;
@@ -408,4 +480,4 @@ declare function ScatterChart({ series, colors, ...props }: ScatterChartProps):
408
480
  type GaugeProps = GaugeProps$1;
409
481
  declare function Gauge(props: GaugeProps): react_jsx_runtime.JSX.Element;
410
482
 
411
- export { AppBarNavItem, type AppBarNavItemProps, BarChart, type BarChartProps, Box, Button, ButtonGroup, type ButtonProps, Card, type CardProps, Chip, Container, DatePicker, type DatePickerProps, Drawer, Fab, type ForestCardColor, type ForestChipColor, type ForestChipProps, ForestProvider, type ForestProviderProps, Gauge, Grid, IconButton, type IconButtonProps, type IconButtonVariant, LineChart, type LineChartProps, Logo, type LogoProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, Paper, PieChart, type PieChartProps, Popover, Portal, ScatterChart, Search, type SearchProps, Select, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarNavProps, Stack, Switch, Tooltip, useChartColors, useSidebar };
483
+ export { AppBarNavItem, type AppBarNavItemProps, AppShell, type AppShellNavItem, type AppShellProps, BarChart, type BarChartProps, Box, Button, ButtonGroup, type ButtonProps, Card, type CardProps, Chip, Container, DatePicker, type DatePickerProps, Drawer, Fab, type ForestCardColor, type ForestChipColor, type ForestChipProps, ForestProvider, type ForestProviderProps, Gauge, Grid, IconButton, type IconButtonProps, type IconButtonVariant, LineChart, type LineChartProps, Logo, type LogoProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, Page, type PageBreadcrumb, type PageProps, Paper, PieChart, type PieChartProps, Popover, Portal, ScatterChart, Search, type SearchProps, Select, SidebarItem, type SidebarItemProps, SidebarNav, type SidebarNavProps, Stack, Switch, Tooltip, useChartColors, useSidebar };