@recursica/mui-adapter 0.2.0 → 0.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.
- package/CHANGELOG.md +6 -0
- package/dist/mui-adapter.cjs +1 -1
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.css +1 -1
- package/dist/mui-adapter.js +249 -90
- package/dist/mui-adapter.js.map +1 -1
- package/dist/src/components/Box/Box.d.ts +2 -3
- package/dist/src/components/Button/Button.d.ts +33 -2
- package/dist/src/components/Container/Container.d.ts +8 -2
- package/dist/src/components/Flex/Flex.d.ts +25 -2
- package/dist/src/components/Group/Group.d.ts +10 -2
- package/dist/src/components/Link/Link.d.ts +13 -2
- package/dist/src/components/Stack/Stack.d.ts +8 -2
- package/dist/src/components/Text/Text.d.ts +18 -2
- package/dist/src/components/Title/Title.d.ts +17 -2
- package/dist/src/components/Typography/Typography.d.ts +27 -0
- package/dist/src/utils/filterStylingProps.d.ts +3 -0
- package/package.json +2 -1
- package/src/Introduction.stories.tsx +113 -110
- package/src/OverStyling.tsx +18 -23
- package/src/Version.tsx +14 -21
- package/src/components/Accordion/Accordion.stories.tsx +19 -0
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +19 -0
- package/src/components/Avatar/Avatar.stories.tsx +19 -0
- package/src/components/Badge/Badge.stories.tsx +19 -0
- package/src/components/Box/Box.stories.tsx +19 -10
- package/src/components/Box/Box.tsx +11 -14
- package/src/components/Box/IMPLEMENTATION_NOTES.md +5 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +19 -0
- package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +17 -0
- package/src/components/Button/Button.module.css +300 -0
- package/src/components/Button/Button.stories.tsx +136 -5
- package/src/components/Button/Button.tsx +116 -5
- package/src/components/Card/Card.stories.tsx +19 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +19 -0
- package/src/components/Chip/Chip.stories.tsx +19 -0
- package/src/components/Container/Container.stories.tsx +19 -0
- package/src/components/Container/Container.tsx +56 -5
- package/src/components/Container/IMPLEMENTATION_NOTES.md +5 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +19 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +19 -0
- package/src/components/FileInput/FileInput.stories.tsx +19 -0
- package/src/components/FileUpload/FileUpload.stories.tsx +19 -0
- package/src/components/Flex/Flex.stories.tsx +19 -0
- package/src/components/Flex/Flex.tsx +77 -5
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +19 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +19 -0
- package/src/components/Group/Group.stories.tsx +133 -5
- package/src/components/Group/Group.tsx +57 -5
- package/src/components/HoverCard/HoverCard.stories.tsx +19 -0
- package/src/components/Label/Label.stories.tsx +19 -0
- package/src/components/Link/Link.module.css +133 -0
- package/src/components/Link/Link.stories.tsx +52 -4
- package/src/components/Link/Link.tsx +47 -5
- package/src/components/Loader/Loader.stories.tsx +19 -0
- package/src/components/Menu/Menu.stories.tsx +19 -0
- package/src/components/Modal/Modal.stories.tsx +19 -0
- package/src/components/NumberInput/NumberInput.stories.tsx +19 -0
- package/src/components/Pagination/Pagination.stories.tsx +19 -0
- package/src/components/Panel/Panel.stories.tsx +19 -0
- package/src/components/Radio/Radio.stories.tsx +19 -0
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +19 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +19 -0
- package/src/components/Slider/Slider.stories.tsx +19 -0
- package/src/components/Stack/Stack.stories.tsx +118 -5
- package/src/components/Stack/Stack.tsx +37 -5
- package/src/components/Stepper/Stepper.stories.tsx +19 -0
- package/src/components/Switch/Switch.stories.tsx +19 -0
- package/src/components/Table/Table.stories.tsx +19 -0
- package/src/components/Tabs/Tabs.stories.tsx +19 -0
- package/src/components/Text/Text.stories.tsx +87 -3
- package/src/components/Text/Text.tsx +27 -4
- package/src/components/TextArea/TextArea.stories.tsx +19 -0
- package/src/components/TextField/TextField.stories.tsx +19 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +19 -0
- package/src/components/Timeline/Timeline.stories.tsx +19 -0
- package/src/components/Title/Title.stories.tsx +68 -3
- package/src/components/Title/Title.tsx +29 -5
- package/src/components/Toast/Toast.stories.tsx +19 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +19 -0
- package/src/components/TransferList/TransferList.stories.tsx +19 -0
- package/src/components/Typography/Typography.tsx +42 -0
- package/src/utils/ColorSchemeWrapper.tsx +1 -5
- package/src/utils/filterStylingProps.ts +13 -1
|
@@ -1,7 +1,118 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Button as MuiButton,
|
|
4
|
+
type ButtonProps as MuiButtonProps,
|
|
5
|
+
} from "@mui/material";
|
|
6
|
+
import {
|
|
7
|
+
filterStylingProps,
|
|
8
|
+
type RecursicaOverStyled,
|
|
9
|
+
} from "../../utils/filterStylingProps";
|
|
10
|
+
import styles from "./Button.module.css";
|
|
2
11
|
|
|
3
|
-
export
|
|
12
|
+
export interface RecursicaButtonProps {
|
|
13
|
+
variant?: "solid" | "outline" | "text";
|
|
14
|
+
size?: "default" | "small";
|
|
15
|
+
icon?: React.ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* For polymorphic support (e.g., `component="a"`), native to MUI.
|
|
18
|
+
*/
|
|
19
|
+
component?: React.ElementType;
|
|
20
|
+
}
|
|
4
21
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
22
|
+
export type ButtonProps = RecursicaOverStyled<
|
|
23
|
+
Omit<MuiButtonProps, "variant" | "size" | "color" | "fullWidth"> &
|
|
24
|
+
RecursicaButtonProps
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
function hasVisibleChildren(children: React.ReactNode): boolean {
|
|
28
|
+
if (children == null || children === "") return false;
|
|
29
|
+
if (typeof children === "string") return children.trim() !== "";
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Recursica Button component wrapping MUI's Button.
|
|
35
|
+
*
|
|
36
|
+
* Supports polymorphism via the `component` prop for custom element rendering.
|
|
37
|
+
* This is particularly useful when you need a button that behaves as a hyperlink (rendering an `<a>` tag)
|
|
38
|
+
* or integrates with a routing library (e.g., `react-router-dom` or Next.js), while preserving full visual styling.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* // Renders as an <a> tag natively
|
|
43
|
+
* <Button component="a" href="/dashboard" target="_blank">Navigate</Button>
|
|
44
|
+
*
|
|
45
|
+
* // Renders using a custom router link
|
|
46
|
+
* <Button component={Link} to="/home">Home</Button>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
50
|
+
function Button(
|
|
51
|
+
{
|
|
52
|
+
variant = "solid",
|
|
53
|
+
size = "default",
|
|
54
|
+
icon,
|
|
55
|
+
children,
|
|
56
|
+
overStyled = false,
|
|
57
|
+
...rest
|
|
58
|
+
},
|
|
59
|
+
ref,
|
|
60
|
+
) {
|
|
61
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
62
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
63
|
+
|
|
64
|
+
// Explicitly delete blocked semantic expansion dimension props that MUI uses natively
|
|
65
|
+
delete restRecord["fullWidth"];
|
|
66
|
+
delete restRecord["color"]; // Recursica handles colors internally via tokens
|
|
67
|
+
|
|
68
|
+
const hasStartIcon = !!icon || !!restRecord["startIcon"];
|
|
69
|
+
const hasEndIcon = !!restRecord["endIcon"];
|
|
70
|
+
const isIconOnly =
|
|
71
|
+
(hasStartIcon || hasEndIcon) && !hasVisibleChildren(children);
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
typeof process !== "undefined" &&
|
|
75
|
+
process.env.NODE_ENV !== "production" &&
|
|
76
|
+
isIconOnly &&
|
|
77
|
+
!restRecord["aria-label"]
|
|
78
|
+
) {
|
|
79
|
+
console.warn(
|
|
80
|
+
'[Recursica Button] Icon-only buttons must provide an accessible name. Pass aria-label (e.g. aria-label="Submit").',
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
85
|
+
const finalClass = classNameProp
|
|
86
|
+
? `${styles.root} ${classNameProp}`
|
|
87
|
+
: styles.root;
|
|
88
|
+
|
|
89
|
+
// We don't map Recursica variant/size to MUI's because we want to completely disable MUI's native
|
|
90
|
+
// variant logic (e.g., elevation, shadows) and style everything strictly through our CSS Modules.
|
|
91
|
+
// However, Mui Button requires some string, but we can just leave it as standard or ignore since
|
|
92
|
+
// our CSS resets its properties anyway, but to be clean we just don't pass variant to MUI.
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<MuiButton
|
|
96
|
+
ref={ref}
|
|
97
|
+
disableRipple
|
|
98
|
+
disableElevation
|
|
99
|
+
className={finalClass}
|
|
100
|
+
startIcon={
|
|
101
|
+
icon != null ? (
|
|
102
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
103
|
+
{icon}
|
|
104
|
+
</span>
|
|
105
|
+
) : undefined
|
|
106
|
+
}
|
|
107
|
+
data-variant={variant}
|
|
108
|
+
data-size={size}
|
|
109
|
+
{...(isIconOnly ? { "data-icon-only": "" } : {})}
|
|
110
|
+
{...sanitizedProps}
|
|
111
|
+
>
|
|
112
|
+
<span className={styles.labelText}>{children}</span>
|
|
113
|
+
</MuiButton>
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
Button.displayName = "Button";
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Card> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Card",
|
|
7
7
|
component: Card,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Checkbox> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Checkbox",
|
|
7
7
|
component: Checkbox,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Chip> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Chip",
|
|
7
7
|
component: Chip,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Container> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Container",
|
|
7
7
|
component: Container,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -1,7 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Container layout wrapper.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: As a foundational structural boundary, the Container component DOES NOT use
|
|
5
|
+
* the `RecursicaOverStyled` gatekeeper. Furthermore, unlike other primitive layouts
|
|
6
|
+
* (Stack, Group, Flex), Container explicitly ALLOWS the `sx` prop as an escape hatch
|
|
7
|
+
* for advanced layout positioning.
|
|
8
|
+
*/
|
|
9
|
+
import React, { forwardRef } from "react";
|
|
10
|
+
import {
|
|
11
|
+
Container as MUIContainer,
|
|
12
|
+
type ContainerProps as MUIContainerProps,
|
|
13
|
+
} from "@mui/material";
|
|
14
|
+
import { type RecursicaSpacing } from "../../utils/filterStylingProps";
|
|
2
15
|
|
|
3
|
-
export
|
|
16
|
+
export interface RecursicaContainerProps {
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
size?:
|
|
19
|
+
| "xs"
|
|
20
|
+
| "sm"
|
|
21
|
+
| "md"
|
|
22
|
+
| "lg"
|
|
23
|
+
| "xl"
|
|
24
|
+
| RecursicaSpacing
|
|
25
|
+
| (string & {})
|
|
26
|
+
| number;
|
|
27
|
+
}
|
|
4
28
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
29
|
+
export type ContainerProps = Omit<MUIContainerProps, "maxWidth"> &
|
|
30
|
+
RecursicaContainerProps;
|
|
31
|
+
|
|
32
|
+
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
|
|
33
|
+
function Container({ children, size, ...rest }, ref) {
|
|
34
|
+
const mapSize: Record<string, "xs" | "sm" | "md" | "lg" | "xl"> = {
|
|
35
|
+
"rec-sm": "sm",
|
|
36
|
+
"rec-default": "md",
|
|
37
|
+
"rec-md": "md",
|
|
38
|
+
"rec-lg": "lg",
|
|
39
|
+
"rec-xl": "xl",
|
|
40
|
+
"rec-2xl": "xl",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const resolvedSize =
|
|
44
|
+
typeof size === "string" && mapSize[size] ? mapSize[size] : size;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<MUIContainer
|
|
48
|
+
ref={ref}
|
|
49
|
+
maxWidth={resolvedSize as MUIContainerProps["maxWidth"]}
|
|
50
|
+
{...rest}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</MUIContainer>
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
Container.displayName = "Container";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Container Implementation Notes
|
|
2
|
+
|
|
3
|
+
## `sx` Prop Exemption
|
|
4
|
+
|
|
5
|
+
By design, the `Container` component explicitly allows the `sx` prop to pass through to the underlying MUI `Container`. Unlike standard UI kit components (which use the `RecursicaOverStyled` gatekeeper) or flex layout primitives (which strip `sx` via `OmitSx` and `filterSxProp`), `Container` acts as a structural boundary where advanced, one-off positioning adjustments may be required by the consuming application.
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof DatePicker> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 DatePicker",
|
|
7
7
|
component: DatePicker,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Dropdown> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Dropdown",
|
|
7
7
|
component: Dropdown,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof FileInput> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 FileInput",
|
|
7
7
|
component: FileInput,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof FileUpload> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 FileUpload",
|
|
7
7
|
component: FileUpload,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Flex> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Flex",
|
|
7
7
|
component: Flex,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -1,7 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Flex layout wrapper.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: MUI does not have a native `<Flex>` component (it relies on `<Box display="flex">`
|
|
5
|
+
* or `<Stack>`). To maintain API parity with the mantine-adapter and provide a consistent
|
|
6
|
+
* developer experience, this component wraps MUI's Box and forces `display="flex"`.
|
|
7
|
+
*
|
|
8
|
+
* Like Stack and Group, this is a primitive layout component. It strictly filters out the
|
|
9
|
+
* `sx` prop using `OmitSx` and `filterSxProp` to enforce the use of standard layout scales.
|
|
10
|
+
*/
|
|
11
|
+
import React, { forwardRef } from "react";
|
|
12
|
+
import { Box as MUIBox, type BoxProps as MUIBoxProps } from "@mui/material";
|
|
13
|
+
import {
|
|
14
|
+
type RecursicaSpacing,
|
|
15
|
+
SPACING_MAP,
|
|
16
|
+
type OmitSx,
|
|
17
|
+
filterSxProp,
|
|
18
|
+
} from "../../utils/filterStylingProps";
|
|
2
19
|
|
|
3
|
-
export
|
|
20
|
+
export interface RecursicaFlexProps {
|
|
21
|
+
/**
|
|
22
|
+
* Content to render inside the flex container.
|
|
23
|
+
*/
|
|
24
|
+
children?: React.ReactNode;
|
|
4
25
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The gap between flex items. Accepts standard MUI spacing or Recursica gap tokens
|
|
28
|
+
* (e.g. "rec-md").
|
|
29
|
+
*/
|
|
30
|
+
gap?: string | number | RecursicaSpacing;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The vertical gap between flex items when wrapping. Accepts standard MUI spacing
|
|
34
|
+
* or Recursica gap tokens.
|
|
35
|
+
*/
|
|
36
|
+
rowGap?: string | number | RecursicaSpacing;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The horizontal gap between flex items when wrapping. Accepts standard MUI spacing
|
|
40
|
+
* or Recursica gap tokens.
|
|
41
|
+
*/
|
|
42
|
+
columnGap?: string | number | RecursicaSpacing;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type FlexProps = OmitSx<MUIBoxProps & RecursicaFlexProps>;
|
|
46
|
+
|
|
47
|
+
export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
|
|
48
|
+
{ children, gap = "rec-default", rowGap, columnGap, ...rest },
|
|
49
|
+
ref,
|
|
50
|
+
) {
|
|
51
|
+
const safeProps = filterSxProp(rest as Record<string, unknown>);
|
|
52
|
+
const resolvedGap =
|
|
53
|
+
typeof gap === "string" && gap in SPACING_MAP
|
|
54
|
+
? SPACING_MAP[gap as keyof typeof SPACING_MAP]
|
|
55
|
+
: gap;
|
|
56
|
+
const resolvedRowGap =
|
|
57
|
+
typeof rowGap === "string" && rowGap in SPACING_MAP
|
|
58
|
+
? SPACING_MAP[rowGap as keyof typeof SPACING_MAP]
|
|
59
|
+
: rowGap;
|
|
60
|
+
const resolvedColumnGap =
|
|
61
|
+
typeof columnGap === "string" && columnGap in SPACING_MAP
|
|
62
|
+
? SPACING_MAP[columnGap as keyof typeof SPACING_MAP]
|
|
63
|
+
: columnGap;
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<MUIBox
|
|
67
|
+
ref={ref}
|
|
68
|
+
display="flex"
|
|
69
|
+
{...safeProps}
|
|
70
|
+
gap={resolvedGap}
|
|
71
|
+
rowGap={resolvedRowGap}
|
|
72
|
+
columnGap={resolvedColumnGap}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</MUIBox>
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
Flex.displayName = "Flex";
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof FormControlLayout> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 FormControlLayout",
|
|
7
7
|
component: FormControlLayout,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof FormControlWrapper> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 FormControlWrapper",
|
|
7
7
|
component: FormControlWrapper,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
include: [
|
|
12
|
+
"layer",
|
|
13
|
+
"withLayer",
|
|
14
|
+
"children",
|
|
15
|
+
"component",
|
|
16
|
+
"variant",
|
|
17
|
+
"size",
|
|
18
|
+
"icon",
|
|
19
|
+
"disabled",
|
|
20
|
+
"href",
|
|
21
|
+
"onClick",
|
|
22
|
+
"onChange",
|
|
23
|
+
"value",
|
|
24
|
+
"checked",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
9
28
|
};
|
|
10
29
|
|
|
11
30
|
export default meta;
|