@recursica/mantine-adapter 0.13.1 → 0.15.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 (32) 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 +1329 -1082
  6. package/dist/mantine-adapter.js.map +1 -1
  7. package/dist/src/components/HoverCard/HoverCard.d.ts +55 -3
  8. package/dist/src/components/NumberInput/NumberInput.d.ts +10 -2
  9. package/dist/src/components/Panel/Panel.d.ts +65 -3
  10. package/dist/src/components/Tooltip/Tooltip.d.ts +42 -3
  11. package/package.json +1 -1
  12. package/src/components/Card/Card.module.css +1 -0
  13. package/src/components/Card/Card.stories.tsx +48 -58
  14. package/src/components/Dropdown/Dropdown.module.css +0 -3
  15. package/src/components/HoverCard/HOVERCARD_IMPLEMENTATION_NOTES.md +77 -0
  16. package/src/components/HoverCard/HoverCard.module.css +84 -0
  17. package/src/components/HoverCard/HoverCard.stories.tsx +160 -5
  18. package/src/components/HoverCard/HoverCard.tsx +153 -4
  19. package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +18 -0
  20. package/src/components/NumberInput/NumberInput.module.css +250 -0
  21. package/src/components/NumberInput/NumberInput.stories.tsx +84 -4
  22. package/src/components/NumberInput/NumberInput.tsx +144 -5
  23. package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +106 -0
  24. package/src/components/Panel/Panel.module.css +154 -0
  25. package/src/components/Panel/Panel.stories.tsx +216 -6
  26. package/src/components/Panel/Panel.tsx +153 -4
  27. package/src/components/TextArea/TextArea.module.css +0 -3
  28. package/src/components/TextField/TextField.module.css +0 -3
  29. package/src/components/Tooltip/TOOLTIP_IMPLEMENTATION_NOTES.md +85 -0
  30. package/src/components/Tooltip/Tooltip.module.css +81 -0
  31. package/src/components/Tooltip/Tooltip.stories.tsx +154 -6
  32. package/src/components/Tooltip/Tooltip.tsx +114 -4
@@ -1,17 +1,165 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { Tooltip } from "./Tooltip";
3
- import { ComingSoon } from "@recursica/storybook-template";
2
+ import { Tooltip, type TooltipProps } from "./Tooltip";
3
+ import { Button } from "../Button";
4
4
 
5
- const meta: Meta<typeof Tooltip> = {
6
- title: "UI-Kit/🚧 Tooltip",
5
+ /**
6
+ * Tooltip story axes:
7
+ * - position: tooltip alignment relative to target
8
+ * - withBeak: beak (arrow) indicator on the tooltip
9
+ * - openDelay / closeDelay: hover timing controls
10
+ * - multiline: text wrapping behavior
11
+ * - disabled: suppress the tooltip entirely
12
+ * - layer: tested via the global Layer decorator (withLayer/layer args)
13
+ */
14
+
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ type TooltipStoryArgs = Record<string, any>;
17
+
18
+ const meta: Meta = {
19
+ title: "UI-Kit/Tooltip",
7
20
  component: Tooltip,
8
21
  tags: ["autodocs"],
22
+ argTypes: {
23
+ label: {
24
+ control: "text",
25
+ description: "Content displayed inside the tooltip.",
26
+ },
27
+ position: {
28
+ control: "select",
29
+ options: [
30
+ "bottom",
31
+ "bottom-start",
32
+ "bottom-end",
33
+ "top",
34
+ "top-start",
35
+ "top-end",
36
+ "left",
37
+ "left-start",
38
+ "left-end",
39
+ "right",
40
+ "right-start",
41
+ "right-end",
42
+ ],
43
+ description: "The position of the tooltip relative to the target.",
44
+ },
45
+ withBeak: {
46
+ control: "boolean",
47
+ description:
48
+ "Whether to display a beak (arrow) pointing to the target. Recursica equivalent of Mantine's withArrow.",
49
+ },
50
+ offset: {
51
+ control: "number",
52
+ description: "Distance in px between the tooltip and the target element.",
53
+ },
54
+ openDelay: {
55
+ control: "number",
56
+ description: "Delay in ms before the tooltip opens on hover.",
57
+ },
58
+ closeDelay: {
59
+ control: "number",
60
+ description: "Delay in ms before the tooltip closes when hover ends.",
61
+ },
62
+ disabled: {
63
+ control: "boolean",
64
+ description: "If set, the tooltip will not be rendered.",
65
+ },
66
+ opened: {
67
+ control: "boolean",
68
+ description:
69
+ "Force the tooltip to stay open. Useful for inspecting styling.",
70
+ },
71
+ // Hide auto-detected HTML attributes that leak from ElementProps<'div'>
72
+ defaultChecked: { table: { disable: true } },
73
+ defaultValue: { table: { disable: true } },
74
+ suppressContentEditableWarning: { table: { disable: true } },
75
+ suppressHydrationWarning: { table: { disable: true } },
76
+ },
77
+ parameters: {
78
+ layout: "centered",
79
+ docs: {
80
+ description: {
81
+ component: `
82
+ The \`Tooltip\` component displays a floating label when the user hovers over or focuses a target element. It wraps Mantine's \`Tooltip\` while enforcing strict Recursica design token styling.
83
+
84
+ ### API
85
+
86
+ Unlike \`HoverCard\`, Tooltip is a single component — content is passed via the \`label\` prop:
87
+ \`\`\`tsx
88
+ <Tooltip label="Helpful text" withBeak>
89
+ <Button>Hover me</Button>
90
+ </Tooltip>
91
+ \`\`\`
92
+
93
+ ### Static Sub-Components
94
+ - \`Tooltip.Floating\` — A tooltip that follows the cursor position
95
+ - \`Tooltip.Group\` — Groups multiple tooltips to share hover delay
96
+
97
+ ### Key Behaviors
98
+ - The beak (arrow) is shown by default (\`withBeak={true}\`)
99
+ - Supports \`openDelay\` and \`closeDelay\` for timing control
100
+ - Set \`multiline\` to allow text wrapping within max-width
101
+ `,
102
+ },
103
+ },
104
+ },
9
105
  };
10
106
 
11
107
  export default meta;
12
108
 
13
- type Story = StoryObj<typeof Tooltip>;
109
+ type Story = StoryObj<TooltipStoryArgs>;
14
110
 
15
111
  export const Default: Story = {
16
- render: () => <ComingSoon componentName="Tooltip" />,
112
+ args: {
113
+ label: "This is a helpful tooltip",
114
+ position: "top",
115
+ withBeak: true,
116
+ offset: 5,
117
+ openDelay: 0,
118
+ closeDelay: 0,
119
+ disabled: false,
120
+ },
121
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
122
+ render: ({ withLayer, layer, ...args }: TooltipStoryArgs) => {
123
+ return (
124
+ <Tooltip {...(args as TooltipProps)}>
125
+ <Button variant="solid">Hover me</Button>
126
+ </Tooltip>
127
+ );
128
+ },
129
+ };
130
+
131
+ export const WithoutBeak: Story = {
132
+ args: {
133
+ label: "Tooltip without a beak indicator",
134
+ position: "top",
135
+ withBeak: false,
136
+ offset: 5,
137
+ },
138
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
139
+ render: ({ withLayer, layer, ...args }: TooltipStoryArgs) => {
140
+ return (
141
+ <Tooltip {...(args as TooltipProps)}>
142
+ <Button variant="outline">Without Beak</Button>
143
+ </Tooltip>
144
+ );
145
+ },
146
+ };
147
+
148
+ export const LongContent: Story = {
149
+ args: {
150
+ label:
151
+ "This is a longer tooltip message that demonstrates how text wraps within the maximum width defined by the design system.",
152
+ position: "top",
153
+ withBeak: true,
154
+ opened: true,
155
+ offset: 5,
156
+ },
157
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
158
+ render: ({ withLayer, layer, ...args }: TooltipStoryArgs) => {
159
+ return (
160
+ <Tooltip {...(args as TooltipProps)}>
161
+ <Button variant="solid">Long Content</Button>
162
+ </Tooltip>
163
+ );
164
+ },
17
165
  };
@@ -1,7 +1,117 @@
1
- import React from "react";
1
+ import {
2
+ Tooltip as MantineTooltip,
3
+ type TooltipProps as MantineTooltipProps,
4
+ } from "@mantine/core";
5
+ import {
6
+ filterStylingProps,
7
+ type RecursicaOverStyled,
8
+ } from "../../utils/filterStylingProps";
9
+ import styles from "./Tooltip.module.css";
2
10
 
3
- export type TooltipProps = React.HTMLAttributes<HTMLDivElement>;
11
+ // ============================================================
12
+ // TOOLTIP
13
+ // ============================================================
4
14
 
5
- export const Tooltip: React.FC<TooltipProps> = (props) => {
6
- return <div {...props}>Tooltip</div>;
15
+ /**
16
+ * Recursica-specific props for Tooltip.
17
+ */
18
+ export interface RecursicaTooltipProps {
19
+ /**
20
+ * Whether to display a beak (arrow) pointing from the tooltip to the target.
21
+ * This is the Recursica equivalent of Mantine's `withArrow`.
22
+ * When both `withBeak` and `withArrow` are provided, `withBeak` takes precedence.
23
+ * @default true
24
+ */
25
+ withBeak?: boolean;
26
+ }
27
+
28
+ /**
29
+ * Recursica Tooltip component wrapping Mantine's Tooltip.
30
+ *
31
+ * Displays a floating label when the user hovers over or focuses a target element.
32
+ * Unlike HoverCard, Tooltip is a single component (not composable) — content is
33
+ * passed via the `label` prop, and the trigger is passed as `children`.
34
+ *
35
+ * ```tsx
36
+ * <Tooltip label="Helpful information" withBeak>
37
+ * <Button>Hover me</Button>
38
+ * </Tooltip>
39
+ * ```
40
+ *
41
+ * Static sub-components available via dot-notation:
42
+ * - `Tooltip.Floating` — Tooltip that follows the cursor
43
+ * - `Tooltip.Group` — Shared hover delay group for multiple tooltips
44
+ */
45
+ export type TooltipProps = RecursicaOverStyled<
46
+ MantineTooltipProps & RecursicaTooltipProps
47
+ >;
48
+
49
+ const TooltipBase = function Tooltip({
50
+ overStyled = false,
51
+ withBeak = true,
52
+ ...rest
53
+ }: TooltipProps) {
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
+ tooltip: styles.tooltip,
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
+ <MantineTooltip
95
+ position="top" /* Recursica default; Mantine defaults to "bottom" */
96
+ multiline /* Always allow text wrapping within max-width */
97
+ arrowSize={arrowSize}
98
+ withArrow={resolvedWithArrow}
99
+ classNames={mergedClassNames}
100
+ {...(sanitizedProps as unknown as MantineTooltipProps)}
101
+ />
102
+ );
7
103
  };
104
+ TooltipBase.displayName = "Tooltip";
105
+
106
+ // ============================================================
107
+ // DOT NOTATION EXPORT
108
+ // ============================================================
109
+
110
+ type TooltipComponent = typeof TooltipBase & {
111
+ Floating: typeof MantineTooltip.Floating;
112
+ Group: typeof MantineTooltip.Group;
113
+ };
114
+
115
+ export const Tooltip = TooltipBase as TooltipComponent;
116
+ Tooltip.Floating = MantineTooltip.Floating;
117
+ Tooltip.Group = MantineTooltip.Group;