@recursica/mantine-adapter 0.32.0 → 0.34.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/CHANGELOG.md +12 -0
- package/OVERSTYLING.md +56 -0
- package/USAGE.md +6 -4
- package/dist/mantine-adapter.cjs +2 -2
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.js +1765 -1445
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/Modal/Modal.d.ts +21 -8
- package/dist/src/components/Pagination/Pagination.d.ts +45 -25
- package/dist/src/components/Panel/Panel.d.ts +22 -8
- package/dist/src/components/Stepper/Stepper.d.ts +4 -2
- package/dist/src/components/Table/Table.d.ts +25 -9
- package/dist/src/components/Tooltip/Tooltip.d.ts +4 -2
- package/llms.txt +57 -2
- package/package.json +3 -2
- package/src/OverStyling.tsx +10 -226
- package/src/components/Accordion/USAGE.md +90 -0
- package/src/components/AssistiveElement/USAGE.md +36 -0
- package/src/components/AutoComplete/USAGE.md +66 -0
- package/src/components/Avatar/USAGE.md +65 -0
- package/src/components/Badge/USAGE.md +59 -0
- package/src/components/Breadcrumb/USAGE.md +59 -0
- package/src/components/Button/USAGE.md +100 -0
- package/src/components/Card/USAGE.md +71 -0
- package/src/components/Checkbox/USAGE.md +64 -0
- package/src/components/Chip/USAGE.md +77 -0
- package/src/components/Container/USAGE.md +47 -0
- package/src/components/DatePicker/USAGE.md +55 -0
- package/src/components/Dropdown/USAGE.md +51 -0
- package/src/components/FileInput/USAGE.md +36 -0
- package/src/components/FileUpload/USAGE.md +41 -0
- package/src/components/Flex/USAGE.md +48 -0
- package/src/components/FormControlLayout/USAGE.md +40 -0
- package/src/components/FormControlWrapper/USAGE.md +75 -0
- package/src/components/Group/USAGE.md +48 -0
- package/src/components/HoverCard/USAGE.md +121 -0
- package/src/components/Label/USAGE.md +87 -0
- package/src/components/Link/USAGE.md +69 -0
- package/src/components/Loader/USAGE.md +63 -0
- package/src/components/Menu/USAGE.md +124 -0
- package/src/components/Modal/Modal.tsx +129 -23
- package/src/components/Modal/USAGE.md +58 -0
- package/src/components/NumberInput/USAGE.md +55 -0
- package/src/components/Pagination/Pagination.tsx +73 -17
- package/src/components/Pagination/USAGE.md +55 -0
- package/src/components/Panel/Panel.tsx +134 -14
- package/src/components/Panel/USAGE.md +145 -0
- package/src/components/Popover/USAGE.md +121 -0
- package/src/components/Radio/USAGE.md +36 -0
- package/src/components/ReadOnlyField/USAGE.md +52 -0
- package/src/components/SegmentedControl/USAGE.md +56 -0
- package/src/components/Slider/USAGE.md +86 -0
- package/src/components/Stack/USAGE.md +48 -0
- package/src/components/Stepper/Stepper.tsx +20 -2
- package/src/components/Stepper/USAGE.md +41 -0
- package/src/components/Switch/USAGE.md +65 -0
- package/src/components/Table/Table.tsx +153 -16
- package/src/components/Table/USAGE.md +41 -0
- package/src/components/Tabs/USAGE.md +45 -0
- package/src/components/Text/USAGE.md +40 -0
- package/src/components/TextArea/USAGE.md +48 -0
- package/src/components/TextField/USAGE.md +60 -0
- package/src/components/TimePicker/USAGE.md +36 -0
- package/src/components/Timeline/USAGE.md +57 -0
- package/src/components/Title/USAGE.md +36 -0
- package/src/components/Toast/USAGE.md +80 -0
- package/src/components/Tooltip/Tooltip.tsx +26 -2
- package/src/components/Tooltip/USAGE.md +124 -0
- package/src/components/TransferList/USAGE.md +46 -0
- package/src/components/Tree/USAGE.md +46 -0
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
Pagination as MantinePagination,
|
|
5
5
|
type PaginationProps as MantinePaginationProps,
|
|
6
6
|
type PaginationRootProps as MantinePaginationRootProps,
|
|
7
|
+
type PaginationControlProps as MantinePaginationControlProps,
|
|
8
|
+
type PaginationDotsProps as MantinePaginationDotsProps,
|
|
7
9
|
} from "@mantine/core";
|
|
8
10
|
import {
|
|
9
11
|
filterStylingProps,
|
|
@@ -28,11 +30,13 @@ export type PaginationRootProps =
|
|
|
28
30
|
RecursicaOverStyled<MantinePaginationRootProps>;
|
|
29
31
|
|
|
30
32
|
export type PaginationEdgeProps<T extends React.ElementType> =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
RecursicaOverStyled<
|
|
34
|
+
React.ComponentProps<T> & {
|
|
35
|
+
/** If set to true, displays text labels alongside the icon. */
|
|
36
|
+
withLabel?: boolean;
|
|
37
|
+
icon?: any;
|
|
38
|
+
}
|
|
39
|
+
>;
|
|
36
40
|
|
|
37
41
|
function usePaginationClassNames(restRecord: Record<string, unknown>): {
|
|
38
42
|
className: string;
|
|
@@ -88,14 +92,18 @@ _PaginationRoot.displayName = "Pagination.Root";
|
|
|
88
92
|
const _PaginationNext = forwardRef<
|
|
89
93
|
HTMLButtonElement,
|
|
90
94
|
PaginationEdgeProps<typeof MantinePagination.Next>
|
|
91
|
-
>(function PaginationNext(
|
|
95
|
+
>(function PaginationNext(
|
|
96
|
+
{ overStyled = false, withLabel, icon, ...rest },
|
|
97
|
+
ref,
|
|
98
|
+
) {
|
|
99
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
92
100
|
const renderIcon = icon || (withLabel ? NextWithLabel : undefined);
|
|
93
101
|
return (
|
|
94
102
|
<MantinePagination.Next
|
|
95
103
|
ref={ref}
|
|
96
104
|
data-variant="text"
|
|
97
105
|
icon={renderIcon as any}
|
|
98
|
-
{...
|
|
106
|
+
{...sanitizedProps}
|
|
99
107
|
/>
|
|
100
108
|
);
|
|
101
109
|
});
|
|
@@ -104,14 +112,18 @@ _PaginationNext.displayName = "Pagination.Next";
|
|
|
104
112
|
const _PaginationPrevious = forwardRef<
|
|
105
113
|
HTMLButtonElement,
|
|
106
114
|
PaginationEdgeProps<typeof MantinePagination.Previous>
|
|
107
|
-
>(function PaginationPrevious(
|
|
115
|
+
>(function PaginationPrevious(
|
|
116
|
+
{ overStyled = false, withLabel, icon, ...rest },
|
|
117
|
+
ref,
|
|
118
|
+
) {
|
|
119
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
108
120
|
const renderIcon = icon || (withLabel ? PrevWithLabel : undefined);
|
|
109
121
|
return (
|
|
110
122
|
<MantinePagination.Previous
|
|
111
123
|
ref={ref}
|
|
112
124
|
data-variant="text"
|
|
113
125
|
icon={renderIcon as any}
|
|
114
|
-
{...
|
|
126
|
+
{...sanitizedProps}
|
|
115
127
|
/>
|
|
116
128
|
);
|
|
117
129
|
});
|
|
@@ -120,14 +132,18 @@ _PaginationPrevious.displayName = "Pagination.Previous";
|
|
|
120
132
|
const _PaginationFirst = forwardRef<
|
|
121
133
|
HTMLButtonElement,
|
|
122
134
|
PaginationEdgeProps<typeof MantinePagination.First>
|
|
123
|
-
>(function PaginationFirst(
|
|
135
|
+
>(function PaginationFirst(
|
|
136
|
+
{ overStyled = false, withLabel, icon, ...rest },
|
|
137
|
+
ref,
|
|
138
|
+
) {
|
|
139
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
124
140
|
const renderIcon = icon || (withLabel ? FirstWithLabel : undefined);
|
|
125
141
|
return (
|
|
126
142
|
<MantinePagination.First
|
|
127
143
|
ref={ref}
|
|
128
144
|
data-variant="text"
|
|
129
145
|
icon={renderIcon as any}
|
|
130
|
-
{...
|
|
146
|
+
{...sanitizedProps}
|
|
131
147
|
/>
|
|
132
148
|
);
|
|
133
149
|
});
|
|
@@ -136,14 +152,18 @@ _PaginationFirst.displayName = "Pagination.First";
|
|
|
136
152
|
const _PaginationLast = forwardRef<
|
|
137
153
|
HTMLButtonElement,
|
|
138
154
|
PaginationEdgeProps<typeof MantinePagination.Last>
|
|
139
|
-
>(function PaginationLast(
|
|
155
|
+
>(function PaginationLast(
|
|
156
|
+
{ overStyled = false, withLabel, icon, ...rest },
|
|
157
|
+
ref,
|
|
158
|
+
) {
|
|
159
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
140
160
|
const renderIcon = icon || (withLabel ? LastWithLabel : undefined);
|
|
141
161
|
return (
|
|
142
162
|
<MantinePagination.Last
|
|
143
163
|
ref={ref}
|
|
144
164
|
data-variant="text"
|
|
145
165
|
icon={renderIcon as any}
|
|
146
|
-
{...
|
|
166
|
+
{...sanitizedProps}
|
|
147
167
|
/>
|
|
148
168
|
);
|
|
149
169
|
});
|
|
@@ -192,14 +212,47 @@ const _Pagination = forwardRef<HTMLDivElement, PaginationProps>(
|
|
|
192
212
|
);
|
|
193
213
|
_Pagination.displayName = "Pagination";
|
|
194
214
|
|
|
215
|
+
export type PaginationControlProps =
|
|
216
|
+
RecursicaOverStyled<MantinePaginationControlProps>;
|
|
217
|
+
|
|
218
|
+
const _PaginationControl = forwardRef<
|
|
219
|
+
HTMLButtonElement,
|
|
220
|
+
PaginationControlProps
|
|
221
|
+
>(function PaginationControl({ overStyled = false, ...rest }, ref) {
|
|
222
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
223
|
+
return (
|
|
224
|
+
<MantinePagination.Control
|
|
225
|
+
ref={ref}
|
|
226
|
+
{...(sanitizedProps as unknown as MantinePaginationControlProps)}
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
_PaginationControl.displayName = "Pagination.Control";
|
|
231
|
+
|
|
232
|
+
export type PaginationDotsProps =
|
|
233
|
+
RecursicaOverStyled<MantinePaginationDotsProps>;
|
|
234
|
+
|
|
235
|
+
const _PaginationDots = forwardRef<HTMLDivElement, PaginationDotsProps>(
|
|
236
|
+
function PaginationDots({ overStyled = false, ...rest }, ref) {
|
|
237
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
238
|
+
return (
|
|
239
|
+
<MantinePagination.Dots
|
|
240
|
+
ref={ref}
|
|
241
|
+
{...(sanitizedProps as unknown as MantinePaginationDotsProps)}
|
|
242
|
+
/>
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
);
|
|
246
|
+
_PaginationDots.displayName = "Pagination.Dots";
|
|
247
|
+
|
|
195
248
|
/**
|
|
196
249
|
* Recursica Pagination component wrapping Mantine's Pagination.
|
|
197
250
|
*/
|
|
198
251
|
export const Pagination = _Pagination as typeof _Pagination & {
|
|
199
252
|
Root: typeof _PaginationRoot;
|
|
200
253
|
Items: typeof MantinePagination.Items;
|
|
201
|
-
Control: typeof
|
|
202
|
-
Dots: typeof
|
|
254
|
+
Control: typeof _PaginationControl;
|
|
255
|
+
Dots: typeof _PaginationDots;
|
|
203
256
|
Next: typeof _PaginationNext;
|
|
204
257
|
Previous: typeof _PaginationPrevious;
|
|
205
258
|
First: typeof _PaginationFirst;
|
|
@@ -208,9 +261,12 @@ export const Pagination = _Pagination as typeof _Pagination & {
|
|
|
208
261
|
};
|
|
209
262
|
|
|
210
263
|
Pagination.Root = _PaginationRoot;
|
|
264
|
+
// Pagination.Items has no styling props of its own (just a `dotsIcon` prop, no
|
|
265
|
+
// `style`/`className`/BoxProps), so re-exporting Mantine's implementation
|
|
266
|
+
// directly is not a styling-gate gap.
|
|
211
267
|
Pagination.Items = MantinePagination.Items;
|
|
212
|
-
Pagination.Control =
|
|
213
|
-
Pagination.Dots =
|
|
268
|
+
Pagination.Control = _PaginationControl;
|
|
269
|
+
Pagination.Dots = _PaginationDots;
|
|
214
270
|
Pagination.Next = _PaginationNext;
|
|
215
271
|
Pagination.Previous = _PaginationPrevious;
|
|
216
272
|
Pagination.First = _PaginationFirst;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Pagination - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Pagination` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Pagination } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Pagination } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <Pagination total={10} value={activePage} onChange={setPage} />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
31
|
+
|
|
32
|
+
> [!IMPORTANT]
|
|
33
|
+
>
|
|
34
|
+
> - **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.
|
|
35
|
+
> - **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.
|
|
36
|
+
> - **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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
## Architecture Decision: CSS Inheritance vs. Composition
|
|
43
|
+
|
|
44
|
+
The Figma design tokens for the `Pagination` component dictate that pagination pages perfectly mimic `Button` variants (e.g. `active-pages_style: "solid"`, `inactive-pages_style: "outline"`, `navigation-controls_style: "text"`).
|
|
45
|
+
|
|
46
|
+
As of the `1.2.0` scoped CSS update, the Figma exporter automatically handles these variants. It flattens and aliases the referenced Button properties directly into the `Pagination` component's variable namespace.
|
|
47
|
+
|
|
48
|
+
We opted to use Mantine's native `PaginationControl` components to ensure all DOM structure, focus management, and accessibility attributes are preserved natively without us needing to carefully rebuild `Pagination.Items` mappings.
|
|
49
|
+
|
|
50
|
+
To honor the Figma design intents while using Mantine's raw `<button>` elements:
|
|
51
|
+
|
|
52
|
+
1. We inherit and map all natively scoped `Pagination` variant styles (small typography, outline/solid/text colors, and hover overlays) directly into `.control` and `.control[data-active]` within `Pagination.module.css`. We do not need to manually reference `Button` variables cross-component.
|
|
53
|
+
2. We inject `data-variant="text"` via `getControlProps` onto the navigation buttons so that they inherit the explicitly aliased text style variables (`navigation-controls`) defined by the UI Kit for pagination.
|
|
54
|
+
|
|
55
|
+
This achieves exact optical alignment with the tokens while maintaining Mantine's robust internal event handling for pagination.
|
|
@@ -2,6 +2,13 @@ import { forwardRef } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
Drawer as MantineDrawer,
|
|
4
4
|
type DrawerProps as MantineDrawerProps,
|
|
5
|
+
type DrawerRootProps as MantineDrawerRootProps,
|
|
6
|
+
type DrawerOverlayProps as MantineDrawerOverlayProps,
|
|
7
|
+
type DrawerContentProps as MantineDrawerContentProps,
|
|
8
|
+
type DrawerHeaderProps as MantineDrawerHeaderProps,
|
|
9
|
+
type DrawerTitleProps as MantineDrawerTitleProps,
|
|
10
|
+
type DrawerCloseButtonProps as MantineDrawerCloseButtonProps,
|
|
11
|
+
type DrawerBodyProps as MantineDrawerBodyProps,
|
|
5
12
|
} from "@mantine/core";
|
|
6
13
|
import {
|
|
7
14
|
filterStylingProps,
|
|
@@ -128,29 +135,142 @@ export const PanelFooter = forwardRef<HTMLDivElement, PanelFooterProps>(
|
|
|
128
135
|
);
|
|
129
136
|
PanelFooter.displayName = "PanelFooter";
|
|
130
137
|
|
|
138
|
+
// ============================================================
|
|
139
|
+
// PANEL SUB-COMPONENTS (wrapped so overStyled/filterStylingProps applies)
|
|
140
|
+
// ============================================================
|
|
141
|
+
|
|
142
|
+
export type PanelRootProps = RecursicaOverStyled<MantineDrawerRootProps>;
|
|
143
|
+
|
|
144
|
+
export const PanelRoot = forwardRef<HTMLDivElement, PanelRootProps>(
|
|
145
|
+
function PanelRoot({ overStyled = false, ...rest }, ref) {
|
|
146
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
147
|
+
return (
|
|
148
|
+
<MantineDrawer.Root
|
|
149
|
+
ref={ref}
|
|
150
|
+
{...(sanitizedProps as unknown as MantineDrawerRootProps)}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
PanelRoot.displayName = "PanelRoot";
|
|
156
|
+
|
|
157
|
+
export type PanelOverlayProps = RecursicaOverStyled<MantineDrawerOverlayProps>;
|
|
158
|
+
|
|
159
|
+
export const PanelOverlay = forwardRef<HTMLDivElement, PanelOverlayProps>(
|
|
160
|
+
function PanelOverlay({ overStyled = false, ...rest }, ref) {
|
|
161
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
162
|
+
return (
|
|
163
|
+
<MantineDrawer.Overlay
|
|
164
|
+
ref={ref}
|
|
165
|
+
{...(sanitizedProps as unknown as MantineDrawerOverlayProps)}
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
PanelOverlay.displayName = "PanelOverlay";
|
|
171
|
+
|
|
172
|
+
export type PanelContentProps = RecursicaOverStyled<MantineDrawerContentProps>;
|
|
173
|
+
|
|
174
|
+
export const PanelContent = forwardRef<HTMLDivElement, PanelContentProps>(
|
|
175
|
+
function PanelContent({ overStyled = false, ...rest }, ref) {
|
|
176
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
177
|
+
return (
|
|
178
|
+
<MantineDrawer.Content
|
|
179
|
+
ref={ref}
|
|
180
|
+
{...(sanitizedProps as unknown as MantineDrawerContentProps)}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
PanelContent.displayName = "PanelContent";
|
|
186
|
+
|
|
187
|
+
export type PanelHeaderProps = RecursicaOverStyled<MantineDrawerHeaderProps>;
|
|
188
|
+
|
|
189
|
+
export const PanelHeader = forwardRef<HTMLElement, PanelHeaderProps>(
|
|
190
|
+
function PanelHeader({ overStyled = false, ...rest }, ref) {
|
|
191
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
192
|
+
return (
|
|
193
|
+
<MantineDrawer.Header
|
|
194
|
+
ref={ref}
|
|
195
|
+
{...(sanitizedProps as unknown as MantineDrawerHeaderProps)}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
PanelHeader.displayName = "PanelHeader";
|
|
201
|
+
|
|
202
|
+
export type PanelTitleProps = RecursicaOverStyled<MantineDrawerTitleProps>;
|
|
203
|
+
|
|
204
|
+
export const PanelTitle = forwardRef<HTMLHeadingElement, PanelTitleProps>(
|
|
205
|
+
function PanelTitle({ overStyled = false, ...rest }, ref) {
|
|
206
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
207
|
+
return (
|
|
208
|
+
<MantineDrawer.Title
|
|
209
|
+
ref={ref}
|
|
210
|
+
{...(sanitizedProps as unknown as MantineDrawerTitleProps)}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
PanelTitle.displayName = "PanelTitle";
|
|
216
|
+
|
|
217
|
+
export type PanelCloseButtonProps =
|
|
218
|
+
RecursicaOverStyled<MantineDrawerCloseButtonProps>;
|
|
219
|
+
|
|
220
|
+
export const PanelCloseButton = forwardRef<
|
|
221
|
+
HTMLButtonElement,
|
|
222
|
+
PanelCloseButtonProps
|
|
223
|
+
>(function PanelCloseButton({ overStyled = false, ...rest }, ref) {
|
|
224
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
225
|
+
return (
|
|
226
|
+
<MantineDrawer.CloseButton
|
|
227
|
+
ref={ref}
|
|
228
|
+
{...(sanitizedProps as unknown as MantineDrawerCloseButtonProps)}
|
|
229
|
+
/>
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
PanelCloseButton.displayName = "PanelCloseButton";
|
|
233
|
+
|
|
234
|
+
export type PanelBodyProps = RecursicaOverStyled<MantineDrawerBodyProps>;
|
|
235
|
+
|
|
236
|
+
export const PanelBody = forwardRef<HTMLDivElement, PanelBodyProps>(
|
|
237
|
+
function PanelBody({ overStyled = false, ...rest }, ref) {
|
|
238
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
239
|
+
return (
|
|
240
|
+
<MantineDrawer.Body
|
|
241
|
+
ref={ref}
|
|
242
|
+
{...(sanitizedProps as unknown as MantineDrawerBodyProps)}
|
|
243
|
+
/>
|
|
244
|
+
);
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
PanelBody.displayName = "PanelBody";
|
|
248
|
+
|
|
131
249
|
// ============================================================
|
|
132
250
|
// DOT NOTATION EXPORT
|
|
133
251
|
// ============================================================
|
|
134
252
|
|
|
135
253
|
type PanelComponent = typeof PanelBase & {
|
|
136
|
-
Root: typeof
|
|
137
|
-
Overlay: typeof
|
|
138
|
-
Content: typeof
|
|
139
|
-
Header: typeof
|
|
140
|
-
Title: typeof
|
|
141
|
-
CloseButton: typeof
|
|
142
|
-
Body: typeof
|
|
254
|
+
Root: typeof PanelRoot;
|
|
255
|
+
Overlay: typeof PanelOverlay;
|
|
256
|
+
Content: typeof PanelContent;
|
|
257
|
+
Header: typeof PanelHeader;
|
|
258
|
+
Title: typeof PanelTitle;
|
|
259
|
+
CloseButton: typeof PanelCloseButton;
|
|
260
|
+
Body: typeof PanelBody;
|
|
143
261
|
Stack: typeof MantineDrawer.Stack;
|
|
144
262
|
Footer: typeof PanelFooter;
|
|
145
263
|
};
|
|
146
264
|
|
|
147
265
|
export const Panel = PanelBase as PanelComponent;
|
|
148
|
-
Panel.Root =
|
|
149
|
-
Panel.Overlay =
|
|
150
|
-
Panel.Content =
|
|
151
|
-
Panel.Header =
|
|
152
|
-
Panel.Title =
|
|
153
|
-
Panel.CloseButton =
|
|
154
|
-
Panel.Body =
|
|
266
|
+
Panel.Root = PanelRoot;
|
|
267
|
+
Panel.Overlay = PanelOverlay;
|
|
268
|
+
Panel.Content = PanelContent;
|
|
269
|
+
Panel.Header = PanelHeader;
|
|
270
|
+
Panel.Title = PanelTitle;
|
|
271
|
+
Panel.CloseButton = PanelCloseButton;
|
|
272
|
+
Panel.Body = PanelBody;
|
|
273
|
+
// Panel.Stack (DrawerStack) only accepts `children` — no styling props to
|
|
274
|
+
// strip, so re-exporting Mantine's implementation directly is not a gap.
|
|
155
275
|
Panel.Stack = MantineDrawer.Stack;
|
|
156
276
|
Panel.Footer = PanelFooter;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Panel - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Panel` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Panel } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Panel } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Panel>
|
|
24
|
+
<Text>This is a clean, structured visual container.</Text>
|
|
25
|
+
</Panel>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Design System Integration
|
|
33
|
+
|
|
34
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
35
|
+
|
|
36
|
+
> [!IMPORTANT]
|
|
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
|
+
> - **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
|
+
> - **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
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Key Integration Features & Constraints
|
|
45
|
+
|
|
46
|
+
## 1. Mapping to Mantine Drawer
|
|
47
|
+
|
|
48
|
+
**Decision:** Panel maps to Mantine's `Drawer` component, not `Paper` or `Card`.
|
|
49
|
+
|
|
50
|
+
**Implementation:** Per the Recursica design system specification, "Panels slide in or expand from the edge of the screen to reveal additional content or functionality." This is the exact behavior of Mantine's `Drawer` component, which provides:
|
|
51
|
+
|
|
52
|
+
- Slide-in animation from any screen edge
|
|
53
|
+
- Overlay/backdrop
|
|
54
|
+
- Portal rendering
|
|
55
|
+
- Focus trapping
|
|
56
|
+
- Scroll locking
|
|
57
|
+
- Close button and title in header
|
|
58
|
+
|
|
59
|
+
Paper and Card are static containers; Drawer is an overlay that matches Panel's defined behavior.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 2. Token Namespace: `panel`
|
|
64
|
+
|
|
65
|
+
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_panel_*` namespace.
|
|
66
|
+
|
|
67
|
+
**Implementation:** The Recursica token system defines the `panel` namespace covering:
|
|
68
|
+
|
|
69
|
+
- Geometry: border-radius, border-size, min-width (200px), max-width (960px)
|
|
70
|
+
- Content padding: content-horizontal-padding (xl), content-vertical-padding (lg)
|
|
71
|
+
- Header/Footer padding: header-footer-horizontal-padding (xl), header-footer-vertical-padding (md)
|
|
72
|
+
- Spacing: header-close-gap (md), footer-button-gap (md)
|
|
73
|
+
- Divider: divider-size (1px), divider-color
|
|
74
|
+
- Elevation: elevation-3
|
|
75
|
+
- Colors (layer-aware): background, border-color, content, divider-color, header-footer-background, title
|
|
76
|
+
- Non-CSS: header-style ("h3") — see §7
|
|
77
|
+
|
|
78
|
+
No tokens from other component namespaces are referenced.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 3. ClassNames Mapping to Drawer
|
|
83
|
+
|
|
84
|
+
**Decision:** Panel maps CSS module classes to Mantine Drawer's stylesNames.
|
|
85
|
+
|
|
86
|
+
**Implementation:** The Drawer stylesNames used are:
|
|
87
|
+
|
|
88
|
+
- `content` — Outer container (background, border, elevation)
|
|
89
|
+
- `header` — Title bar with close button (padding, divider, gap)
|
|
90
|
+
- `title` — Title text color
|
|
91
|
+
- `body` — Scrollable content area (padding)
|
|
92
|
+
|
|
93
|
+
Other stylesNames (`overlay`, `root`, `inner`, `close`) are left to Mantine defaults.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. Default Placement Override
|
|
98
|
+
|
|
99
|
+
**Decision:** Use `placement` instead of `position` for configuring slide-out direction, and default it to `"right"`.
|
|
100
|
+
|
|
101
|
+
**Implementation:** The prop was renamed from `position` to `placement` to prevent collision with the CSS `position` keyword, which is strictly blocked by the styling gatekeeper (`BLOCKED_STYLING_KEYS`). This allows configuring the drawer direction natively while maintaining strict design-system boundaries. The `placement="right"` default is mapped internally to Mantine Drawer's `position` prop before any other sanitized props are applied. Right-side panels are the most common pattern for supplementary content, settings, and detail views.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 5. Custom Panel.Footer
|
|
106
|
+
|
|
107
|
+
**Decision:** A custom `Panel.Footer` sub-component is provided. Mantine's Drawer does not have a native footer.
|
|
108
|
+
|
|
109
|
+
**Implementation:** `Panel.Footer` is a `<div>` with inline styles referencing Recursica CSS variables for:
|
|
110
|
+
|
|
111
|
+
- `header-footer-background` and `header-footer-padding` tokens
|
|
112
|
+
- Top divider using `divider-size` and `divider-color`
|
|
113
|
+
- `footer-button-gap` for action button spacing
|
|
114
|
+
- `margin-top: auto` to push the footer to the bottom
|
|
115
|
+
|
|
116
|
+
Inline styles are used instead of a CSS module class because the footer is rendered inside the Drawer's `<body>` element, and the CSS variables are applied to the body's parent container. The inline styles ensure the footer correctly references the panel tokens regardless of DOM position.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 6. Hardcoded Values
|
|
121
|
+
|
|
122
|
+
### `border-style: solid` (CSS module, `.content`)
|
|
123
|
+
|
|
124
|
+
Mantine's Drawer content does not set `border-style` natively. Without this, the border-width and border-color tokens have no visible effect. Same pattern as Card, Menu, HoverCard, Tooltip.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 7. `header-style` Typography Utility Class
|
|
129
|
+
|
|
130
|
+
**Decision:** The `header-style` token exports as the string `"h3"`, so we use the generated global utility class `.recursica_brand_typography_h3`.
|
|
131
|
+
|
|
132
|
+
**Implementation:** The PostCSS compiler generates `.recursica_brand_typography_<typeName>` classes at the bottom of the scoped variables file to apply full typography definitions without assigning variables inline. We apply this to the `.title` class via `composes: recursica_brand_typography_h3 from global;`.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 8. Panel Types: Standard vs Scrollable
|
|
137
|
+
|
|
138
|
+
**Decision:** Both standard and scrollable types are supported natively.
|
|
139
|
+
|
|
140
|
+
**Implementation:** Per the Recursica specification:
|
|
141
|
+
|
|
142
|
+
- **Standard** — All content visible without scrolling. The default behavior when content fits.
|
|
143
|
+
- **Scrollable** — Internal scrollbar enabled when content exceeds the panel height. Header and footer CTAs remain pinned.
|
|
144
|
+
|
|
145
|
+
Mantine's Drawer handles this automatically — the `body` section scrolls when content overflows, while the `header` remains fixed. The `Panel.Footer` uses `margin-top: auto` to stay at the bottom.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Popover - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Popover` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Popover } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Popover } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Popover position="bottom" withArrow>
|
|
24
|
+
<Popover.Target>
|
|
25
|
+
<Button>Open Popover</Button>
|
|
26
|
+
</Popover.Target>
|
|
27
|
+
<Popover.Dropdown>
|
|
28
|
+
<Text size="sm">This is the popover content.</Text>
|
|
29
|
+
</Popover.Dropdown>
|
|
30
|
+
</Popover>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 3. Design System Integration
|
|
38
|
+
|
|
39
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
40
|
+
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
>
|
|
43
|
+
> - **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.
|
|
44
|
+
> - **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.
|
|
45
|
+
> - **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.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 4. Key Integration Features & Constraints
|
|
50
|
+
|
|
51
|
+
## 1. Composable API Preservation (1:1 Mapping)
|
|
52
|
+
|
|
53
|
+
**Decision:** We maintain the exact library composition API structure (`<Popover>`, `<Popover.Target>`, `<Popover.Dropdown>`) as a 1:1 React component mapping.
|
|
54
|
+
|
|
55
|
+
**Implementation:** Mantine's Popover internally manages click detection, open/close state, Floating UI positioning, and portal rendering. By preserving the exact sub-component tree, Recursica safely inherits all of these behaviors without reimplementation.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 2. Popover.Target Pass-Through
|
|
60
|
+
|
|
61
|
+
**Decision:** `Popover.Target` is a transparent pass-through with no styling applied.
|
|
62
|
+
|
|
63
|
+
**Implementation:** The target wrapper exists solely to manage Mantine's ref forwarding and event binding for the trigger element. No `filterStylingProps` or CSS module classes are applied — the trigger's appearance is entirely controlled by whatever component the integrator places inside it (e.g., `<Button>`). This is identical to the `Menu.Target` and `HoverCard.Target` pattern.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. Token Namespace: `hover-card-popover`
|
|
68
|
+
|
|
69
|
+
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_hover-card-popover_*` namespace.
|
|
70
|
+
|
|
71
|
+
**Implementation:** The Recursica token system defines a single shared namespace (`hover-card-popover`) for this component and HoverCard. It covers geometry (border-radius, border-size, padding, min/max-width), typography (content-text\_\*), elevation, and layer-aware colors (background, border-color, content).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 4. Hardcoded Values
|
|
76
|
+
|
|
77
|
+
**Decision:** Two hardcoded values exist in the component.
|
|
78
|
+
|
|
79
|
+
### `border-style: solid` (CSS module)
|
|
80
|
+
|
|
81
|
+
Mantine renders the dropdown using its `Paper` component, which does not set `border-style` natively. Without this hardcoded value, the border-width and border-color tokens would have no visible effect. This is the same pattern used in the Menu component's dropdown.
|
|
82
|
+
|
|
83
|
+
### `arrowSize` defaulted to `16` (Popover.tsx)
|
|
84
|
+
|
|
85
|
+
Mantine's `arrowSize` prop is a JavaScript number used for inline style calculations: it sets `width`, `height`, and a positioning offset (`-arrowSize/2`) directly on the arrow `<div>` element. These inline styles **cannot** be overridden via CSS without `!important`, and the positioning offset has no CSS equivalent. This means the beak size cannot be fully CSS-driven — it is one of the rare cases where a design token value must be mirrored as a JS prop.
|
|
86
|
+
|
|
87
|
+
The default value `16` matches the Recursica `beak-size` token (`--recursica_ui-kit_components_hover-card-popover_properties_beak-size: 16px`). Developers can override `arrowSize` if needed, but should be aware this is a design system concern. If the token value changes, the default in `Popover.tsx` must also be updated.
|
|
88
|
+
|
|
89
|
+
This is documented as an open issue in `docs/COMPONENT_ISSUES.md`.
|
|
90
|
+
|
|
91
|
+
**Note:** Mantine calls this the "arrow"; Recursica calls it the "beak". The Recursica prop `withBeak` (defaulting to `true`) maps to Mantine's `withArrow`. Both `withBeak` and `withArrow` are accepted; `withBeak` takes precedence.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 5. Minimal CSS Override Philosophy
|
|
96
|
+
|
|
97
|
+
**Decision:** The CSS module only overrides visual design tokens (colors, typography, spacing, borders, shadows). All structural layout properties are deferred to Mantine's native behavior.
|
|
98
|
+
|
|
99
|
+
**Implementation:** Popover is an overlay component where Mantine's native Floating UI positioning and Paper layout are already correct. We avoid setting:
|
|
100
|
+
|
|
101
|
+
- `overflow` on the dropdown (Mantine handles scroll behavior natively)
|
|
102
|
+
- `display`, `position`, `z-index` (Floating UI controls these)
|
|
103
|
+
- `pointer-events` (Mantine manages hover detection across target and dropdown)
|
|
104
|
+
|
|
105
|
+
**Rationale:** Default to Mantine's native behavior and only override what the Recursica token system explicitly needs to control.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 6. ClassNames Merging on Root
|
|
110
|
+
|
|
111
|
+
**Decision:** The root `Popover` component binds CSS module classes via `classNames` on the Mantine root.
|
|
112
|
+
|
|
113
|
+
**Implementation:** The root component receives `classNames={{ dropdown: styles.dropdown, arrow: styles.arrow }}` and merges any consumer-provided `classNames` when `overStyled` is true. This ensures our token-driven styles are applied to the dropdown panel without wrapper divs, and the consumer's classes are additive.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 7. Default Position Override
|
|
118
|
+
|
|
119
|
+
**Decision:** Recursica defaults `position` to `"top"`. Mantine defaults to `"bottom"`.
|
|
120
|
+
|
|
121
|
+
**Implementation:** The `position="top"` default is set on the Mantine root element before the prop spread, so developer-provided `position` values still take precedence. This aligns with Recursica's design intent for overlay components to appear above their trigger by default.
|