@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
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof AssistiveElement> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 AssistiveElement",
|
|
7
7
|
component: AssistiveElement,
|
|
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 Avatar> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Avatar",
|
|
7
7
|
component: Avatar,
|
|
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 Badge> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Badge",
|
|
7
7
|
component: Badge,
|
|
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;
|
|
@@ -12,6 +12,23 @@ const meta: Meta<typeof Box> = {
|
|
|
12
12
|
"The `Box` component is the foundational layout primitive. It accepts all standard MUI layout properties (like `m`, `mt`, `p`, `px`, etc.), but natively intercepts **Recursica Spacing Tokens** (e.g., `rec-none`, `rec-sm`, `rec-default`, `rec-md`, `rec-lg`, `rec-xl`, `rec-2xl`). This allows developers to use Recursica's strict design tokens seamlessly alongside standard MUI spacing.",
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
|
+
controls: {
|
|
16
|
+
include: [
|
|
17
|
+
"layer",
|
|
18
|
+
"withLayer",
|
|
19
|
+
"children",
|
|
20
|
+
"component",
|
|
21
|
+
"variant",
|
|
22
|
+
"size",
|
|
23
|
+
"icon",
|
|
24
|
+
"disabled",
|
|
25
|
+
"href",
|
|
26
|
+
"onClick",
|
|
27
|
+
"onChange",
|
|
28
|
+
"value",
|
|
29
|
+
"checked",
|
|
30
|
+
],
|
|
31
|
+
},
|
|
15
32
|
},
|
|
16
33
|
};
|
|
17
34
|
|
|
@@ -24,11 +41,7 @@ export const Default: Story = {
|
|
|
24
41
|
m: "20px",
|
|
25
42
|
},
|
|
26
43
|
render: (args) => (
|
|
27
|
-
<Box
|
|
28
|
-
{...args}
|
|
29
|
-
style={{ border: "1px solid gray", padding: "10px" }}
|
|
30
|
-
overStyled={true}
|
|
31
|
-
/>
|
|
44
|
+
<Box {...args} style={{ border: "1px solid gray", padding: "10px" }} />
|
|
32
45
|
),
|
|
33
46
|
};
|
|
34
47
|
|
|
@@ -40,11 +53,7 @@ export const WithRecursicaTokens: Story = {
|
|
|
40
53
|
},
|
|
41
54
|
render: (args) => (
|
|
42
55
|
<div style={{ border: "1px dashed #ccc", display: "inline-block" }}>
|
|
43
|
-
<Box
|
|
44
|
-
{...args}
|
|
45
|
-
style={{ backgroundColor: "rgba(0,0,0,0.1)" }}
|
|
46
|
-
overStyled={true}
|
|
47
|
-
/>
|
|
56
|
+
<Box {...args} style={{ backgroundColor: "rgba(0,0,0,0.1)" }} />
|
|
48
57
|
</div>
|
|
49
58
|
),
|
|
50
59
|
};
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Box layout wrapper.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: Box is the lowest-level primitive layout component. It explicitly ALLOWS
|
|
5
|
+
* the `sx` prop as an escape hatch. It does not use the strict RecursicaOverStyled gatekeeper
|
|
6
|
+
* or any style stripping utilities.
|
|
7
|
+
*/
|
|
1
8
|
import React, { forwardRef } from "react";
|
|
2
9
|
import { Box as MUIBox, type BoxProps as MUIBoxProps } from "@mui/material";
|
|
3
|
-
import {
|
|
4
|
-
filterStylingProps,
|
|
5
|
-
type RecursicaOverStyled,
|
|
6
|
-
} from "../../utils/filterStylingProps";
|
|
7
10
|
|
|
8
|
-
export type BoxProps<C extends React.ElementType = "div"> =
|
|
9
|
-
|
|
11
|
+
export type BoxProps<C extends React.ElementType = "div"> = MUIBoxProps<
|
|
12
|
+
C,
|
|
13
|
+
{ component?: C }
|
|
10
14
|
>;
|
|
11
15
|
|
|
12
16
|
export const Box = forwardRef(function Box<C extends React.ElementType = "div">(
|
|
13
17
|
props: BoxProps<C>,
|
|
14
18
|
ref: React.Ref<Element>,
|
|
15
19
|
) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const sanitizedProps = filterStylingProps(
|
|
19
|
-
rest as Record<string, unknown>,
|
|
20
|
-
overStyled,
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
return <MUIBox ref={ref} {...sanitizedProps} />;
|
|
20
|
+
return <MUIBox ref={ref} {...props} />;
|
|
24
21
|
}) as <C extends React.ElementType = "div">(
|
|
25
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
23
|
props: BoxProps<C> & { ref?: React.ForwardedRef<any> },
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Box Implementation Notes
|
|
2
|
+
|
|
3
|
+
## `sx` Prop Exemption
|
|
4
|
+
|
|
5
|
+
By design, the `Box` component is the most permissive primitive in the UI kit. It explicitly allows the `sx` prop to pass through to the underlying MUI `Box`. It does not use any strict styling gatekeepers (`RecursicaOverStyled`, `filterSxProp`). It is intended to be used as a final escape hatch when the standard layout primitives or design system tokens cannot fulfill a unique layout requirement.
|
|
@@ -6,6 +6,25 @@ const meta: Meta<typeof Breadcrumb> = {
|
|
|
6
6
|
title: "UI-Kit/🚧 Breadcrumb",
|
|
7
7
|
component: Breadcrumb,
|
|
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;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Button Component Implementation Notes
|
|
2
|
+
|
|
3
|
+
**Implementation Philosophy:**
|
|
4
|
+
The Button component serves as a foundational building block in Recursica. This implementation wraps the `@mui/material/Button` component but **disables its native visual heuristics entirely.**
|
|
5
|
+
|
|
6
|
+
We explicitly pass `disableRipple` and `disableElevation` to block MUI's dynamic behaviors. Furthermore, we intentionally **do not** map our `variant` or `size` properties to MUI's native `variant` or `size` props because doing so would trigger MUI's internal CSS engines to inject styles that clash with our strict design tokens.
|
|
7
|
+
|
|
8
|
+
**Styling Strategy:**
|
|
9
|
+
|
|
10
|
+
- We utilize `filterStylingProps` to prevent rogue injections of `sx`, `style`, or `className` properties that would violate the design system.
|
|
11
|
+
- All styling is controlled directly via CSS Modules, mapping DOM attributes like `data-variant` and `data-size` to pure CSS selectors.
|
|
12
|
+
- Hover states are managed with a standard `::after` pseudo-element overlay hack rather than relying on native hover psuedo-selectors modifying background-color directly. This allows a clean `opacity` overlay based on the provided design tokens, which guarantees identical visual feedback behavior across all underlying themes without overriding background hues manually.
|
|
13
|
+
- The polymorphic `component` prop natively supported by MUI is safely forwarded to allow correct semantics (e.g. rendering as an `<a>` tag or using a router `Link`).
|
|
14
|
+
|
|
15
|
+
**Accessibility:**
|
|
16
|
+
|
|
17
|
+
- We inject a development-time warning explicitly requiring `aria-label` when the component detects an icon-only configuration.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/* Baseline and Reset */
|
|
2
|
+
.root {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
margin: 0;
|
|
5
|
+
border-style: solid;
|
|
6
|
+
overflow: hidden; /* Truncation bounding box */
|
|
7
|
+
position: relative;
|
|
8
|
+
transition: all 0.2s ease;
|
|
9
|
+
width: fit-content; /* Prevent stretching in flex columns */
|
|
10
|
+
|
|
11
|
+
/* Shared Defaults */
|
|
12
|
+
font-family: var(
|
|
13
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-family
|
|
14
|
+
);
|
|
15
|
+
font-size: var(
|
|
16
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-size
|
|
17
|
+
);
|
|
18
|
+
font-style: var(
|
|
19
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-style
|
|
20
|
+
);
|
|
21
|
+
font-weight: var(
|
|
22
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-weight
|
|
23
|
+
);
|
|
24
|
+
letter-spacing: var(
|
|
25
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_letter-spacing
|
|
26
|
+
);
|
|
27
|
+
line-height: var(
|
|
28
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_line-height
|
|
29
|
+
);
|
|
30
|
+
text-decoration: var(
|
|
31
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-decoration
|
|
32
|
+
);
|
|
33
|
+
text-transform: var(
|
|
34
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-transform
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Reset MUI native properties */
|
|
39
|
+
.root {
|
|
40
|
+
text-transform: none;
|
|
41
|
+
min-width: 0;
|
|
42
|
+
color: inherit;
|
|
43
|
+
background-color: transparent;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Internal layout logic for Truncation */
|
|
47
|
+
.root > * {
|
|
48
|
+
min-width: 0;
|
|
49
|
+
position: relative;
|
|
50
|
+
z-index: 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.label {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
min-width: 0;
|
|
57
|
+
flex: 1 1 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.labelText {
|
|
61
|
+
display: block;
|
|
62
|
+
min-width: 0;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
font-size: inherit;
|
|
67
|
+
line-height: inherit;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ==== SIZES ==== */
|
|
71
|
+
.root[data-size="default"] {
|
|
72
|
+
border-radius: var(
|
|
73
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_border-radius
|
|
74
|
+
);
|
|
75
|
+
height: var(
|
|
76
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_height
|
|
77
|
+
);
|
|
78
|
+
min-width: var(
|
|
79
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_min-width
|
|
80
|
+
);
|
|
81
|
+
padding: 0
|
|
82
|
+
var(
|
|
83
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_horizontal-padding
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
.root[data-size="default"] .labelText {
|
|
87
|
+
max-width: var(
|
|
88
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_max-label-width
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
.root[data-size="small"] {
|
|
92
|
+
border-radius: var(
|
|
93
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_border-radius
|
|
94
|
+
);
|
|
95
|
+
height: var(
|
|
96
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_height
|
|
97
|
+
);
|
|
98
|
+
min-width: var(
|
|
99
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_min-width
|
|
100
|
+
);
|
|
101
|
+
padding: 0
|
|
102
|
+
var(
|
|
103
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_horizontal-padding
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
/* Override specific typography for small */
|
|
107
|
+
font-family: var(
|
|
108
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_text_font-family,
|
|
109
|
+
var(
|
|
110
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-family
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
font-size: var(
|
|
114
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_text_font-size,
|
|
115
|
+
var(
|
|
116
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-size
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
font-weight: var(
|
|
120
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_text_font-weight,
|
|
121
|
+
var(
|
|
122
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-weight
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
.root[data-size="small"] .labelText {
|
|
127
|
+
max-width: var(
|
|
128
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_max-label-width
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Icon Resets */
|
|
133
|
+
.iconWrapper {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
justify-content: center;
|
|
137
|
+
flex-shrink: 0;
|
|
138
|
+
}
|
|
139
|
+
.iconWrapper > * {
|
|
140
|
+
width: 100%;
|
|
141
|
+
height: 100%;
|
|
142
|
+
object-fit: contain;
|
|
143
|
+
}
|
|
144
|
+
.root[data-size="default"] .iconWrapper {
|
|
145
|
+
width: var(
|
|
146
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_icon
|
|
147
|
+
);
|
|
148
|
+
height: var(
|
|
149
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_icon
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
.root[data-size="small"] .iconWrapper {
|
|
153
|
+
width: var(
|
|
154
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_icon
|
|
155
|
+
);
|
|
156
|
+
height: var(
|
|
157
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_icon
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* MUI uses .MuiButton-startIcon and .MuiButton-endIcon */
|
|
162
|
+
.root[data-size="default"] .MuiButton-startIcon,
|
|
163
|
+
.root[data-size="default"] .MuiButton-endIcon {
|
|
164
|
+
margin-left: 0;
|
|
165
|
+
margin-right: var(
|
|
166
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_icon-text-gap
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
.root[data-size="small"] .MuiButton-startIcon,
|
|
170
|
+
.root[data-size="small"] .MuiButton-endIcon {
|
|
171
|
+
margin-left: 0;
|
|
172
|
+
margin-right: var(
|
|
173
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_icon-text-gap
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Icon-only logic overrides */
|
|
178
|
+
.root[data-icon-only] .MuiButton-startIcon,
|
|
179
|
+
.root[data-icon-only] .MuiButton-endIcon {
|
|
180
|
+
margin-right: 0;
|
|
181
|
+
margin-left: 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Disabled */
|
|
185
|
+
.root[data-size="default"]:disabled,
|
|
186
|
+
.root[data-size="default"]:global(.Mui-disabled) {
|
|
187
|
+
opacity: var(
|
|
188
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_disabled-opacity
|
|
189
|
+
);
|
|
190
|
+
cursor: not-allowed;
|
|
191
|
+
}
|
|
192
|
+
.root[data-size="small"]:disabled,
|
|
193
|
+
.root[data-size="small"]:global(.Mui-disabled) {
|
|
194
|
+
opacity: var(
|
|
195
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_disabled-opacity
|
|
196
|
+
);
|
|
197
|
+
cursor: not-allowed;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Global Hover Hack Overlay */
|
|
201
|
+
.root::after {
|
|
202
|
+
content: "";
|
|
203
|
+
position: absolute;
|
|
204
|
+
inset: 0;
|
|
205
|
+
border-radius: inherit;
|
|
206
|
+
z-index: 0;
|
|
207
|
+
pointer-events: none;
|
|
208
|
+
transition: opacity 150ms ease;
|
|
209
|
+
opacity: 0;
|
|
210
|
+
}
|
|
211
|
+
.root[data-size="default"]::after {
|
|
212
|
+
background-color: var(
|
|
213
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_hover-color
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
.root[data-size="small"]::after {
|
|
217
|
+
background-color: var(
|
|
218
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_hover-color
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
.root:hover:not(:disabled):not(:global(.Mui-disabled))::after {
|
|
222
|
+
opacity: var(
|
|
223
|
+
--recursica_ui-kit_components_button_variants_sizes_default_properties_hover-opacity,
|
|
224
|
+
0.1
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* ==== VARIANTS ==== */
|
|
229
|
+
|
|
230
|
+
/* SOLID */
|
|
231
|
+
.root[data-variant="solid"] {
|
|
232
|
+
border-width: var(
|
|
233
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_border-size
|
|
234
|
+
);
|
|
235
|
+
box-shadow: var(
|
|
236
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_elevation
|
|
237
|
+
);
|
|
238
|
+
background-color: var(
|
|
239
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_colors_background
|
|
240
|
+
);
|
|
241
|
+
border-color: var(
|
|
242
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_colors_border-color
|
|
243
|
+
);
|
|
244
|
+
color: var(
|
|
245
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_colors_text
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
.root[data-variant="solid"]:hover:not(:disabled):not(:global(.Mui-disabled)) {
|
|
249
|
+
color: var(
|
|
250
|
+
--recursica_ui-kit_components_button_variants_styles_solid_properties_colors_text-hover
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* OUTLINE */
|
|
255
|
+
.root[data-variant="outline"] {
|
|
256
|
+
border-width: var(
|
|
257
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_border-size
|
|
258
|
+
);
|
|
259
|
+
box-shadow: var(
|
|
260
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_elevation
|
|
261
|
+
);
|
|
262
|
+
background-color: var(
|
|
263
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_colors_background
|
|
264
|
+
);
|
|
265
|
+
border-color: var(
|
|
266
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_colors_border-color
|
|
267
|
+
);
|
|
268
|
+
color: var(
|
|
269
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_colors_text
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
.root[data-variant="outline"]:hover:not(:disabled):not(:global(.Mui-disabled)) {
|
|
273
|
+
color: var(
|
|
274
|
+
--recursica_ui-kit_components_button_variants_styles_outline_properties_colors_text-hover
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* TEXT */
|
|
279
|
+
.root[data-variant="text"] {
|
|
280
|
+
border-width: var(
|
|
281
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_border-size
|
|
282
|
+
);
|
|
283
|
+
box-shadow: var(
|
|
284
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_elevation
|
|
285
|
+
);
|
|
286
|
+
background-color: var(
|
|
287
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_background
|
|
288
|
+
);
|
|
289
|
+
border-color: var(
|
|
290
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_border-color
|
|
291
|
+
);
|
|
292
|
+
color: var(
|
|
293
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_text
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
.root[data-variant="text"]:hover:not(:disabled):not(:global(.Mui-disabled)) {
|
|
297
|
+
color: var(
|
|
298
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_text-hover
|
|
299
|
+
);
|
|
300
|
+
}
|
|
@@ -1,16 +1,147 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
3
|
import { Button } from "./Button";
|
|
3
|
-
import {
|
|
4
|
+
import { Layer } from "@recursica/adapter-common";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
type ButtonStoryProps = React.ComponentProps<typeof Button>;
|
|
7
|
+
|
|
8
|
+
const meta: Meta<ButtonStoryProps> = {
|
|
9
|
+
title: "UI-Kit/Button",
|
|
7
10
|
component: Button,
|
|
8
11
|
tags: ["autodocs"],
|
|
12
|
+
argTypes: {
|
|
13
|
+
variant: {
|
|
14
|
+
control: "select",
|
|
15
|
+
options: ["solid", "outline", "text"],
|
|
16
|
+
description: "The visual variant of the button",
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
control: "radio",
|
|
20
|
+
options: ["default", "small"],
|
|
21
|
+
description: "The size of the button",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
parameters: {
|
|
25
|
+
controls: {
|
|
26
|
+
include: [
|
|
27
|
+
"layer",
|
|
28
|
+
"withLayer",
|
|
29
|
+
"variant",
|
|
30
|
+
"size",
|
|
31
|
+
"children",
|
|
32
|
+
"component",
|
|
33
|
+
"icon",
|
|
34
|
+
"disabled",
|
|
35
|
+
"href",
|
|
36
|
+
"onClick",
|
|
37
|
+
"onChange",
|
|
38
|
+
"value",
|
|
39
|
+
"checked",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
9
43
|
};
|
|
10
44
|
|
|
11
45
|
export default meta;
|
|
12
|
-
|
|
46
|
+
|
|
47
|
+
type Story = StoryObj<ButtonStoryProps>;
|
|
13
48
|
|
|
14
49
|
export const Default: Story = {
|
|
15
|
-
|
|
50
|
+
args: {
|
|
51
|
+
children: "Explore Button",
|
|
52
|
+
variant: "solid",
|
|
53
|
+
size: "default",
|
|
54
|
+
disabled: false,
|
|
55
|
+
},
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
57
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
58
|
+
return <Button {...args} />;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const SolidDefault: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
children: "Solid Default",
|
|
65
|
+
variant: "solid",
|
|
66
|
+
size: "default",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const OutlineSmall: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
children: "Outline Small",
|
|
73
|
+
variant: "outline",
|
|
74
|
+
size: "small",
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const TextWithIcon: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
children: "Text With Icon",
|
|
81
|
+
variant: "text",
|
|
82
|
+
size: "default",
|
|
83
|
+
icon: (
|
|
84
|
+
<svg
|
|
85
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
86
|
+
width="24"
|
|
87
|
+
height="24"
|
|
88
|
+
viewBox="0 0 24 24"
|
|
89
|
+
fill="none"
|
|
90
|
+
stroke="currentColor"
|
|
91
|
+
strokeWidth="2"
|
|
92
|
+
strokeLinecap="round"
|
|
93
|
+
strokeLinejoin="round"
|
|
94
|
+
>
|
|
95
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
96
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
97
|
+
</svg>
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const LayerOneSolid: Story = {
|
|
103
|
+
args: {
|
|
104
|
+
children: "Layer 1 Solid",
|
|
105
|
+
variant: "solid",
|
|
106
|
+
size: "default",
|
|
107
|
+
},
|
|
108
|
+
render: (args: ButtonStoryProps) => (
|
|
109
|
+
<Layer layer={1} style={{ padding: "24px" }}>
|
|
110
|
+
<Button {...args} />
|
|
111
|
+
</Layer>
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const DisabledSolid: Story = {
|
|
116
|
+
args: {
|
|
117
|
+
children: "Disabled Solid",
|
|
118
|
+
variant: "solid",
|
|
119
|
+
size: "default",
|
|
120
|
+
disabled: true,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const PolymorphicAsLink: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
children: "Button as Link",
|
|
127
|
+
variant: "solid",
|
|
128
|
+
size: "default",
|
|
129
|
+
component: "a",
|
|
130
|
+
href: "https://example.com",
|
|
131
|
+
target: "_blank",
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const TruncatedLabel: Story = {
|
|
136
|
+
args: {
|
|
137
|
+
children:
|
|
138
|
+
"This is an exceptionally long button label designed to demonstrate how the component handles text overflow by applying an ellipsis rather than breaking the layout or wrapping to multiple lines.",
|
|
139
|
+
variant: "solid",
|
|
140
|
+
size: "default",
|
|
141
|
+
},
|
|
142
|
+
render: (args: ButtonStoryProps) => (
|
|
143
|
+
<div style={{ maxWidth: "250px" }}>
|
|
144
|
+
<Button {...args} />
|
|
145
|
+
</div>
|
|
146
|
+
),
|
|
16
147
|
};
|