@recursica/mui-adapter 0.33.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 +11 -0
- package/dist/index.d.ts +6 -0
- package/dist/mui-adapter.cjs +1 -1
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.js +18 -7
- package/dist/mui-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Menu/IMPLEMENTATION_NOTES.md +1 -0
- package/src/components/Menu/Menu.stories.tsx +37 -0
- package/src/components/Menu/Menu.tsx +25 -5
- package/src/components/Menu/USAGE.md +6 -0
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/borderux/recursica.git",
|
|
14
14
|
"directory": "packages/mui-adapter"
|
|
15
15
|
},
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.34.0",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"vitest": "^3.2.4"
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@recursica/adapter-common": "^0.
|
|
105
|
+
"@recursica/adapter-common": "^0.25.0",
|
|
106
106
|
"@recursica/official-release": "^2.8.0",
|
|
107
107
|
"dayjs": "^1.11.21"
|
|
108
108
|
},
|
|
@@ -2,3 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
- **Compositional API Dropped:** Mantine uses `<Menu.Target>`, `<Menu.Dropdown>`, `<Menu.Item>`, etc., and manages state natively via React context within `<Menu>`. MUI's API is fully monolithic.
|
|
4
4
|
- **Monolithic API Adopted:** Following architectural review, we have abandoned the fabricated context wrappers for `mui-adapter`. We now natively export `Menu`, `MenuItem`, and `MenuDivider` wrapping their `@mui/material` counterparts. Developers are expected to manage `anchorEl` state themselves, just like native MUI. Storybook tests have been updated to simulate this open state so visual regressions still cover the dropdown menu visually.
|
|
5
|
+
- **`maxHeight` Override:** `<Menu maxHeight={...}>` overrides the token-driven dropdown max-height with an explicit pixel (or other CSS length) value — the one deliberate exception to "no inline design tokens in TSX" (see `COMPONENT_DEV_GUIDE.md`). Implemented by merging `maxHeight` into `slotProps.paper.style`, alongside any caller-supplied `slotProps`, rather than a CSS module change; the CSS module's token-driven `max-height` stays untouched when the prop isn't passed.
|
|
@@ -300,6 +300,43 @@ export const WithSubmenus: Story = {
|
|
|
300
300
|
},
|
|
301
301
|
};
|
|
302
302
|
|
|
303
|
+
export const WithMaxHeight: Story = {
|
|
304
|
+
render: (args) => (
|
|
305
|
+
<InteractiveMenu {...args}>
|
|
306
|
+
<MenuItem>
|
|
307
|
+
<SettingsIcon style={{ marginRight: 8 }} /> Settings
|
|
308
|
+
</MenuItem>
|
|
309
|
+
<MenuItem>
|
|
310
|
+
<MessageIcon style={{ marginRight: 8 }} /> Messages
|
|
311
|
+
</MenuItem>
|
|
312
|
+
<MenuItem>
|
|
313
|
+
<ImageIcon style={{ marginRight: 8 }} /> Gallery
|
|
314
|
+
</MenuItem>
|
|
315
|
+
<MenuItem>
|
|
316
|
+
<SearchIcon style={{ marginRight: 8 }} /> Search
|
|
317
|
+
</MenuItem>
|
|
318
|
+
<MenuItem>
|
|
319
|
+
<ArrowsIcon style={{ marginRight: 8 }} /> Transfer my data
|
|
320
|
+
</MenuItem>
|
|
321
|
+
<MenuItem>
|
|
322
|
+
<TrashIcon style={{ marginRight: 8 }} /> Delete my account
|
|
323
|
+
</MenuItem>
|
|
324
|
+
</InteractiveMenu>
|
|
325
|
+
),
|
|
326
|
+
args: {
|
|
327
|
+
opened: true,
|
|
328
|
+
maxHeight: 160,
|
|
329
|
+
},
|
|
330
|
+
parameters: {
|
|
331
|
+
docs: {
|
|
332
|
+
description: {
|
|
333
|
+
story:
|
|
334
|
+
"`maxHeight` overrides the token-driven dropdown max-height with an explicit pixel value, scrolling the item list once it's exceeded.",
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
|
|
303
340
|
// mui-adapter's Menu has no native hover-trigger support (unlike Mantine's `trigger` prop),
|
|
304
341
|
// so this story implements open-on-hover itself: hovering the target opens the menu, and a
|
|
305
342
|
// short close delay (mirroring Mantine's `closeDelay`) keeps it open while the pointer moves
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef } from "react";
|
|
1
|
+
import { forwardRef, type CSSProperties } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Menu as MuiMenu,
|
|
4
4
|
type MenuProps as MuiMenuProps,
|
|
@@ -19,27 +19,47 @@ import { type RecursicaMenuProps } from "@recursica/adapter-common";
|
|
|
19
19
|
export type MenuProps = RecursicaOverStyled<MuiMenuProps & RecursicaMenuProps>;
|
|
20
20
|
|
|
21
21
|
export const Menu = forwardRef<HTMLDivElement, MenuProps>(function Menu(
|
|
22
|
-
{ overStyled = false, className, ...rest },
|
|
22
|
+
{ overStyled = false, className, maxHeight, ...rest },
|
|
23
23
|
ref,
|
|
24
24
|
) {
|
|
25
25
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
26
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
26
27
|
|
|
27
28
|
const mergedClassNames = mergeClassNames(
|
|
28
29
|
{
|
|
29
30
|
paper: styles.dropdown,
|
|
30
31
|
list: styles.dropdown,
|
|
31
32
|
},
|
|
32
|
-
|
|
33
|
-
| Partial<Record<string, string>>
|
|
34
|
-
| undefined,
|
|
33
|
+
restRecord.classes as Partial<Record<string, string>> | undefined,
|
|
35
34
|
);
|
|
36
35
|
|
|
36
|
+
// `maxHeight` is a caller-supplied override of the token-driven dropdown max-height, applied
|
|
37
|
+
// to the Paper slot's inline style — an explicit per-instance escape hatch, not a design token.
|
|
38
|
+
const callerSlotProps = restRecord.slotProps as
|
|
39
|
+
| { paper?: Record<string, unknown> }
|
|
40
|
+
| undefined;
|
|
41
|
+
const mergedSlotProps = maxHeight
|
|
42
|
+
? {
|
|
43
|
+
...callerSlotProps,
|
|
44
|
+
paper: {
|
|
45
|
+
...callerSlotProps?.paper,
|
|
46
|
+
style: {
|
|
47
|
+
...(callerSlotProps?.paper?.style as CSSProperties | undefined),
|
|
48
|
+
maxHeight,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
: callerSlotProps;
|
|
53
|
+
|
|
37
54
|
return (
|
|
38
55
|
<MuiMenu
|
|
39
56
|
ref={ref}
|
|
40
57
|
{...(sanitizedProps as MuiMenuProps)}
|
|
41
58
|
className={className}
|
|
42
59
|
classes={mergedClassNames}
|
|
60
|
+
{...(mergedSlotProps
|
|
61
|
+
? { slotProps: mergedSlotProps as MuiMenuProps["slotProps"] }
|
|
62
|
+
: {})}
|
|
43
63
|
/>
|
|
44
64
|
);
|
|
45
65
|
});
|
|
@@ -45,3 +45,9 @@ All Recursica components in the `@recursica/mui-adapter` package adhere strictly
|
|
|
45
45
|
> - **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.
|
|
46
46
|
> - **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.
|
|
47
47
|
> - **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.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. Notes
|
|
52
|
+
|
|
53
|
+
- `maxHeight` on `<Menu>` overrides the dropdown's token-driven max-height with an explicit pixel (or other CSS length) value, e.g. `<Menu maxHeight={320}>`. It's a per-instance escape hatch, not a design token — leave it unset to use the token default.
|