@recursica/mui-adapter 0.34.0 → 0.34.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/index.d.ts +219 -154
  3. package/dist/mui-adapter.cjs +55 -55
  4. package/dist/mui-adapter.cjs.map +1 -1
  5. package/dist/mui-adapter.css +1 -1
  6. package/dist/mui-adapter.js +3383 -3440
  7. package/dist/mui-adapter.js.map +1 -1
  8. package/package.json +9 -4
  9. package/src/OverStyling.tsx +2 -2
  10. package/src/components/Accordion/Accordion.test.tsx +1 -0
  11. package/src/components/AssistiveElement/AssistiveElement.test.tsx +1 -0
  12. package/src/components/Autocomplete/Autocomplete.test.tsx +1 -0
  13. package/src/components/Avatar/Avatar.test.tsx +1 -0
  14. package/src/components/Badge/Badge.test.tsx +1 -0
  15. package/src/components/Box/Box.test.tsx +1 -0
  16. package/src/components/Breadcrumb/Breadcrumb.test.tsx +1 -0
  17. package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +10 -0
  18. package/src/components/Button/Button.module.css +1 -0
  19. package/src/components/Button/Button.styleIsolation.dom.test.tsx +98 -0
  20. package/src/components/Card/Card.test.tsx +1 -0
  21. package/src/components/Checkbox/Checkbox.test.tsx +1 -0
  22. package/src/components/Chip/Chip.test.tsx +1 -0
  23. package/src/components/Container/Container.test.tsx +1 -0
  24. package/src/components/DatePicker/DatePicker.stories.tsx +25 -0
  25. package/src/components/DatePicker/DatePicker.test.tsx +1 -0
  26. package/src/components/Dropdown/Dropdown.test.tsx +1 -0
  27. package/src/components/FileInput/FileInput.test.tsx +1 -0
  28. package/src/components/FileUpload/FileUpload.test.tsx +1 -0
  29. package/src/components/Flex/Flex.test.tsx +1 -0
  30. package/src/components/Flex/Flex.tsx +21 -4
  31. package/src/components/FormControlLayout/FormControlLayout.test.tsx +1 -0
  32. package/src/components/FormControlWrapper/FormControlWrapper.test.tsx +1 -0
  33. package/src/components/Grid/Grid.stories.tsx +38 -62
  34. package/src/components/Grid/Grid.test.tsx +1 -0
  35. package/src/components/Grid/Grid.tsx +59 -144
  36. package/src/components/Grid/IMPLEMENTATION_NOTES.md +11 -11
  37. package/src/components/Grid/USAGE.md +8 -6
  38. package/src/components/Group/Group.test.tsx +1 -0
  39. package/src/components/Group/Group.tsx +24 -2
  40. package/src/components/HoverCard/HoverCard.test.tsx +1 -0
  41. package/src/components/Label/Label.test.tsx +1 -0
  42. package/src/components/Link/Link.test.tsx +1 -0
  43. package/src/components/Loader/Loader.test.tsx +1 -0
  44. package/src/components/Menu/Menu.test.tsx +1 -0
  45. package/src/components/Modal/Modal.module.css +103 -1
  46. package/src/components/Modal/Modal.stories.tsx +28 -2
  47. package/src/components/Modal/Modal.test.tsx +1 -0
  48. package/src/components/NumberInput/NumberInput.test.tsx +1 -0
  49. package/src/components/Pagination/Pagination.test.tsx +1 -0
  50. package/src/components/Panel/Panel.test.tsx +1 -0
  51. package/src/components/Popover/Popover.test.tsx +1 -0
  52. package/src/components/Radio/Radio.test.tsx +1 -0
  53. package/src/components/ReadOnlyField/ReadOnlyField.test.tsx +1 -0
  54. package/src/components/SegmentedControl/SegmentedControl.test.tsx +1 -0
  55. package/src/components/Slider/Slider.test.tsx +1 -0
  56. package/src/components/Stack/Stack.stories.tsx +9 -9
  57. package/src/components/Stack/Stack.test.tsx +1 -0
  58. package/src/components/Stack/Stack.tsx +15 -14
  59. package/src/components/Stack/USAGE.md +1 -1
  60. package/src/components/Stepper/Stepper.test.tsx +1 -0
  61. package/src/components/Switch/Switch.stories.tsx +1 -1
  62. package/src/components/Switch/Switch.test.tsx +1 -0
  63. package/src/components/Table/Table.test.tsx +1 -0
  64. package/src/components/Tabs/Tabs.test.tsx +1 -0
  65. package/src/components/Text/Text.stories.tsx +3 -16
  66. package/src/components/Text/Text.test.tsx +1 -0
  67. package/src/components/TextArea/TextArea.test.tsx +1 -0
  68. package/src/components/TextField/TextField.test.tsx +1 -0
  69. package/src/components/TimePicker/TimePicker.test.tsx +1 -0
  70. package/src/components/Timeline/Timeline.test.tsx +1 -0
  71. package/src/components/Title/Title.stories.tsx +3 -16
  72. package/src/components/Title/Title.test.tsx +1 -0
  73. package/src/components/Toast/Toast.test.tsx +1 -0
  74. package/src/components/Tooltip/Tooltip.test.tsx +1 -0
  75. package/src/components/TransferList/TransferList.test.tsx +1 -0
  76. package/src/components/Tree/Tree.test.tsx +1 -0
  77. package/src/components/Typography/Typography.test.tsx +1 -0
  78. package/src/utils/filterStylingProps.test.ts +85 -0
@@ -19,12 +19,12 @@ const meta: Meta<StackStoryProps> = {
19
19
  },
20
20
  },
21
21
  args: {
22
- gap: "rec-default",
23
- align: "stretch",
24
- justify: "flex-start",
22
+ spacing: "rec-default",
23
+ alignItems: "stretch",
24
+ justifyContent: "flex-start",
25
25
  },
26
26
  argTypes: {
27
- gap: {
27
+ spacing: {
28
28
  control: "select",
29
29
  options: [
30
30
  "rec-none",
@@ -40,14 +40,14 @@ const meta: Meta<StackStoryProps> = {
40
40
  "lg",
41
41
  "xl",
42
42
  ],
43
- description: "Gap between elements",
43
+ description: "Space between elements",
44
44
  },
45
- align: {
45
+ alignItems: {
46
46
  control: "select",
47
47
  options: ["flex-start", "center", "flex-end", "stretch"],
48
48
  description: "Align-items property",
49
49
  },
50
- justify: {
50
+ justifyContent: {
51
51
  control: "select",
52
52
  options: [
53
53
  "flex-start",
@@ -81,7 +81,7 @@ export const Default: Story = {
81
81
 
82
82
  export const StaticGapSmall: Story = {
83
83
  args: {
84
- gap: "rec-sm",
84
+ spacing: "rec-sm",
85
85
  },
86
86
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
87
87
  render: ({ withLayer, layer, ...args }: any) => (
@@ -95,7 +95,7 @@ export const StaticGapSmall: Story = {
95
95
 
96
96
  export const StaticGapLarge: Story = {
97
97
  args: {
98
- gap: "rec-xl",
98
+ spacing: "rec-xl",
99
99
  },
100
100
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
101
101
  render: ({ withLayer, layer, ...args }: any) => (
@@ -0,0 +1 @@
1
+ // Placeholder for future Stack component tests. Add tests here if/when needed.
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Stack layout wrapper.
3
+ *
4
+ * MUI has a native `Stack`, so this simply passes through its own props (`direction`,
5
+ * `spacing`, `alignItems`, `justifyContent`, etc.) with no Recursica renaming — only
6
+ * `spacing` gains `rec-*` token support via `WithRecursicaSpacing`.
7
+ */
1
8
  import { forwardRef } from "react";
2
9
  import {
3
10
  Stack as MUIStack,
@@ -10,29 +17,23 @@ import {
10
17
  type WithRecursicaSpacing,
11
18
  } from "../../utils/filterStylingProps";
12
19
 
13
- import { type RecursicaStackProps } from "@recursica/adapter-common";
14
-
15
- export type StackProps = WithRecursicaSpacing<
16
- OmitSx<Omit<MUIStackProps, "spacing"> & RecursicaStackProps>
17
- >;
20
+ export type StackProps = WithRecursicaSpacing<OmitSx<MUIStackProps>>;
18
21
 
19
22
  export const Stack = forwardRef<HTMLDivElement, StackProps>(function Stack(
20
- { children, gap = "rec-default", align, justify, ...rest },
23
+ { children, spacing = "rec-default", ...rest },
21
24
  ref,
22
25
  ) {
23
26
  const safeProps = filterSxProp(rest as Record<string, unknown>);
24
- const resolvedGap =
25
- typeof gap === "string" && gap in SPACING_MAP
26
- ? SPACING_MAP[gap as keyof typeof SPACING_MAP]
27
- : gap;
27
+ const resolvedSpacing =
28
+ typeof spacing === "string" && spacing in SPACING_MAP
29
+ ? SPACING_MAP[spacing as keyof typeof SPACING_MAP]
30
+ : spacing;
28
31
 
29
32
  return (
30
33
  <MUIStack
31
34
  ref={ref}
32
- {...safeProps}
33
- spacing={resolvedGap}
34
- alignItems={align}
35
- justifyContent={justify}
35
+ {...(safeProps as unknown as MUIStackProps)}
36
+ spacing={resolvedSpacing}
36
37
  >
37
38
  {children}
38
39
  </MUIStack>
@@ -20,7 +20,7 @@ import { Stack } from "@recursica/mui-adapter";
20
20
 
21
21
  export default function Demo() {
22
22
  return (
23
- <Stack gap="md" align="stretch">
23
+ <Stack spacing="md" alignItems="stretch">
24
24
  <Text>Item 1</Text>
25
25
  <Text>Item 2</Text>
26
26
  </Stack>
@@ -0,0 +1 @@
1
+ // Placeholder for future Stepper component tests. Add tests here if/when needed.
@@ -77,7 +77,7 @@ export const SideBySideLayout: Story = {
77
77
  export const StaticVariations: Story = {
78
78
  args: {},
79
79
  render: () => (
80
- <Stack gap="xl">
80
+ <Stack spacing="xl">
81
81
  <Switch label="Default Unchecked State" />
82
82
  <Switch label="Checked State" defaultChecked />
83
83
  <Switch label="Disabled Unchecked" disabled />
@@ -0,0 +1 @@
1
+ // Placeholder for future Switch component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Table component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Tabs component tests. Add tests here if/when needed.
@@ -1,6 +1,5 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { Text } from "./Text";
3
- import { Layer } from "@recursica/adapter-common";
4
3
 
5
4
  const meta: Meta<typeof Text> = {
6
5
  title: "UI-Kit/Text",
@@ -46,25 +45,13 @@ export const Default: Story = {
46
45
  children:
47
46
  "This is standard body typography controlled by the central UI-kit boundaries exclusively.",
48
47
  },
49
- render: ({ ...args }) => (
50
- <Layer layer={0} style={{ padding: "48px" }}>
51
- <Text {...args} />
52
- </Layer>
53
- ),
48
+ render: ({ ...args }) => <Text {...args} />,
54
49
  };
55
50
 
56
51
  export const StaticVariations: Story = {
57
52
  args: {},
58
53
  render: () => (
59
- <Layer
60
- layer={0}
61
- style={{
62
- padding: "48px",
63
- display: "flex",
64
- flexDirection: "column",
65
- gap: "16px",
66
- }}
67
- >
54
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
68
55
  <Text variant="body">
69
56
  Body (Base paragraph and generic information flow)
70
57
  </Text>
@@ -83,6 +70,6 @@ export const StaticVariations: Story = {
83
70
  <Text variant="subtitle-small">
84
71
  Subtitle Small (Section anchors deep in hierarchy)
85
72
  </Text>
86
- </Layer>
73
+ </div>
87
74
  ),
88
75
  };
@@ -0,0 +1 @@
1
+ // Placeholder for future Text component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future TextArea component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future TextField component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future TimePicker component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Timeline component tests. Add tests here if/when needed.
@@ -1,6 +1,5 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { Title } from "./Title";
3
- import { Layer } from "@recursica/adapter-common";
4
3
 
5
4
  const meta: Meta<typeof Title> = {
6
5
  title: "UI-Kit/Title",
@@ -33,31 +32,19 @@ export const Default: Story = {
33
32
  order: 1,
34
33
  children: "Semantic H1 Document Boundary",
35
34
  },
36
- render: ({ ...args }) => (
37
- <Layer layer={0} style={{ padding: "48px" }}>
38
- <Title {...args} />
39
- </Layer>
40
- ),
35
+ render: ({ ...args }) => <Title {...args} />,
41
36
  };
42
37
 
43
38
  export const StaticVariations: Story = {
44
39
  args: {},
45
40
  render: () => (
46
- <Layer
47
- layer={0}
48
- style={{
49
- padding: "48px",
50
- display: "flex",
51
- flexDirection: "column",
52
- gap: "24px",
53
- }}
54
- >
41
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
55
42
  <Title order={1}>H1 Title</Title>
56
43
  <Title order={2}>H2 Title</Title>
57
44
  <Title order={3}>H3 Title</Title>
58
45
  <Title order={4}>H4 Title</Title>
59
46
  <Title order={5}>H5 Title</Title>
60
47
  <Title order={6}>H6 Title</Title>
61
- </Layer>
48
+ </div>
62
49
  ),
63
50
  };
@@ -0,0 +1 @@
1
+ // Placeholder for future Title component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Toast component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Tooltip component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future TransferList component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Tree component tests. Add tests here if/when needed.
@@ -0,0 +1 @@
1
+ // Placeholder for future Typography component tests. Add tests here if/when needed.
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ BLOCKED_STYLING_KEYS,
4
+ SPACING_MAP,
5
+ filterStylingProps,
6
+ filterSxProp,
7
+ } from "./filterStylingProps";
8
+
9
+ describe("filterStylingProps", () => {
10
+ it("strips every blocked styling key by default", () => {
11
+ const props = Object.fromEntries(
12
+ BLOCKED_STYLING_KEYS.map((key) => [key, "should-be-removed"]),
13
+ );
14
+
15
+ const sanitized = filterStylingProps(props);
16
+
17
+ for (const key of BLOCKED_STYLING_KEYS) {
18
+ expect(sanitized).not.toHaveProperty(key);
19
+ }
20
+ });
21
+
22
+ it("keeps props that aren't blocked styling keys", () => {
23
+ const sanitized = filterStylingProps({
24
+ disabled: true,
25
+ "aria-label": "Submit",
26
+ });
27
+
28
+ expect(sanitized).toEqual({ disabled: true, "aria-label": "Submit" });
29
+ });
30
+
31
+ it("keeps layout props (e.g. margin) untouched when not a rec- token", () => {
32
+ const sanitized = filterStylingProps({ m: "16px" });
33
+
34
+ expect(sanitized).toEqual({ m: "16px" });
35
+ });
36
+
37
+ it("maps rec- spacing tokens on layout props to their CSS variable", () => {
38
+ const sanitized = filterStylingProps({ m: "rec-lg", gap: "rec-sm" });
39
+
40
+ expect(sanitized).toEqual({
41
+ m: SPACING_MAP["rec-lg"],
42
+ gap: SPACING_MAP["rec-sm"],
43
+ });
44
+ });
45
+
46
+ it("does not map rec- tokens on props that aren't layout props", () => {
47
+ const sanitized = filterStylingProps({ "data-testid": "rec-lg" });
48
+
49
+ expect(sanitized).toEqual({ "data-testid": "rec-lg" });
50
+ });
51
+
52
+ it("leaves an unrecognized rec- value alone", () => {
53
+ const sanitized = filterStylingProps({ m: "rec-not-a-real-token" });
54
+
55
+ expect(sanitized).toEqual({ m: "rec-not-a-real-token" });
56
+ });
57
+
58
+ it("bypasses all filtering when overStyled is true", () => {
59
+ const props = { className: "custom", sx: { color: "red" }, m: "rec-lg" };
60
+
61
+ expect(filterStylingProps(props, true)).toEqual(props);
62
+ });
63
+
64
+ it("does not mutate the input props object", () => {
65
+ const props = { className: "custom", m: "rec-lg" };
66
+
67
+ filterStylingProps(props);
68
+
69
+ expect(props).toEqual({ className: "custom", m: "rec-lg" });
70
+ });
71
+ });
72
+
73
+ describe("filterSxProp", () => {
74
+ it("removes only the sx prop", () => {
75
+ const sanitized = filterSxProp({ sx: { color: "red" }, disabled: true });
76
+
77
+ expect(sanitized).toEqual({ disabled: true });
78
+ });
79
+
80
+ it("is a no-op when sx isn't present", () => {
81
+ const props = { disabled: true };
82
+
83
+ expect(filterSxProp(props)).toEqual(props);
84
+ });
85
+ });