@recursica/mantine-adapter 0.33.0 → 0.35.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.
@@ -1,3 +1,5 @@
1
+ import ReactMarkdown from "react-markdown";
2
+ import { TypographyStylesProvider } from "@mantine/core";
1
3
  import {
2
4
  Container,
3
5
  Card,
@@ -13,6 +15,7 @@ import {
13
15
  toggleGlobalOverStyled,
14
16
  wrapComponent,
15
17
  } from "@recursica/adapter-common";
18
+ import overStylingDoc from "../OVERSTYLING.md?raw";
16
19
 
17
20
  const Button = wrapComponent(RawButton);
18
21
  const Text = wrapComponent(RawText);
@@ -24,246 +27,27 @@ export const OverStylingInfo = () => {
24
27
  <Container size="md" style={{ padding: "32px 0" }}>
25
28
  <Card>
26
29
  <Card.Content>
27
- <Title order={1} mb="rec-md">
28
- Over Styling (<code>overStyled</code>)
29
- </Title>
30
- <Text mb="rec-md">
31
- By default, all Recursica components are strictly sandboxed. This
32
- means they are protected against arbitrary styling configurations
33
- (like passing generic React <code>style</code> objects, custom{" "}
34
- <code>classNames</code> injections, or using deep Mantine layout
35
- hooks like <code>bg</code> and <code>c</code>). This strict
36
- compile-time and run-time enforcement guarantees that your design
37
- system tokens remain true across your application.
38
- </Text>
39
- <Text mb="rec-md">
40
- However, there may be edge cases where a developer absolutely must
41
- modify a component beyond what the design tokens natively allow. For
42
- this, we provide the <strong>escape hatch</strong> property:{" "}
43
- <code>overStyled={`{true}`}</code>.
44
- </Text>
45
-
46
- <Title order={3} mb="rec-sm">
47
- The Core Philosophy
48
- </Title>
49
- <Text mb="rec-sm">
50
- **You should not over-style components.** Using{" "}
51
- <code>overStyled</code> explicitly signifies that you are breaking
52
- design system rules.
53
- </Text>
54
- <Stack
55
- component="ol"
56
- style={{ paddingLeft: "24px" }}
57
- mb="rec-xl"
58
- gap="rec-sm"
59
- >
60
- <li>
61
- <Text>
62
- <strong>Technical Debt:</strong> If over-styling is required, it
63
- should be treated as a short-term workaround. Ideally, the
64
- component will be refactored once the required layouts or
65
- variants are officially integrated into the core Recursica
66
- component library.
67
- </Text>
68
- </li>
69
- <li>
70
- <Text>
71
- <strong>Auditing & Searching:</strong> Because this pattern
72
- creates technical debt, we enforce the explicit{" "}
73
- <code>overStyled</code> boolean. This provides a highly
74
- auditable, easily searchable string. Product managers and
75
- engineers can quickly grep the codebase for{" "}
76
- <code>overStyled</code> (or the <code>RecursicaOverStyled</code>{" "}
77
- typings) to hunt down components that don't match standard
78
- patterns.
79
- </Text>
80
- </li>
81
- <li>
82
- <Text>
83
- <strong>Highly Custom Components:</strong> If your application
84
- genuinely requires massive custom layouts that the UI kit cannot
85
- support, <strong>do not hack the Recursica component</strong>.
86
- Instead, it is highly encouraged that you import the underlying
87
- primitive component directly from <code>@mantine/core</code> and
88
- construct your independent feature there. While you can utilize
89
- raw Recursica CSS variables on these custom components, note
90
- that they are not guaranteed to be accurately maintained as
91
- Recursica evolves. Keep strict components strict!
92
- </Text>
93
- </li>
94
- </Stack>
30
+ <TypographyStylesProvider>
31
+ <ReactMarkdown>{overStylingDoc}</ReactMarkdown>
32
+ </TypographyStylesProvider>
95
33
 
96
34
  <Stack
97
35
  style={{ height: 1, backgroundColor: "#eaeaea" }}
98
- mb="rec-xl"
36
+ my="rec-xl"
99
37
  />
100
38
 
101
- <Title order={3} mb="rec-sm">
102
- Permitted Layout Properties
103
- </Title>
104
- <Text mb="rec-sm">
105
- Unlike deep styling bounds (colors, typography, padding,
106
- dimensions), external <strong>layout spacing properties</strong>{" "}
107
- like Margins (<code>m</code>, <code>mt</code>, <code>mb</code>,{" "}
108
- <code>mx</code>) are safely <strong>permitted by default</strong>.
109
- This allows integrators to structurally compose components alongside
110
- siblings without breaching internal token boundaries.
111
- </Text>
112
- <Text mb="rec-xl">
113
- When using layout properties, you have the flexibility to use either
114
- ecosystem seamlessly:
115
- </Text>
116
- <Stack
117
- component="ol"
118
- style={{ paddingLeft: "24px" }}
119
- mb="rec-md"
120
- gap="rec-sm"
121
- >
122
- <li>
123
- <Text>
124
- <strong>Mantine Core Values:</strong> Passing standard Mantine
125
- sizes (like <code>mt="md"</code>) passes straight through to
126
- Mantine natively, allowing you to interface completely normally
127
- with a parent application's existing Mantine Theme setup that
128
- might fall outside Recursica's scope.
129
- </Text>
130
- </li>
131
- <li>
132
- <Text>
133
- <strong>Recursica Strict Tokens:</strong> Passing our custom
134
- prefixed tokens (like <code>mt="rec-md"</code>) signals our
135
- internal layout interceptor to securely translate the value
136
- directly to our native <code>recursica_brand_dimensions</code>{" "}
137
- CSS variables. This ensures strict design token measurements
138
- while sharing the exact same prop interface!
139
- </Text>
140
- </li>
141
- </Stack>
142
- <Text mb="rec-sm" overStyled fw={500}>
143
- Available Recursica Layout Tokens:
144
- </Text>
145
- <Stack
146
- component="ul"
147
- style={{ paddingLeft: "24px" }}
148
- mb="rec-xl"
149
- gap="rec-none"
150
- >
151
- <li>
152
- <Text>
153
- <code>rec-none</code> (0px limit)
154
- </Text>
155
- </li>
156
- <li>
157
- <Text>
158
- <code>rec-sm</code> (0.5x scaling)
159
- </Text>
160
- </li>
161
- <li>
162
- <Text>
163
- <code>rec-default</code> (1.0x scaling)
164
- </Text>
165
- </li>
166
- <li>
167
- <Text>
168
- <code>rec-md</code> (1.5x scaling)
169
- </Text>
170
- </li>
171
- <li>
172
- <Text>
173
- <code>rec-lg</code> (2.0x scaling)
174
- </Text>
175
- </li>
176
- <li>
177
- <Text>
178
- <code>rec-xl</code> (3.0x scaling)
179
- </Text>
180
- </li>
181
- <li>
182
- <Text>
183
- <code>rec-2xl</code> (4.0x scaling)
184
- </Text>
185
- </li>
186
- </Stack>
187
-
188
- <Stack
189
- style={{ height: 1, backgroundColor: "#eaeaea" }}
190
- mb="rec-xl"
191
- />
192
-
193
- <Title order={3} mb="rec-sm">
194
- Primitive Layout Components Exemption
39
+ <Title order={3} mb="rec-md">
40
+ Try It Yourself
195
41
  </Title>
196
- <Text mb="rec-sm">
197
- Unlike complex UI components (Buttons, Tabs, Inputs) which are
198
- strictly protected, <strong>Primitive Layout Components</strong> (
199
- <code>Flex</code>, <code>Stack</code>, <code>Group</code>,{" "}
200
- <code>Container</code>) are entirely exempt from the{" "}
201
- <code>RecursicaOverStyled</code> gatekeeper.
202
- </Text>
203
- <Text mb="rec-xl">
204
- Because the entire functional purpose of these components is
205
- structural layout composition, developers are free to pass any
206
- standard Mantine width, height, padding, margin, gap, and alignment
207
- property directly to them without needing to flag{" "}
208
- <code>overStyled={`{true}`}</code>. The internal custom token mapper
209
- (such as converting <code>gap="rec-md"</code>) is still active
210
- natively on these wrappers.
211
- </Text>
212
-
213
- <Stack
214
- style={{ height: 1, backgroundColor: "#eaeaea" }}
215
- mb="rec-xl"
216
- />
217
42
 
218
- <Title order={3} mb="rec-sm">
219
- Visual Auditing & Highlights (Development Only)
220
- </Title>
221
- <Text mb="rec-sm">
222
- To make it easy to spot technical debt and design system violations,
223
- Recursica automatically tracks any component that uses the{" "}
224
- <code>overStyled={`{true}`}</code> prop.
225
- </Text>
226
- <Text mb="rec-sm">
227
- In <strong>development builds</strong>, you can highlight all
228
- over-styled components on the page. Open your browser's developer
229
- console and run:
230
- </Text>
231
- <Stack
232
- style={{
233
- padding: 12,
234
- backgroundColor: "#f5f5f5",
235
- borderRadius: 6,
236
- fontSize: 13,
237
- marginTop: 8,
238
- marginBottom: 16,
239
- }}
240
- >
241
- <code>recursica.toggleOverStyled()</code>
242
- </Stack>
243
- <Group mb="rec-md">
43
+ <Group mb="rec-xl">
244
44
  <Switch
245
45
  label="Highlight Over-Styled Components"
246
46
  checked={isHighlightActive}
247
47
  onChange={() => toggleGlobalOverStyled()}
248
48
  />
249
49
  </Group>
250
- <Text mb="rec-xl">
251
- This toggles a <strong>cyan 2px box shadow</strong> outline around
252
- the children of all over-styled components. The wrapping elements
253
- use <code>display: contents</code> under the hood to ensure they
254
- occupy zero DOM space and do not affect flex, grid, or absolute
255
- positioning flow. In production builds, this debugging helper is
256
- completely disabled and stripped with zero performance overhead.
257
- </Text>
258
50
 
259
- <Stack
260
- style={{ height: 1, backgroundColor: "#eaeaea" }}
261
- mb="rec-xl"
262
- />
263
-
264
- <Title order={3} mb="rec-md">
265
- Live Example
266
- </Title>
267
51
  <Text mb="rec-xl">
268
52
  Below is a side-by-side comparison. The first is a standard
269
53
  Recursica Button protected by the design tokens mapping. The second
@@ -0,0 +1,9 @@
1
+ # Grid Implementation Notes
2
+
3
+ The `Grid` component is a generic 12-column (by default) layout wrapper mapped directly to Mantine's `Grid`/`Grid.Col`. It requires no custom logical layouts or CSS workarounds — Mantine handles column geometry, breakpoints, and wrapping natively.
4
+
5
+ The one deliberate divergence from Mantine's native API: the public `gap` prop replaces Mantine's `gutter`, for naming consistency with the other primitive layout components (`Flex`, `Stack`, `Group`). `gap` is translated to Mantine's `gutter` prop internally via `mapLayoutProps`, the same utility used to resolve `rec-*` spacing tokens elsewhere.
6
+
7
+ `Grid.Col`'s `span`, `offset`, `order`, `visibleFrom`, and `hiddenFrom` props are passed straight through to Mantine's `Grid.Col` unchanged — Mantine already uses generic, portable naming for these.
8
+
9
+ Like the other primitive layout components, `Grid` and `Grid.Col` use `WithRecursicaSpacing<T>` rather than `RecursicaOverStyled<T>` and are listed in the "Primitive Layout Components Exemption" section of `OVERSTYLING.md`.
@@ -0,0 +1,11 @@
1
+ /* HARDCODED VALUES:
2
+ * None. This is a generic grid layout wrapper.
3
+ */
4
+
5
+ .root {
6
+ /* Mantine handles the grid geometry (columns, gutter, spans) natively. No intrinsic design-system styles required for pure layout wrappers. */
7
+ }
8
+
9
+ .col {
10
+ /* Mantine handles column sizing (span, offset, order, visibleFrom/hiddenFrom) natively. */
11
+ }
@@ -0,0 +1,182 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { Grid } from "./Grid";
4
+ import { Card } from "../Card/Card";
5
+ import { Text } from "../Text/Text";
6
+
7
+ type GridStoryProps = React.ComponentProps<typeof Grid>;
8
+
9
+ const meta: Meta<GridStoryProps> = {
10
+ title: "UI-Kit/Grid",
11
+ component: Grid,
12
+ tags: ["autodocs"],
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component:
17
+ "Grid is a 12-column (by default) responsive grid layout that maps directly to Mantine's Grid/Grid.Col, providing column spans, offsets, ordering, and breakpoint-based visibility.",
18
+ },
19
+ },
20
+ },
21
+ args: {
22
+ gap: "rec-default",
23
+ columns: 12,
24
+ grow: false,
25
+ },
26
+ argTypes: {
27
+ gap: {
28
+ control: "select",
29
+ options: [
30
+ "rec-none",
31
+ "rec-sm",
32
+ "rec-default",
33
+ "rec-md",
34
+ "rec-lg",
35
+ "rec-xl",
36
+ "rec-2xl",
37
+ ],
38
+ description: "Gap between columns",
39
+ },
40
+ columns: {
41
+ control: "number",
42
+ description: "Number of columns in each row",
43
+ },
44
+ grow: {
45
+ control: "boolean",
46
+ description: "Columns in the last row expand to fill available space",
47
+ },
48
+ justify: {
49
+ control: "select",
50
+ options: [
51
+ "flex-start",
52
+ "center",
53
+ "flex-end",
54
+ "space-between",
55
+ "space-around",
56
+ ],
57
+ description: "Justify-content property",
58
+ },
59
+ align: {
60
+ control: "select",
61
+ options: ["flex-start", "center", "flex-end", "stretch"],
62
+ description: "Align-items property",
63
+ },
64
+ },
65
+ };
66
+
67
+ export default meta;
68
+
69
+ type Story = StoryObj<GridStoryProps>;
70
+
71
+ const Swatch = ({ children }: { children: React.ReactNode }) => (
72
+ <Card>
73
+ <Card.Content>
74
+ <Text>{children}</Text>
75
+ </Card.Content>
76
+ </Card>
77
+ );
78
+
79
+ export const Default: Story = {
80
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
81
+ render: ({ withLayer, layer, ...args }: any) => (
82
+ <Grid {...args}>
83
+ <Grid.Col span={4}>
84
+ <Swatch>span 4</Swatch>
85
+ </Grid.Col>
86
+ <Grid.Col span={4}>
87
+ <Swatch>span 4</Swatch>
88
+ </Grid.Col>
89
+ <Grid.Col span={4}>
90
+ <Swatch>span 4</Swatch>
91
+ </Grid.Col>
92
+ </Grid>
93
+ ),
94
+ };
95
+
96
+ export const ResponsiveSpans: Story = {
97
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
98
+ render: ({ withLayer, layer, ...args }: any) => (
99
+ <Grid {...args}>
100
+ <Grid.Col span={{ base: 12, sm: 6, md: 3 }}>
101
+ <Swatch>base 12 / sm 6 / md 3</Swatch>
102
+ </Grid.Col>
103
+ <Grid.Col span={{ base: 12, sm: 6, md: 3 }}>
104
+ <Swatch>base 12 / sm 6 / md 3</Swatch>
105
+ </Grid.Col>
106
+ <Grid.Col span={{ base: 12, sm: 6, md: 3 }}>
107
+ <Swatch>base 12 / sm 6 / md 3</Swatch>
108
+ </Grid.Col>
109
+ <Grid.Col span={{ base: 12, sm: 6, md: 3 }}>
110
+ <Swatch>base 12 / sm 6 / md 3</Swatch>
111
+ </Grid.Col>
112
+ </Grid>
113
+ ),
114
+ };
115
+
116
+ export const Offset: Story = {
117
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
118
+ render: ({ withLayer, layer, ...args }: any) => (
119
+ <Grid {...args}>
120
+ <Grid.Col span={4} offset={4}>
121
+ <Swatch>span 4, offset 4</Swatch>
122
+ </Grid.Col>
123
+ <Grid.Col span={4}>
124
+ <Swatch>span 4</Swatch>
125
+ </Grid.Col>
126
+ </Grid>
127
+ ),
128
+ };
129
+
130
+ export const Grow: Story = {
131
+ args: {
132
+ grow: true,
133
+ },
134
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
135
+ render: ({ withLayer, layer, ...args }: any) => (
136
+ <Grid {...args}>
137
+ <Grid.Col span={3}>
138
+ <Swatch>span 3</Swatch>
139
+ </Grid.Col>
140
+ <Grid.Col span={3}>
141
+ <Swatch>span 3</Swatch>
142
+ </Grid.Col>
143
+ <Grid.Col span={3}>
144
+ <Swatch>span 3 (grows to fill row)</Swatch>
145
+ </Grid.Col>
146
+ </Grid>
147
+ ),
148
+ };
149
+
150
+ export const CustomColumnCount: Story = {
151
+ args: {
152
+ columns: 6,
153
+ },
154
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
155
+ render: ({ withLayer, layer, ...args }: any) => (
156
+ <Grid {...args}>
157
+ <Grid.Col span={2}>
158
+ <Swatch>span 2 of 6</Swatch>
159
+ </Grid.Col>
160
+ <Grid.Col span={2}>
161
+ <Swatch>span 2 of 6</Swatch>
162
+ </Grid.Col>
163
+ <Grid.Col span={2}>
164
+ <Swatch>span 2 of 6</Swatch>
165
+ </Grid.Col>
166
+ </Grid>
167
+ ),
168
+ };
169
+
170
+ export const VisibleHiddenFrom: Story = {
171
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
172
+ render: ({ withLayer, layer, ...args }: any) => (
173
+ <Grid {...args}>
174
+ <Grid.Col span={6} hiddenFrom="sm">
175
+ <Swatch>hidden from sm and up</Swatch>
176
+ </Grid.Col>
177
+ <Grid.Col span={6} visibleFrom="sm">
178
+ <Swatch>visible from sm and up</Swatch>
179
+ </Grid.Col>
180
+ </Grid>
181
+ ),
182
+ };
@@ -0,0 +1,145 @@
1
+ import { forwardRef } from "react";
2
+ import {
3
+ Grid as MantineGrid,
4
+ type GridProps as MantineGridProps,
5
+ type GridColProps as MantineGridColProps,
6
+ createPolymorphicComponent,
7
+ } from "@mantine/core";
8
+ import {
9
+ mapLayoutProps,
10
+ type WithRecursicaSpacing,
11
+ } from "../../utils/filterStylingProps";
12
+ import styles from "./Grid.module.css";
13
+
14
+ import {
15
+ type RecursicaGridProps,
16
+ type RecursicaGridColProps,
17
+ } from "@recursica/adapter-common";
18
+
19
+ /**
20
+ * Grid layout wrapper.
21
+ *
22
+ * Note: Unlike complex UI components, primitive layout components (Flex, Stack, Group, Container, Grid)
23
+ * DO NOT use the `RecursicaOverStyled` gatekeeper. Developers must be able to freely pass
24
+ * width, height, padding, margins, and flexbox alignment props to construct structural layouts.
25
+ */
26
+ export type GridProps = WithRecursicaSpacing<
27
+ Omit<MantineGridProps, "gutter"> & RecursicaGridProps
28
+ >;
29
+
30
+ const _Grid = forwardRef<HTMLDivElement, GridProps>(function Grid(
31
+ { children, gap = "rec-default", ...rest },
32
+ ref,
33
+ ) {
34
+ const mergedClassNames: Partial<Record<string, string>> = {
35
+ root: styles.root,
36
+ };
37
+
38
+ const classNamesProp = rest.classNames;
39
+ if (
40
+ classNamesProp &&
41
+ typeof classNamesProp === "object" &&
42
+ !Array.isArray(classNamesProp)
43
+ ) {
44
+ const o = classNamesProp as Partial<Record<string, string>>;
45
+ mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
46
+ }
47
+
48
+ const classNameProp = rest.className as string | undefined;
49
+ const finalClass = classNameProp
50
+ ? `${styles.root} ${classNameProp}`
51
+ : styles.root;
52
+
53
+ const { gap: gutter, ...mappedRest } = mapLayoutProps({
54
+ gap,
55
+ ...rest,
56
+ } as Record<string, unknown>);
57
+
58
+ return (
59
+ <MantineGrid
60
+ ref={ref}
61
+ gutter={gutter as MantineGridProps["gutter"]}
62
+ className={finalClass}
63
+ classNames={mergedClassNames}
64
+ {...(mappedRest as unknown as Omit<MantineGridProps, "gutter">)}
65
+ >
66
+ {children}
67
+ </MantineGrid>
68
+ );
69
+ });
70
+ _Grid.displayName = "Grid";
71
+
72
+ /**
73
+ * Recursica Grid layout wrapper.
74
+ *
75
+ * Supports polymorphism via the `component` prop for custom element rendering.
76
+ * @example
77
+ * ```tsx
78
+ * <Grid gap="rec-default">
79
+ * <Grid.Col span={6}>Half width</Grid.Col>
80
+ * <Grid.Col span={6}>Half width</Grid.Col>
81
+ * </Grid>
82
+ * ```
83
+ */
84
+ const GridBase = createPolymorphicComponent<"div", GridProps>(_Grid);
85
+
86
+ // ============================================================
87
+ // GRID.COL
88
+ // ============================================================
89
+
90
+ export type GridColProps = WithRecursicaSpacing<
91
+ MantineGridColProps & RecursicaGridColProps
92
+ >;
93
+
94
+ const _GridCol = forwardRef<HTMLDivElement, GridColProps>(function GridCol(
95
+ { children, ...rest },
96
+ ref,
97
+ ) {
98
+ const mergedClassNames: Partial<Record<string, string>> = {
99
+ col: styles.col,
100
+ };
101
+
102
+ const classNamesProp = rest.classNames;
103
+ if (
104
+ classNamesProp &&
105
+ typeof classNamesProp === "object" &&
106
+ !Array.isArray(classNamesProp)
107
+ ) {
108
+ const o = classNamesProp as Partial<Record<string, string>>;
109
+ mergedClassNames.col = o.col ? `${styles.col} ${o.col}` : styles.col;
110
+ }
111
+
112
+ const classNameProp = rest.className as string | undefined;
113
+ const finalClass = classNameProp
114
+ ? `${styles.col} ${classNameProp}`
115
+ : styles.col;
116
+
117
+ return (
118
+ <MantineGrid.Col
119
+ ref={ref}
120
+ className={finalClass}
121
+ classNames={mergedClassNames}
122
+ {...(mapLayoutProps(
123
+ rest as Record<string, unknown>,
124
+ ) as unknown as MantineGridColProps)}
125
+ >
126
+ {children}
127
+ </MantineGrid.Col>
128
+ );
129
+ });
130
+ _GridCol.displayName = "GridCol";
131
+
132
+ export const GridCol = createPolymorphicComponent<"div", GridColProps>(
133
+ _GridCol,
134
+ );
135
+
136
+ // ============================================================
137
+ // DOT NOTATION EXPORT
138
+ // ============================================================
139
+
140
+ type GridComponent = typeof GridBase & {
141
+ Col: typeof GridCol;
142
+ };
143
+
144
+ export const Grid = GridBase as GridComponent;
145
+ Grid.Col = GridCol;
@@ -0,0 +1,47 @@
1
+ # Grid - Usage Guide
2
+
3
+ This document describes how to integrate and use the `Grid` component in your projects using `@recursica/mantine-adapter`.
4
+
5
+ ---
6
+
7
+ ## 1. Import Reference
8
+
9
+ ```tsx
10
+ import { Grid } from "@recursica/mantine-adapter";
11
+ ```
12
+
13
+ ---
14
+
15
+ ## 2. Basic Example
16
+
17
+ ```tsx
18
+ import React from "react";
19
+ import { Grid } from "@recursica/mantine-adapter";
20
+
21
+ export default function Demo() {
22
+ return (
23
+ <Grid gap="rec-default">
24
+ <Grid.Col span={6}>Half width</Grid.Col>
25
+ <Grid.Col span={{ base: 12, sm: 6, md: 3 }}>Responsive width</Grid.Col>
26
+ </Grid>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ---
32
+
33
+ ## 3. Design System Integration
34
+
35
+ All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
36
+
37
+ > [!IMPORTANT]
38
+ >
39
+ > - **Anti-override protection**: `Grid` is a primitive layout component (see [OVERSTYLING.md](../../../OVERSTYLING.md)) and is exempt from the `RecursicaOverStyled` gatekeeper, so standard Mantine layout props pass through freely.
40
+ > - **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
+ > - **Variables and Theming**: Spacing is entirely determined by the `rec-*` token scale, mapped transparently to standard Mantine gutter values.
42
+
43
+ ---
44
+
45
+ ## 4. Key Integration Features & Constraints
46
+
47
+ The `Grid` component maps directly to Mantine's `Grid`/`Grid.Col`. The one deviation from Mantine's native API: the prop for spacing between columns is named `gap` (not Mantine's `gutter`), for consistency with `Flex`, `Stack`, and `Group`. Everything else — `columns`, `grow`, `justify`, `align` on `Grid`, and `span`, `offset`, `order`, `visibleFrom`, `hiddenFrom` on `Grid.Col` — matches Mantine's own naming and accepts the same shapes, including per-breakpoint objects (`{ base, xs, sm, md, lg, xl }`).