@recursica/adapter-mui-v7 1.1.0 → 1.3.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 (55) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/OVERSTYLING.md +1 -1
  3. package/SETUP.md +26 -3
  4. package/dist/adapter-mui-v7.cjs +69 -69
  5. package/dist/adapter-mui-v7.cjs.map +1 -1
  6. package/dist/adapter-mui-v7.css +1 -1
  7. package/dist/adapter-mui-v7.js +5955 -5739
  8. package/dist/adapter-mui-v7.js.map +1 -1
  9. package/dist/index.d.ts +69 -51
  10. package/llms.txt +1 -1
  11. package/package.json +4 -4
  12. package/recursica_brand.json +2 -2
  13. package/recursica_tokens.json +2 -2
  14. package/recursica_ui-kit.json +2 -2
  15. package/recursica_variables_scoped.css +7 -3
  16. package/src/components/Checkbox/Checkbox.module.css +1 -3
  17. package/src/components/Container/USAGE.md +0 -1
  18. package/src/components/FileInput/FileInput.module.css +8 -0
  19. package/src/components/FileUpload/FileUpload.module.css +1 -0
  20. package/src/components/FileUpload/FileUpload.tsx +1 -0
  21. package/src/components/Flex/USAGE.md +2 -1
  22. package/src/components/Group/USAGE.md +2 -1
  23. package/src/components/LayoutGrid/LAYOUT_GRID_IMPLEMENTATION_NOTES.md +82 -0
  24. package/src/components/LayoutGrid/LayoutGrid.columns.dom.test.tsx +78 -0
  25. package/src/components/{Grid/Grid.module.css → LayoutGrid/LayoutGrid.module.css} +11 -10
  26. package/src/components/LayoutGrid/LayoutGrid.stories.tsx +61 -0
  27. package/src/components/LayoutGrid/LayoutGrid.test.tsx +1 -0
  28. package/src/components/LayoutGrid/LayoutGrid.tsx +181 -0
  29. package/src/components/LayoutGrid/USAGE.md +79 -0
  30. package/src/components/LayoutGrid/index.ts +1 -0
  31. package/src/components/Menu/Menu.stories.tsx +0 -3
  32. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +42 -38
  33. package/src/components/Pagination/Pagination.icons.tsx +0 -32
  34. package/src/components/Pagination/Pagination.manifest.dom.test.tsx +105 -0
  35. package/src/components/Pagination/Pagination.module.css +25 -164
  36. package/src/components/Pagination/Pagination.tsx +221 -97
  37. package/src/components/Pagination/USAGE.md +8 -1
  38. package/src/components/Panel/Panel.module.css +24 -1
  39. package/src/components/Panel/Panel.stories.tsx +4 -4
  40. package/src/components/Panel/Panel.tsx +10 -1
  41. package/src/components/Radio/Radio.module.css +2 -2
  42. package/src/components/SegmentedControl/SegmentedControl.module.css +18 -0
  43. package/src/components/Stack/USAGE.md +2 -1
  44. package/src/components/Stepper/Stepper.module.css +0 -21
  45. package/src/components/index.ts +1 -1
  46. package/src/index.ts +1 -0
  47. package/src/utils/breakpointsFromRecManifest.test.ts +40 -0
  48. package/src/utils/breakpointsFromRecManifest.ts +72 -0
  49. package/src/utils/index.ts +1 -0
  50. package/src/components/Grid/Grid.stories.tsx +0 -151
  51. package/src/components/Grid/Grid.test.tsx +0 -1
  52. package/src/components/Grid/Grid.tsx +0 -189
  53. package/src/components/Grid/IMPLEMENTATION_NOTES.md +0 -99
  54. package/src/components/Grid/USAGE.md +0 -57
  55. package/src/components/Grid/index.ts +0 -1
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ import { CardProps as CardProps_2 } from '@mui/material';
13
13
  import { CheckboxProps as CheckboxProps_2 } from '@mui/material';
14
14
  import { ChipProps as ChipProps_2 } from '@mui/material';
15
15
  import { CommonProps } from '@mui/material/OverridableComponent';
16
+ import { ComponentPropsWithoutRef } from 'react';
16
17
  import { ContainerProps as ContainerProps_2 } from '@mui/material';
17
18
  import { CSSProperties } from 'react';
18
19
  import { DatePickerProps as DatePickerProps_2 } from '@mui/x-date-pickers/DatePicker';
@@ -31,7 +32,7 @@ import { FormControlProps } from '@mui/material';
31
32
  import { FormGroupProps } from '@mui/material';
32
33
  import { FormHelperTextProps } from '@mui/material';
33
34
  import { ForwardRefExoticComponent } from 'react';
34
- import { GridProps as GridProps_2 } from '@mui/material';
35
+ import { GridProps } from '@mui/material';
35
36
  import { HTMLAttributes } from 'react';
36
37
  import { InputBaseProps } from '@mui/material';
37
38
  import { InputLabelProps } from '@mui/material';
@@ -39,7 +40,6 @@ import { JSX } from 'react';
39
40
  import { LinkProps as LinkProps_2 } from '@mui/material';
40
41
  import { MenuItemProps as MenuItemProps_2 } from '@mui/material';
41
42
  import { MenuProps as MenuProps_2 } from '@mui/material';
42
- import { PaginationProps as PaginationProps_2 } from '@mui/material';
43
43
  import { RadioGroupProps as RadioGroupProps_2 } from '@mui/material';
44
44
  import { RadioProps as RadioProps_2 } from '@mui/material';
45
45
  import { ReactNode } from 'react';
@@ -68,11 +68,11 @@ import { RecursicaFileUploadItem } from '@recursica/adapter-common';
68
68
  import { RecursicaFileUploadProps as RecursicaFileUploadProps_2 } from '@recursica/adapter-common';
69
69
  import { RecursicaFormControlLayoutProps } from '@recursica/adapter-common';
70
70
  import { RecursicaFormControlWrapperProps as RecursicaFormControlWrapperProps_2 } from '@recursica/adapter-common';
71
- import { RecursicaGridColProps } from '@recursica/adapter-common';
72
- import { RecursicaGridProps } from '@recursica/adapter-common';
73
71
  import { RecursicaHeadingProps } from '@recursica/adapter-common';
74
72
  import { RecursicaHoverCardProps } from '@recursica/adapter-common';
75
73
  import { RecursicaLabelProps } from '@recursica/adapter-common';
74
+ import { RecursicaLayoutGridColProps } from '@recursica/adapter-common';
75
+ import { RecursicaLayoutGridProps } from '@recursica/adapter-common';
76
76
  import { RecursicaLinkProps } from '@recursica/adapter-common';
77
77
  import { RecursicaLoaderProps } from '@recursica/adapter-common';
78
78
  import { RecursicaMenuProps } from '@recursica/adapter-common';
@@ -139,6 +139,7 @@ import { TimePickerProps as TimePickerProps_2 } from '@mui/x-date-pickers/TimePi
139
139
  import { ToggleButtonGroupProps } from '@mui/material';
140
140
  import { TooltipProps as TooltipProps_2 } from '@mui/material';
141
141
  import { TypographyProps as TypographyProps_2 } from '@mui/material';
142
+ import { UsePaginationProps } from '@mui/material/usePagination';
142
143
  import { WithRecursicaSpacing } from '@recursica/adapter-common';
143
144
 
144
145
  export declare const Accordion: AccordionComponent;
@@ -352,6 +353,23 @@ export declare type BreadcrumbProps = RecursicaOverStyled<Omit<BreadcrumbsProps,
352
353
 
353
354
  declare type Breakpoint = "xs" | "sm" | "md" | "lg" | "xl";
354
355
 
356
+ /**
357
+ * Builds a `{ name: <start px> }` breakpoint values object from the manifest's layout grids, to
358
+ * merge into MUI's `createTheme({ breakpoints: { values } })`. Opt-in: nothing in the adapter
359
+ * calls this for you, and the result is a plain object you can edit.
360
+ *
361
+ * MUI breakpoints are mobile-first start widths, so each non-default grid maps to its
362
+ * `min-width`; a grid with only a `max-width` (e.g. `mobile`, up to 480px) starts at `0`. The
363
+ * `default` grid has no width of its own: when other grids exist it is included, named `default`,
364
+ * starting one pixel past the widest `max-width`. A manifest with only the `default` grid (the
365
+ * stock Forge export) returns `{}`. MUI's `values` replaces its defaults rather than merging, so
366
+ * spread MUI's own defaults first: `values: { ...createTheme().breakpoints.values, ...result }`.
367
+ *
368
+ * Throws for a non-default grid with neither width, for non-numeric widths, and when no other grid
369
+ * has a `max-width` for `default` to start after.
370
+ */
371
+ export declare function breakpointsFromRecManifest(manifest: ManifestWithLayoutGrids): Record<string, number>;
372
+
355
373
  /**
356
374
  * Recursica Button component wrapping MUI's Button.
357
375
  *
@@ -620,32 +638,6 @@ export declare const FormControlWrapper: default_2.ForwardRefExoticComponent<Omi
620
638
 
621
639
  export declare type FormControlWrapperProps = RecursicaFormControlWrapperProps;
622
640
 
623
- export declare const Grid: GridComponent;
624
-
625
- declare const GridBase: ForwardRefExoticComponent<Omit<GridProps, "ref"> & RefAttributes<HTMLDivElement>>;
626
-
627
- export declare const GridCol: ForwardRefExoticComponent<Omit<GridColProps, "ref"> & RefAttributes<HTMLDivElement>>;
628
-
629
- export declare type GridColProps = WithRecursicaSpacing<OmitSx<Omit<GridProps_2, "container" | "order">>> & RecursicaGridColProps & {
630
- /** Sets the CSS `order` property. Applied via inline style — see notes above. */
631
- order?: number;
632
- /** Hides the column below the given breakpoint. MUI has no native equivalent. */
633
- visibleFrom?: Breakpoint;
634
- /** Hides the column above the given breakpoint. MUI has no native equivalent. */
635
- hiddenFrom?: Breakpoint;
636
- };
637
-
638
- declare type GridComponent = typeof GridBase & {
639
- Col: typeof GridCol;
640
- };
641
-
642
- export declare type GridProps = WithRecursicaSpacing<OmitSx<Omit<GridProps_2, "container" | "justifyContent" | "alignItems" | "spacing" | "columnSpacing" | "rowSpacing" | "columns">>> & RecursicaGridProps & {
643
- /** Sets `justify-content` on the container. Applied via inline style — see notes above. */
644
- justifyContent?: CSSProperties["justifyContent"];
645
- /** Sets `align-items` on the container. Applied via inline style — see notes above. */
646
- alignItems?: CSSProperties["alignItems"];
647
- };
648
-
649
641
  export declare const Group: ForwardRefExoticComponent<Omit<GroupProps, "ref"> & RefAttributes<HTMLDivElement>>;
650
642
 
651
643
  declare interface GroupOwnProps {
@@ -724,6 +716,32 @@ export declare interface LabelProps extends InputLabelProps, RecursicaLabelProps
724
716
  overStyled?: boolean;
725
717
  }
726
718
 
719
+ export declare const LayoutGrid: LayoutGridComponent;
720
+
721
+ declare const LayoutGridBase: ForwardRefExoticComponent<Omit<LayoutGridProps, "ref"> & RefAttributes<HTMLDivElement>>;
722
+
723
+ export declare const LayoutGridCol: ForwardRefExoticComponent<Omit<LayoutGridColProps, "ref"> & RefAttributes<HTMLDivElement>>;
724
+
725
+ export declare type LayoutGridColProps = WithRecursicaSpacing<OmitSx<Omit<GridProps, "container" | "order">>> & RecursicaLayoutGridColProps & {
726
+ /** Sets the CSS `order` property. Applied via inline style. */
727
+ order?: number;
728
+ /** Hides the column below the given breakpoint. MUI has no native equivalent. */
729
+ visibleFrom?: Breakpoint;
730
+ /** Hides the column above the given breakpoint. MUI has no native equivalent. */
731
+ hiddenFrom?: Breakpoint;
732
+ };
733
+
734
+ declare type LayoutGridComponent = typeof LayoutGridBase & {
735
+ Col: typeof LayoutGridCol;
736
+ };
737
+
738
+ export declare type LayoutGridProps = WithRecursicaSpacing<OmitSx<Omit<GridProps, "container" | "justifyContent" | "alignItems" | "spacing" | "columnSpacing" | "rowSpacing" | "columns">>> & RecursicaLayoutGridProps & {
739
+ /** Sets `justify-content` on the container. Applied via inline style. */
740
+ justifyContent?: CSSProperties["justifyContent"];
741
+ /** Sets `align-items` on the container. Applied via inline style. */
742
+ alignItems?: CSSProperties["alignItems"];
743
+ };
744
+
727
745
  export declare const Link: ForwardRefExoticComponent<(Omit<Omit<WithRecursicaSpacing<Omit<LinkProps_2, "underline"> & RecursicaLinkProps>, "className" | "classes" | "style" | "sx" | "color" | "bgcolor" | "backgroundColor" | "typography" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textAlign" | "border" | "borderTop" | "borderBottom" | "borderLeft" | "borderRight" | "borderColor" | "borderRadius" | "boxShadow" | "display" | "position" | "zIndex" | "p" | "py" | "px" | "pt" | "pb" | "pl" | "pr" | "classNames" | "styles" | "vars" | "bg" | "c" | "opacity" | "ff" | "fz" | "fw" | "lts" | "ta" | "lh" | "fs" | "tt" | "td" | "bd" | "bdw" | "bds" | "bdc" | "bdr" | "shadow" | "w" | "miw" | "maw" | "h" | "mih" | "mah"> & Omit<ForbiddenStyles, never> & {
728
746
  overStyled?: false | undefined;
729
747
  }, "ref"> | Omit<Omit<Omit<LinkProps_2, "underline"> & RecursicaLinkProps, "m" | "my" | "mx" | "mt" | "mb" | "ml" | "mr" | "gap" | "rowGap" | "columnGap" | "gutter" | "spacing"> & {
@@ -749,6 +767,12 @@ export declare const Loader: default_2.ForwardRefExoticComponent<LoaderProps & d
749
767
 
750
768
  export declare type LoaderProps = RecursicaOverStyled<default_2.HTMLAttributes<HTMLSpanElement> & RecursicaLoaderProps>;
751
769
 
770
+ declare interface ManifestWithLayoutGrids {
771
+ brand?: {
772
+ "layout-grids"?: Record<string, unknown>;
773
+ };
774
+ }
775
+
752
776
  export declare const Menu: ForwardRefExoticComponent<(Omit<Omit<WithRecursicaSpacing<MenuProps_2 & RecursicaMenuProps>, "className" | "classes" | "style" | "sx" | "color" | "bgcolor" | "backgroundColor" | "typography" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textAlign" | "border" | "borderTop" | "borderBottom" | "borderLeft" | "borderRight" | "borderColor" | "borderRadius" | "boxShadow" | "display" | "position" | "zIndex" | "p" | "py" | "px" | "pt" | "pb" | "pl" | "pr" | "classNames" | "styles" | "vars" | "bg" | "c" | "opacity" | "ff" | "fz" | "fw" | "lts" | "ta" | "lh" | "fs" | "tt" | "td" | "bd" | "bdw" | "bds" | "bdc" | "bdr" | "shadow" | "w" | "miw" | "maw" | "h" | "mih" | "mah"> & Omit<ForbiddenStyles, never> & {
753
777
  overStyled?: false | undefined;
754
778
  }, "ref"> | Omit<Omit<MenuProps_2 & RecursicaMenuProps, "m" | "my" | "mx" | "mt" | "mb" | "ml" | "mr" | "gap" | "rowGap" | "columnGap" | "gutter" | "spacing"> & {
@@ -902,6 +926,8 @@ declare const ModalTitle: default_2.ForwardRefExoticComponent<(Omit<Omit<WithRec
902
926
 
903
927
  export declare type ModalTitleProps = RecursicaOverStyled<DialogTitleProps>;
904
928
 
929
+ declare type NavControl = "first" | "previous" | "next" | "last";
930
+
905
931
  export declare const NumberInput: default_2.ForwardRefExoticComponent<(Omit<Omit<WithRecursicaSpacing<RecursicaNumberInputProps>, "className" | "classes" | "style" | "sx" | "color" | "bgcolor" | "backgroundColor" | "typography" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textAlign" | "border" | "borderTop" | "borderBottom" | "borderLeft" | "borderRight" | "borderColor" | "borderRadius" | "boxShadow" | "display" | "position" | "zIndex" | "p" | "py" | "px" | "pt" | "pb" | "pl" | "pr" | "classNames" | "styles" | "vars" | "bg" | "c" | "opacity" | "ff" | "fz" | "fw" | "lts" | "ta" | "lh" | "fs" | "tt" | "td" | "bd" | "bdw" | "bds" | "bdc" | "bdr" | "shadow" | "w" | "miw" | "maw" | "h" | "mih" | "mah"> & Omit<ForbiddenStyles, never> & {
906
932
  overStyled?: false | undefined;
907
933
  }, "ref"> | Omit<Omit<RecursicaNumberInputProps, "m" | "my" | "mx" | "mt" | "mb" | "ml" | "mr" | "gap" | "rowGap" | "columnGap" | "gutter" | "spacing"> & {
@@ -926,28 +952,20 @@ export declare type NumberInputProps = RecursicaOverStyled<RecursicaNumberInputP
926
952
  declare type OmitSx<T> = Omit<T, "sx">;
927
953
 
928
954
  /**
929
- * Recursica Pagination component wrapping Mui's Pagination.
955
+ * Recursica Pagination. Its page and navigation buttons are Recursica `Button`s whose style and
956
+ * size come from the manifest's `ui-kit.components.pagination` selected variants. Requires the
957
+ * `manifest` prop on `RecursicaThemeProvider`.
930
958
  */
931
- export declare const Pagination: ForwardRefExoticComponent<(Omit<Omit<WithRecursicaSpacing<PaginationProps_2 & RecursicaPaginationProps>, "className" | "classes" | "style" | "sx" | "color" | "bgcolor" | "backgroundColor" | "typography" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textAlign" | "border" | "borderTop" | "borderBottom" | "borderLeft" | "borderRight" | "borderColor" | "borderRadius" | "boxShadow" | "display" | "position" | "zIndex" | "p" | "py" | "px" | "pt" | "pb" | "pl" | "pr" | "classNames" | "styles" | "vars" | "bg" | "c" | "opacity" | "ff" | "fz" | "fw" | "lts" | "ta" | "lh" | "fs" | "tt" | "td" | "bd" | "bdw" | "bds" | "bdc" | "bdr" | "shadow" | "w" | "miw" | "maw" | "h" | "mih" | "mah"> & Omit<ForbiddenStyles, never> & {
932
- overStyled?: false | undefined;
933
- }, "ref"> | Omit<Omit<PaginationProps_2 & RecursicaPaginationProps, "m" | "my" | "mx" | "mt" | "mb" | "ml" | "mr" | "gap" | "rowGap" | "columnGap" | "gutter" | "spacing"> & {
934
- m?: string | number | RecursicaSpacing;
935
- mx?: string | number | RecursicaSpacing;
936
- my?: string | number | RecursicaSpacing;
937
- mt?: string | number | RecursicaSpacing;
938
- mb?: string | number | RecursicaSpacing;
939
- ml?: string | number | RecursicaSpacing;
940
- mr?: string | number | RecursicaSpacing;
941
- gap?: string | number | RecursicaSpacing;
942
- rowGap?: string | number | RecursicaSpacing;
943
- columnGap?: string | number | RecursicaSpacing;
944
- gutter?: string | number | RecursicaSpacing;
945
- spacing?: string | number | RecursicaSpacing;
946
- } & {
947
- overStyled: true;
948
- }, "ref">) & RefAttributes<HTMLDivElement>>;
949
-
950
- export declare type PaginationProps = RecursicaOverStyled<PaginationProps_2 & RecursicaPaginationProps>;
959
+ export declare const Pagination: ForwardRefExoticComponent<PaginationProps & RefAttributes<HTMLElement>>;
960
+
961
+ export declare type PaginationProps = RecursicaOverStyled<RecursicaPaginationProps & Pick<UsePaginationProps, "page" | "defaultPage" | "onChange" | "siblingCount" | "boundaryCount" | "disabled"> & {
962
+ /** Extra props for each page button */
963
+ getItemProps?: (page: number) => Record<string, unknown>;
964
+ /** Extra props for each first/previous/next/last button */
965
+ getControlProps?: (control: NavControl) => Record<string, unknown>;
966
+ /** Replaces the dots between page ranges */
967
+ dotsIcon?: ReactNode;
968
+ } & Omit<ComponentPropsWithoutRef<"nav">, "onChange" | "children">>;
951
969
 
952
970
  export declare const Panel: PanelComponent;
953
971
 
package/llms.txt CHANGED
@@ -40,11 +40,11 @@ Each component has its own `USAGE.md` documenting its props, adapter-specific be
40
40
  - [Flex](src/components/Flex/USAGE.md)
41
41
  - [FormControlLayout](src/components/FormControlLayout/USAGE.md)
42
42
  - [FormControlWrapper](src/components/FormControlWrapper/USAGE.md)
43
- - [Grid](src/components/Grid/USAGE.md)
44
43
  - [Group](src/components/Group/USAGE.md)
45
44
  - [HoverCard](src/components/HoverCard/USAGE.md)
46
45
  - [Label](src/components/Label/USAGE.md)
47
46
  - [Layer](src/components/Layer/USAGE.md)
47
+ - [LayoutGrid](src/components/LayoutGrid/USAGE.md)
48
48
  - [Link](src/components/Link/USAGE.md)
49
49
  - [Loader](src/components/Loader/USAGE.md)
50
50
  - [Menu](src/components/Menu/USAGE.md)
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "type": "git",
13
13
  "url": "git+https://github.com/borderux/recursica-adapter-mui-v7.git"
14
14
  },
15
- "version": "1.1.0",
15
+ "version": "1.3.0",
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
@@ -83,9 +83,9 @@
83
83
  "@mui/x-date-pickers": "^9.11.0",
84
84
  "@mui/x-tree-view": "^9.11.0",
85
85
  "@playwright/test": "^1.62.1",
86
- "@recursica/adapter-tester": "^5.2.0",
86
+ "@recursica/adapter-tester": "^5.3.1",
87
87
  "@recursica/recursica-postcss-vars": "^1.5.0",
88
- "@recursica/storybook-template": "^0.7.11",
88
+ "@recursica/storybook-template": "^0.7.15",
89
89
  "@recursica/token-analyzer": "^1.8.0",
90
90
  "@storybook/addon-a11y": "^10.3.3",
91
91
  "@storybook/addon-docs": "^10.3.3",
@@ -122,7 +122,7 @@
122
122
  "vitest": "^3.2.4"
123
123
  },
124
124
  "dependencies": {
125
- "@recursica/adapter-common": "^0.31.0",
125
+ "@recursica/adapter-common": "^1.1.1",
126
126
  "@recursica/official-release": "^2.8.0",
127
127
  "dayjs": "^1.11.21"
128
128
  },
@@ -2603,8 +2603,8 @@
2603
2603
  },
2604
2604
  "$extensions": {
2605
2605
  "recursica.metadata": {
2606
- "exportedAt": "2026-09-23T16:11:12.118Z",
2607
- "version": "0.28.2"
2606
+ "exportedAt": "2026-10-02T22:19:36.595Z",
2607
+ "version": "0.29.0"
2608
2608
  }
2609
2609
  }
2610
2610
  }
@@ -762,8 +762,8 @@
762
762
  },
763
763
  "$extensions": {
764
764
  "recursica.metadata": {
765
- "exportedAt": "2026-09-23T16:11:12.114Z",
766
- "version": "0.28.2"
765
+ "exportedAt": "2026-10-02T22:19:36.595Z",
766
+ "version": "0.29.0"
767
767
  }
768
768
  }
769
769
  }
@@ -9042,8 +9042,8 @@
9042
9042
  },
9043
9043
  "$extensions": {
9044
9044
  "recursica.metadata": {
9045
- "exportedAt": "2026-09-23T16:11:12.142Z",
9046
- "version": "0.28.2"
9045
+ "exportedAt": "2026-10-02T22:19:36.595Z",
9046
+ "version": "0.29.0"
9047
9047
  }
9048
9048
  }
9049
9049
  }
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  * Recursica CSS Variables - Scoped
3
- * Transform version: 1.3.3
4
- * Source JSON version: 0.28.2
5
- * Generated: Wed, 23 Sep 2026 16:11:12 GMT
3
+ * Transform version: 1.4.0
4
+ * Source JSON version: 0.29.0
5
+ * Generated: Fri, 02 Oct 2026 22:19:36 GMT
6
6
  *
7
7
  * --- How to integrate this file ---
8
8
  *
@@ -133,10 +133,14 @@
133
133
  --recursica_brand_layer_1_elements_interactive_tone: var(--recursica_tokens_colors_scale-06_400);
134
134
  --recursica_brand_layer_2_elements_interactive_tone: var(--recursica_tokens_colors_scale-06_400);
135
135
  --recursica_brand_layer_3_elements_interactive_tone: var(--recursica_tokens_colors_scale-06_400);
136
+ --recursica_brand_layout-grids_column-gutter: var(--recursica_brand_layout-grids_default_column-gutter);
137
+ --recursica_brand_layout-grids_columns: var(--recursica_brand_layout-grids_default_columns);
136
138
  --recursica_brand_layout-grids_default_column-gutter: var(--recursica_tokens_sizes_2x);
137
139
  --recursica_brand_layout-grids_default_columns: 6;
138
140
  --recursica_brand_layout-grids_default_margin: var(--recursica_tokens_sizes_3x);
139
141
  --recursica_brand_layout-grids_default_row-gutter: var(--recursica_tokens_sizes_3x);
142
+ --recursica_brand_layout-grids_margin: var(--recursica_brand_layout-grids_default_margin);
143
+ --recursica_brand_layout-grids_row-gutter: var(--recursica_brand_layout-grids_default_row-gutter);
140
144
  --recursica_brand_modes_dark_elevations_elevation-0: var(--recursica_brand_modes_dark_elevations_elevation-0_x) var(--recursica_brand_modes_dark_elevations_elevation-0_y) var(--recursica_brand_modes_dark_elevations_elevation-0_blur) var(--recursica_brand_modes_dark_elevations_elevation-0_spread) var(--recursica_brand_modes_dark_elevations_elevation-0_color);
141
145
  --recursica_brand_modes_dark_elevations_elevation-0_blur: 0px;
142
146
  --recursica_brand_modes_dark_elevations_elevation-0_color: var(--recursica_brand_modes_dark_palettes_neutral_500_color_tone);
@@ -21,7 +21,7 @@
21
21
  /* SideBySide Variant */
22
22
  .groupRoot[data-layout="side-by-side"] {
23
23
  flex-direction: column;
24
- flex-wrap: wrap;
24
+ flex-wrap: nowrap;
25
25
  padding-top: var(
26
26
  --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_vertical-padding
27
27
  );
@@ -278,8 +278,6 @@
278
278
  );
279
279
  }
280
280
  .groupRoot[data-layout="side-by-side"] {
281
- flex-direction: row;
282
- flex-wrap: wrap;
283
281
  gap: var(
284
282
  --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_gutter
285
283
  );
@@ -35,7 +35,6 @@ All Recursica components in the `@recursica/adapter-mui-v7` package adhere stric
35
35
 
36
36
  > [!IMPORTANT]
37
37
  >
38
- > - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
39
38
  > - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
40
39
  > - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
41
40
 
@@ -52,6 +52,14 @@
52
52
  min-height: var(
53
53
  --recursica_ui-kit_components_file-input_properties_min-height
54
54
  );
55
+ /* Fixed height (icon + padding + border) so the nested clear Button overflows the row instead of growing the control. */
56
+ height: calc(
57
+ var(--recursica_ui-kit_components_file-input_properties_icon-size) + 2 *
58
+ var(
59
+ --recursica_ui-kit_components_file-input_properties_vertical-padding
60
+ ) +
61
+ 2 * var(--recursica_ui-kit_components_file-input_properties_border-size)
62
+ );
55
63
  gap: var(--recursica_ui-kit_components_file-input_properties_icon-text-gap);
56
64
  padding-top: var(
57
65
  --recursica_ui-kit_components_file-input_properties_vertical-padding
@@ -30,6 +30,7 @@
30
30
  display: flex;
31
31
  flex-direction: column;
32
32
  width: 100%;
33
+ max-width: var(--recursica_ui-kit_globals_form_field_size_max-width);
33
34
  gap: var(--recursica_ui-kit_components_file-upload_properties_list-spacing);
34
35
  }
35
36
 
@@ -264,6 +264,7 @@ export const FileUpload = forwardRef<HTMLDivElement, FileUploadProps>(
264
264
  required={required}
265
265
  disabled={disabled}
266
266
  id={id}
267
+ controlMaxWidth="var(--recursica_ui-kit_globals_form_field_size_max-width)"
267
268
  >
268
269
  <div
269
270
  ref={ref}
@@ -36,6 +36,7 @@ All Recursica components in the `@recursica/adapter-mui-v7` package adhere stric
36
36
 
37
37
  > [!IMPORTANT]
38
38
  >
39
- > - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
40
39
  > - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
41
40
  > - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
41
+
42
+ > [!NOTE] > **Responsive props use your MUI theme's breakpoints, not Forge's.** Keys such as `{ xs, sm, md }` come from `theme.breakpoints`; Forge's layout grids switch via plain CSS `@media` and never edit the MUI theme. Build your theme with `breakpointsFromRecManifest` so the two agree (see [LayoutGrid](../LayoutGrid/USAGE.md)).
@@ -36,6 +36,7 @@ All Recursica components in the `@recursica/adapter-mui-v7` package adhere stric
36
36
 
37
37
  > [!IMPORTANT]
38
38
  >
39
- > - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
40
39
  > - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
41
40
  > - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
41
+
42
+ > [!NOTE] > **Responsive props use your MUI theme's breakpoints, not Forge's.** Keys such as `{ xs, sm, md }` come from `theme.breakpoints`; Forge's layout grids switch via plain CSS `@media` and never edit the MUI theme. Build your theme with `breakpointsFromRecManifest` so the two agree (see [LayoutGrid](../LayoutGrid/USAGE.md)).
@@ -0,0 +1,82 @@
1
+ # LayoutGrid Implementation Notes
2
+
3
+ `LayoutGrid` is the Recursica layout grid. MUI has no native Grid/Grid.Col split: its `Grid`
4
+ merges "container" and "item" behavior into one component (toggled by `container` and a `size`
5
+ prop). `LayoutGrid` always renders `<MuiGrid container>` and `LayoutGrid.Col` renders `<MuiGrid>`
6
+ in item mode, to keep the same dot-notation shape as the Mantine adapter. It was named `Grid`
7
+ before 2026-10-05.
8
+
9
+ Unlike the other primitive layout components (`Flex`, `Stack`, `Group`, `Container`), it has a
10
+ formal Recursica prop contract (`RecursicaLayoutGridProps` in `adapter-common`) and wires the
11
+ design system's `layout-grids` tokens. Its other props are MUI's own vocabulary, not a shared
12
+ contract:
13
+
14
+ - **`size`** (not Mantine's `span`): a column count, `"auto"`, `"grow"`, or a responsive object keyed by
15
+ MUI's breakpoints (`xs`/`sm`/`md`/`lg`/`xl`, no `"base"`). It renames to `span` when
16
+ `RecursicaLayoutGridColProps` picks `span` up (queued in `adapter-common`).
17
+ - **`offset`**: MUI's own prop, used as is.
18
+ - **`grow` (container)**: not implemented; use `size="grow"` per column.
19
+ - **`order`, `justifyContent`, `alignItems`**: typed by MUI but never read by its Grid generator
20
+ (`@mui/system` `gridGenerator`), so they're applied via inline `style`.
21
+ - **`visibleFrom` / `hiddenFrom`**: no MUI mechanism, so `LayoutGrid.module.css` has media-query
22
+ classes hardcoded to MUI's default breakpoints (0/600/900/1200/1536). They do not follow a
23
+ customized `theme.breakpoints`.
24
+
25
+ ## Forge contract
26
+
27
+ Forge always emits a default grid with columns (default 6, editable), column-gutter, row-gutter and
28
+ side margin, in the CSS and in `recursica_manifest.json`. Additional breakpoints are overrides, so
29
+ nothing here has a fallback value.
30
+
31
+ ## No integrator-facing layout props
32
+
33
+ Columns, column-gutter, row-gutter and margin are design-system-managed, not per-instance settings.
34
+ `columns`, `spacing`, `columnSpacing` and `rowSpacing` were removed from the public type and are
35
+ deleted at runtime so they can't shadow the token-driven values. For an arbitrary N-column grid,
36
+ use MUI's `Grid` directly.
37
+
38
+ ## How each token is applied
39
+
40
+ Forge emits a responsive alias per grid var (`--recursica_brand_layout-grids_{columns,row-gutter,column-gutter,margin}`),
41
+ set from `_default_*` at `:root` and redefined inside Forge's `@media` blocks per non-default grid.
42
+ `LayoutGrid` reads only the alias, so tokens follow breakpoints with no JS. Overlapping ranges are
43
+ not guarded by Forge; the later `@media` block wins.
44
+
45
+ - **Columns**: MUI's Grid computes widths in CSS from `--Grid-parent-columns`, so unlike Mantine no
46
+ per-column style rule is needed. `LayoutGrid` passes the alias as `columns`
47
+ (`var(--recursica_brand_layout-grids_columns)`); MUI types it as a number but writes it
48
+ verbatim into the custom property, which the width `calc()` then reads. Verified in
49
+ `@mui/system`'s `gridGenerator`.
50
+ - **Column gutter / row gutter**: passed to MUI's own `columnSpacing`/`rowSpacing` as the
51
+ responsive aliases. MUI applies each independently (strings are not multiplied by `theme.spacing`).
52
+ - **Margin**: no MUI Grid prop equivalent; `.root` in `LayoutGrid.module.css` reads it directly.
53
+ - **Clamping**: MUI's width calc does not clamp, so `size={6}` at 3 columns would overflow.
54
+ `.col { max-width: 100% }` makes it fill the row instead, matching Mantine's `min(span, columns)`.
55
+
56
+ ## Breakpoints
57
+
58
+ Responsive `size`/`offset` switch at the MUI theme's breakpoints, which Forge never edits.
59
+ Integrators should merge `breakpointsFromRecManifest(manifest)` into `theme.breakpoints.values`
60
+ so both switch at the same widths (MUI's `values` replaces its defaults, so spread them first;
61
+ see SETUP.md). `RecursicaThemeProvider` is UI-kit agnostic and does not compare the manifest
62
+ against the theme. The helper returns numbers (MUI's unit), not the `"Npx"` strings the Mantine
63
+ one returns.
64
+
65
+ ## `LayoutGrid.Col` contract is scaffolded
66
+
67
+ `RecursicaLayoutGridColProps` currently only contributes `children`; `span`, `order`,
68
+ `visibleFrom` and `hiddenFrom` are drafted and commented out in `adapter-common`. No runtime
69
+ effect here.
70
+
71
+ ## Brand-layer exemption
72
+
73
+ `layout-grids` tokens have no `ui-kit` layer in Forge's model, so `LayoutGrid.module.css` reads
74
+ `brand_layout-grids_margin` directly with a `recursica-allow-brand:` header. The other three are
75
+ read in `LayoutGrid.tsx` (a TSX prop value), which the analyzer does not scan.
76
+
77
+ ## Stories
78
+
79
+ A single `Default` story reads `brand.layout-grids.default.columns` from the manifest (via
80
+ `useRecursicaManifest()`) and fills two rows of that many single-column cells. Same story id as the
81
+ Mantine adapter's, so it diffs against its golden. Only `size` is used, so the story stays valid
82
+ for every adapter.
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { createRoot } from "react-dom/client";
3
+ import { flushSync } from "react-dom";
4
+ import { StyledEngineProvider } from "@mui/material/styles";
5
+ import { LayoutGrid } from "./LayoutGrid";
6
+
7
+ function mount(node: React.ReactElement) {
8
+ const container = document.createElement("div");
9
+ document.body.appendChild(container);
10
+ const root = createRoot(container);
11
+ // injectFirst, as RecursicaThemeProvider does, so the component CSS beats MUI's.
12
+ flushSync(() =>
13
+ root.render(
14
+ <StyledEngineProvider injectFirst>{node}</StyledEngineProvider>,
15
+ ),
16
+ );
17
+ return {
18
+ container,
19
+ done: () => {
20
+ root.unmount();
21
+ container.remove();
22
+ },
23
+ };
24
+ }
25
+
26
+ describe("LayoutGrid tokens", () => {
27
+ it("takes columns and gutters from the responsive Forge variables", () => {
28
+ document.documentElement.style.setProperty(
29
+ "--recursica_brand_layout-grids_columns",
30
+ "3",
31
+ );
32
+ document.documentElement.style.setProperty(
33
+ "--recursica_brand_layout-grids_column-gutter",
34
+ "10px",
35
+ );
36
+ document.documentElement.style.setProperty(
37
+ "--recursica_brand_layout-grids_row-gutter",
38
+ "20px",
39
+ );
40
+ const { container, done } = mount(
41
+ <LayoutGrid>
42
+ <LayoutGrid.Col size={1}>a</LayoutGrid.Col>
43
+ </LayoutGrid>,
44
+ );
45
+ const grid = container.querySelector(".MuiGrid-container") as HTMLElement;
46
+ const style = getComputedStyle(grid);
47
+ expect(style.getPropertyValue("--Grid-columns").trim()).toBe("3");
48
+ expect(style.getPropertyValue("--Grid-columnSpacing").trim()).toBe("10px");
49
+ expect(style.getPropertyValue("--Grid-rowSpacing").trim()).toBe("20px");
50
+ done();
51
+ });
52
+
53
+ it("drops columns and spacing props passed at runtime", () => {
54
+ const { container, done } = mount(
55
+ <LayoutGrid {...({ columns: 12, spacing: 8 } as Record<string, unknown>)}>
56
+ <LayoutGrid.Col size={1}>a</LayoutGrid.Col>
57
+ </LayoutGrid>,
58
+ );
59
+ const grid = container.querySelector(".MuiGrid-container") as HTMLElement;
60
+ expect(
61
+ getComputedStyle(grid).getPropertyValue("--Grid-columns").trim(),
62
+ ).toBe("3");
63
+ done();
64
+ });
65
+
66
+ it("clamps a column wider than the grid to the row", () => {
67
+ const { container, done } = mount(
68
+ <LayoutGrid>
69
+ <LayoutGrid.Col size={6}>a</LayoutGrid.Col>
70
+ </LayoutGrid>,
71
+ );
72
+ const col = container.querySelector(
73
+ ".MuiGrid-container > div",
74
+ ) as HTMLElement;
75
+ expect(getComputedStyle(col).maxWidth).toBe("100%");
76
+ done();
77
+ });
78
+ });
@@ -3,25 +3,26 @@
3
3
  * - Breakpoint pixel thresholds below (600/900/1200/1536) match MUI's own default
4
4
  * theme.breakpoints (xs/sm/md/lg/xl). They drive `visibleFrom`/`hiddenFrom`, which
5
5
  * have no native MUI Grid equivalent to hook into. If the consuming app customizes
6
- * its MUI theme breakpoints, these thresholds will not follow that change —
6
+ * its MUI theme breakpoints, these thresholds will not follow that change:
7
7
  * structural layout mechanics, not a design token.
8
8
  */
9
9
 
10
- /* Brand-layer exemption (recursica-allow-brand) — layout-grid tokens have no ui-kit-layer
10
+ /* Brand-layer exemption (recursica-allow-brand): layout-grid tokens have no ui-kit-layer
11
11
  * representation in Forge's model (a grid is a page-layout primitive, not a "component"), so
12
- * Grid is the one component that reads brand_layout-grids_* directly. Column-gutter/row-gutter
13
- * are applied via MUI's own native `columnSpacing`/`rowSpacing` props in Grid.tsx instead (MUI's
14
- * Grid generator reads them straight off the prop, no CSS declaration needed); `margin` has no
15
- * MUI Grid prop equivalent at all, so it's applied here, always from the design token — margin is
16
- * design-system-managed, not an integrator-facing override. See IMPLEMENTATION_NOTES.md.
17
- * recursica-allow-brand: --recursica_brand_layout-grids_default_margin
12
+ * LayoutGrid reads the responsive brand_layout-grids_* alias directly (Forge redefines it per
13
+ * breakpoint inside @media). Columns, column-gutter and row-gutter are applied in
14
+ * LayoutGrid.tsx through MUI's own props; `margin` has no MUI Grid prop equivalent, so it's
15
+ * applied here. See LAYOUT_GRID_IMPLEMENTATION_NOTES.md.
16
+ * recursica-allow-brand: --recursica_brand_layout-grids_margin
18
17
  */
19
18
 
20
- .root.root {
21
- margin: var(--recursica_brand_layout-grids_default_margin);
19
+ .root {
20
+ margin: var(--recursica_brand_layout-grids_margin);
22
21
  }
23
22
 
23
+ /* A numeric size larger than the current column count fills the row instead of overflowing. */
24
24
  .col {
25
+ max-width: 100%;
25
26
  }
26
27
 
27
28
  .hiddenFromXs {