@recursica/mantine-adapter 0.18.0 → 0.20.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/mantine-adapter.cjs +1 -1
  3. package/dist/mantine-adapter.cjs.map +1 -1
  4. package/dist/mantine-adapter.css +1 -1
  5. package/dist/mantine-adapter.js +1654 -1366
  6. package/dist/mantine-adapter.js.map +1 -1
  7. package/dist/src/components/Modal/Modal.d.ts +39 -2
  8. package/dist/src/components/Modal/index.d.ts +1 -0
  9. package/dist/src/components/Popover/Popover.d.ts +55 -0
  10. package/dist/src/components/Popover/index.d.ts +1 -0
  11. package/dist/src/components/Stack/Stack.d.ts +9 -1
  12. package/dist/src/components/Timeline/Timeline.d.ts +14 -2
  13. package/dist/src/components/Timeline/TimelineItem.d.ts +25 -0
  14. package/dist/src/components/Toast/Toast.d.ts +21 -2
  15. package/dist/src/components/Toast/index.d.ts +1 -0
  16. package/dist/src/components/index.d.ts +2 -1
  17. package/dist/src/utils/filterStylingProps.d.ts +2 -0
  18. package/package.json +1 -1
  19. package/src/Introduction.stories.tsx +77 -103
  20. package/src/OverStyling.tsx +216 -171
  21. package/src/components/Button/Button.module.css +21 -4
  22. package/src/components/Button/Button.stories.tsx +14 -0
  23. package/src/components/Flex/Flex.tsx +9 -4
  24. package/src/components/Group/Group.tsx +5 -3
  25. package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +15 -0
  26. package/src/components/Modal/Modal.module.css +127 -0
  27. package/src/components/Modal/Modal.stories.tsx +66 -4
  28. package/src/components/Modal/Modal.tsx +218 -3
  29. package/src/components/Modal/index.ts +1 -0
  30. package/src/components/Popover/IMPLEMENTATION_NOTES.md +77 -0
  31. package/src/components/Popover/Popover.module.css +84 -0
  32. package/src/components/Popover/Popover.stories.tsx +133 -0
  33. package/src/components/Popover/Popover.tsx +156 -0
  34. package/src/components/Popover/index.ts +1 -0
  35. package/src/components/Stack/Stack.tsx +9 -5
  36. package/src/components/Timeline/TIMELINE_IMPLEMENTATION_NOTES.md +13 -0
  37. package/src/components/Timeline/Timeline.module.css +361 -0
  38. package/src/components/Timeline/Timeline.stories.tsx +114 -3
  39. package/src/components/Timeline/Timeline.tsx +81 -4
  40. package/src/components/Timeline/TimelineItem.tsx +102 -0
  41. package/src/components/Toast/TOAST_IMPLEMENTATION_NOTES.md +39 -0
  42. package/src/components/Toast/Toast.module.css +109 -0
  43. package/src/components/Toast/Toast.stories.tsx +57 -7
  44. package/src/components/Toast/Toast.tsx +90 -4
  45. package/src/components/Toast/index.ts +1 -0
  46. package/src/components/index.ts +2 -1
  47. package/src/utils/filterStylingProps.ts +17 -1
@@ -0,0 +1,133 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Popover } from "./Popover";
3
+ import { Button } from "../Button";
4
+ import { Text } from "../Text/Text";
5
+ import { Stack } from "../Stack/Stack";
6
+
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ type PopoverStoryArgs = Record<string, any>;
9
+
10
+ const meta = {
11
+ title: "UI-Kit/Popover",
12
+ component: Popover,
13
+ tags: ["autodocs"],
14
+ parameters: {
15
+ docs: {
16
+ description: {
17
+ component:
18
+ "The `Popover` component is a composable wrapper around Mantine's Popover. It displays a dropdown panel when the user clicks or interacts with a target element.",
19
+ },
20
+ },
21
+ },
22
+ argTypes: {
23
+ withBeak: {
24
+ control: "boolean",
25
+ description:
26
+ "Whether to display a beak (arrow) pointing from the dropdown to the target.",
27
+ },
28
+ position: {
29
+ control: "select",
30
+ options: [
31
+ "top",
32
+ "top-start",
33
+ "top-end",
34
+ "bottom",
35
+ "bottom-start",
36
+ "bottom-end",
37
+ "left",
38
+ "left-start",
39
+ "left-end",
40
+ "right",
41
+ "right-start",
42
+ "right-end",
43
+ ],
44
+ description: "Dropdown position relative to target",
45
+ },
46
+ defaultOpened: {
47
+ control: "boolean",
48
+ description: "Initial opened state",
49
+ },
50
+ },
51
+ } satisfies Meta<typeof Popover>;
52
+
53
+ export default meta;
54
+ type Story = StoryObj<typeof meta>;
55
+
56
+ export const Default: Story = {
57
+ args: {
58
+ withBeak: true,
59
+ position: "top",
60
+ },
61
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
62
+ render: ({ withLayer, layer, ...args }: PopoverStoryArgs) => {
63
+ return (
64
+ <Popover width={250} {...args}>
65
+ <Popover.Target>
66
+ <Button variant="solid">Toggle Popover</Button>
67
+ </Popover.Target>
68
+ <Popover.Dropdown>
69
+ <Text size="rec-sm">
70
+ This is the popover content. It can contain any elements you want to
71
+ display when the user clicks the target.
72
+ </Text>
73
+ </Popover.Dropdown>
74
+ </Popover>
75
+ );
76
+ },
77
+ };
78
+
79
+ export const SolidDefault: Story = {
80
+ args: {
81
+ withBeak: true,
82
+ position: "top",
83
+ defaultOpened: true,
84
+ },
85
+ parameters: {
86
+ controls: { disable: true },
87
+ },
88
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
89
+ render: ({ withLayer, layer, ...args }: PopoverStoryArgs) => {
90
+ return (
91
+ <Stack align="center" justify="center" style={{ padding: "100px" }}>
92
+ <Popover width={200} {...args}>
93
+ <Popover.Target>
94
+ <Button variant="solid">Toggle Popover</Button>
95
+ </Popover.Target>
96
+ <Popover.Dropdown>
97
+ <Text size="rec-sm">
98
+ This is a static representation of an opened popover with a beak.
99
+ </Text>
100
+ </Popover.Dropdown>
101
+ </Popover>
102
+ </Stack>
103
+ );
104
+ },
105
+ };
106
+
107
+ export const WithoutBeak: Story = {
108
+ args: {
109
+ withBeak: false,
110
+ position: "bottom",
111
+ defaultOpened: true,
112
+ },
113
+ parameters: {
114
+ controls: { disable: true },
115
+ },
116
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
117
+ render: ({ withLayer, layer, ...args }: PopoverStoryArgs) => {
118
+ return (
119
+ <Stack align="center" justify="center" style={{ padding: "100px" }}>
120
+ <Popover width={200} {...args}>
121
+ <Popover.Target>
122
+ <Button variant="outline">Bottom Popover</Button>
123
+ </Popover.Target>
124
+ <Popover.Dropdown>
125
+ <Text size="rec-sm">
126
+ This popover is positioned at the bottom and has no beak.
127
+ </Text>
128
+ </Popover.Dropdown>
129
+ </Popover>
130
+ </Stack>
131
+ );
132
+ },
133
+ };
@@ -0,0 +1,156 @@
1
+ import {
2
+ Popover as MantinePopover,
3
+ type PopoverProps as MantinePopoverProps,
4
+ type PopoverTargetProps as MantinePopoverTargetProps,
5
+ type PopoverDropdownProps as MantinePopoverDropdownProps,
6
+ } from "@mantine/core";
7
+ import {
8
+ filterStylingProps,
9
+ type RecursicaOverStyled,
10
+ } from "../../utils/filterStylingProps";
11
+ import styles from "./Popover.module.css";
12
+
13
+ // ============================================================
14
+ // POPOVER ROOT
15
+ // ============================================================
16
+
17
+ /**
18
+ * Recursica-specific props for Popover.
19
+ */
20
+ export interface RecursicaPopoverProps {
21
+ /**
22
+ * Whether to display a beak (arrow) pointing from the dropdown to the target.
23
+ * This is the Recursica equivalent of Mantine's `withArrow`.
24
+ * When both `withBeak` and `withArrow` are provided, `withBeak` takes precedence.
25
+ */
26
+ withBeak?: boolean;
27
+ }
28
+
29
+ /**
30
+ * Recursica Popover component wrapping Mantine's composable Popover.
31
+ *
32
+ * Displays a dropdown panel when the user clicks or interacts with a target element.
33
+ * Uses the composable dot-notation pattern:
34
+ * ```tsx
35
+ * <Popover withBeak>
36
+ * <Popover.Target>
37
+ * <Button>Click me</Button>
38
+ * </Popover.Target>
39
+ * <Popover.Dropdown>
40
+ * Content displayed in popover
41
+ * </Popover.Dropdown>
42
+ * </Popover>
43
+ * ```
44
+ */
45
+ export type PopoverProps = RecursicaOverStyled<
46
+ MantinePopoverProps & RecursicaPopoverProps
47
+ >;
48
+
49
+ const PopoverBase = function Popover({
50
+ overStyled = false,
51
+ withBeak = true,
52
+ ...rest
53
+ }: PopoverProps) {
54
+ const sanitizedProps = filterStylingProps(rest, overStyled);
55
+
56
+ // Bind CSS module classes to Mantine's internal classNames API
57
+ const mergedClassNames: Partial<Record<string, string>> = {
58
+ dropdown: styles.dropdown,
59
+ arrow: styles.arrow,
60
+ };
61
+
62
+ const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
63
+ if (
64
+ classNamesProp &&
65
+ typeof classNamesProp === "object" &&
66
+ !Array.isArray(classNamesProp)
67
+ ) {
68
+ const o = classNamesProp as Record<string, string>;
69
+ Object.keys(o).forEach((key) => {
70
+ if (mergedClassNames[key]) {
71
+ mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
72
+ } else {
73
+ mergedClassNames[key] = o[key];
74
+ }
75
+ });
76
+ }
77
+
78
+ // arrowSize must be a JS number prop — Mantine uses it for inline width/height
79
+ // and positioning offset (-arrowSize/2) calculations that cannot be CSS-driven.
80
+ // Default to 16 to match the Recursica beak-size token (16px).
81
+ const arrowSize =
82
+ ((sanitizedProps as Record<string, unknown>).arrowSize as
83
+ | number
84
+ | undefined) ?? 16;
85
+
86
+ // Resolve withBeak (Recursica) vs withArrow (Mantine).
87
+ // withBeak takes precedence when both are provided.
88
+ const withArrow = (sanitizedProps as Record<string, unknown>).withArrow as
89
+ | boolean
90
+ | undefined;
91
+ const resolvedWithArrow = withBeak ?? withArrow;
92
+
93
+ return (
94
+ <MantinePopover
95
+ position="top" /* Recursica default; Mantine defaults to "bottom" */
96
+ arrowSize={arrowSize}
97
+ withArrow={resolvedWithArrow}
98
+ classNames={mergedClassNames}
99
+ {...(sanitizedProps as unknown as MantinePopoverProps)}
100
+ />
101
+ );
102
+ };
103
+ PopoverBase.displayName = "Popover";
104
+
105
+ // ============================================================
106
+ // POPOVER TARGET
107
+ // ============================================================
108
+
109
+ /**
110
+ * Wrapper for the element that triggers the popover.
111
+ * Requires a single child element that supports ref forwarding.
112
+ */
113
+ export type PopoverTargetProps = MantinePopoverTargetProps;
114
+
115
+ const PopoverTarget = function PopoverTarget(props: PopoverTargetProps) {
116
+ return <MantinePopover.Target {...props} />;
117
+ };
118
+ PopoverTarget.displayName = "PopoverTarget";
119
+
120
+ // ============================================================
121
+ // POPOVER DROPDOWN
122
+ // ============================================================
123
+
124
+ /** The dropdown panel displayed from the popover. */
125
+ export type PopoverDropdownProps =
126
+ RecursicaOverStyled<MantinePopoverDropdownProps>;
127
+
128
+ const PopoverDropdown = function PopoverDropdown({
129
+ overStyled = false,
130
+ ...rest
131
+ }: PopoverDropdownProps) {
132
+ const sanitizedProps = filterStylingProps(rest, overStyled);
133
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
134
+ .className as string | undefined;
135
+
136
+ return (
137
+ <MantinePopover.Dropdown
138
+ className={classNameProp}
139
+ {...(sanitizedProps as unknown as MantinePopoverDropdownProps)}
140
+ />
141
+ );
142
+ };
143
+ PopoverDropdown.displayName = "PopoverDropdown";
144
+
145
+ // ============================================================
146
+ // DOT NOTATION EXPORT
147
+ // ============================================================
148
+
149
+ type PopoverComponent = typeof PopoverBase & {
150
+ Target: typeof PopoverTarget;
151
+ Dropdown: typeof PopoverDropdown;
152
+ };
153
+
154
+ export const Popover = PopoverBase as PopoverComponent;
155
+ Popover.Target = PopoverTarget;
156
+ Popover.Dropdown = PopoverDropdown;
@@ -0,0 +1 @@
1
+ export * from "./Popover";
@@ -2,8 +2,12 @@ import { forwardRef } from "react";
2
2
  import {
3
3
  Stack as MantineStack,
4
4
  type StackProps as MantineStackProps,
5
+ createPolymorphicComponent,
5
6
  } from "@mantine/core";
6
- import { type RecursicaSpacing } from "../../utils/filterStylingProps";
7
+ import {
8
+ type RecursicaSpacing,
9
+ mapLayoutProps,
10
+ } from "../../utils/filterStylingProps";
7
11
  import styles from "./Stack.module.css";
8
12
 
9
13
  export interface RecursicaStackProps {
@@ -23,7 +27,7 @@ export interface RecursicaStackProps {
23
27
  */
24
28
  export type StackProps = MantineStackProps & RecursicaStackProps;
25
29
 
26
- export const Stack = forwardRef<HTMLDivElement, StackProps>(function Stack(
30
+ const _Stack = forwardRef<HTMLDivElement, StackProps>(function Stack(
27
31
  { children, gap = "rec-default", ...rest },
28
32
  ref,
29
33
  ) {
@@ -51,12 +55,12 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>(function Stack(
51
55
  ref={ref}
52
56
  className={finalClass}
53
57
  classNames={mergedClassNames}
54
- gap={gap}
55
- {...rest}
58
+ {...mapLayoutProps({ gap, ...rest } as Record<string, unknown>)}
56
59
  >
57
60
  {children}
58
61
  </MantineStack>
59
62
  );
60
63
  });
64
+ _Stack.displayName = "Stack";
61
65
 
62
- Stack.displayName = "Stack";
66
+ export const Stack = createPolymorphicComponent<"div", StackProps>(_Stack);
@@ -0,0 +1,13 @@
1
+ # Timeline Implementation Notes
2
+
3
+ ## Architecture
4
+
5
+ The `Timeline` component is a strict structural wrapper around Mantine's `<Timeline>` and `<Timeline.Item>` components.
6
+
7
+ - `Timeline.tsx` intercepts overarching properties like `lineWidth` and `bulletSize` to strip them out via `overStyled`, strictly adhering to the CSS token mapping in `.item` rules instead.
8
+ - `TimelineItem.tsx` implements a custom `timestamp` React node rendering slot to match the design system, positioning the text directly below the item's `children`.
9
+ - `TimelineItem.tsx` supports a custom `bulletVariant` prop (`"default" | "avatar" | "icon" | "icon-alternative"`) mapped onto `data-variant` to handle CSS variations dynamically.
10
+
11
+ ## Limitations & Missing Tokens
12
+
13
+ - **Avatar Bullet Size**: There is no specific pixel variable provided for the Avatar bullet size in the UI kit tokens (`avatar-size` evaluates to `"default"`). To maintain exact mathematical centering with Mantine's connector line `calc()` equations, the CSS falls back to inheriting the `default` bullet size (`20px`) for avatar nodes natively. If users supply a custom sized `img` tag, it must adhere to inline structural constraints or flex mappings.