@recursica/mantine-adapter 0.13.0 → 0.14.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 +12 -0
- package/dist/mantine-adapter.cjs +1 -1
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.css +1 -1
- package/dist/mantine-adapter.js +1304 -1059
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/HoverCard/HoverCard.d.ts +55 -3
- package/dist/src/components/NumberInput/NumberInput.d.ts +10 -2
- package/dist/src/components/Panel/Panel.d.ts +57 -3
- package/dist/src/components/Tooltip/Tooltip.d.ts +42 -3
- package/package.json +1 -1
- package/src/components/Dropdown/Dropdown.module.css +0 -3
- package/src/components/HoverCard/HOVERCARD_IMPLEMENTATION_NOTES.md +77 -0
- package/src/components/HoverCard/HoverCard.module.css +84 -0
- package/src/components/HoverCard/HoverCard.stories.tsx +160 -5
- package/src/components/HoverCard/HoverCard.tsx +153 -4
- package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +25 -0
- package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +18 -0
- package/src/components/NumberInput/NumberInput.module.css +250 -0
- package/src/components/NumberInput/NumberInput.stories.tsx +84 -4
- package/src/components/NumberInput/NumberInput.tsx +144 -5
- package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +106 -0
- package/src/components/Panel/Panel.module.css +143 -0
- package/src/components/Panel/Panel.stories.tsx +205 -6
- package/src/components/Panel/Panel.tsx +143 -4
- package/src/components/TextArea/TextArea.module.css +0 -3
- package/src/components/TextField/TextField.module.css +0 -3
- package/src/components/Tooltip/TOOLTIP_IMPLEMENTATION_NOTES.md +85 -0
- package/src/components/Tooltip/Tooltip.module.css +81 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +154 -6
- package/src/components/Tooltip/Tooltip.tsx +114 -4
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { HoverCardProps as MantineHoverCardProps, HoverCardTargetProps as MantineHoverCardTargetProps, HoverCardDropdownProps as MantineHoverCardDropdownProps } from '@mantine/core';
|
|
2
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
3
|
+
/**
|
|
4
|
+
* Recursica-specific props for HoverCard.
|
|
5
|
+
*/
|
|
6
|
+
export interface RecursicaHoverCardProps {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to display a beak (arrow) pointing from the dropdown to the target.
|
|
9
|
+
* This is the Recursica equivalent of Mantine's `withArrow`.
|
|
10
|
+
* When both `withBeak` and `withArrow` are provided, `withBeak` takes precedence.
|
|
11
|
+
*/
|
|
12
|
+
withBeak?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Recursica HoverCard component wrapping Mantine's composable HoverCard.
|
|
16
|
+
*
|
|
17
|
+
* Displays a dropdown panel when the user hovers over a target element.
|
|
18
|
+
* Uses the composable dot-notation pattern:
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <HoverCard withBeak>
|
|
21
|
+
* <HoverCard.Target>
|
|
22
|
+
* <Button>Hover me</Button>
|
|
23
|
+
* </HoverCard.Target>
|
|
24
|
+
* <HoverCard.Dropdown>
|
|
25
|
+
* Content displayed on hover
|
|
26
|
+
* </HoverCard.Dropdown>
|
|
27
|
+
* </HoverCard>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export type HoverCardProps = RecursicaOverStyled<MantineHoverCardProps & RecursicaHoverCardProps>;
|
|
31
|
+
declare const HoverCardBase: {
|
|
32
|
+
({ overStyled, withBeak, ...rest }: HoverCardProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
displayName: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Wrapper for the element that triggers the hover card.
|
|
37
|
+
* Requires a single child element that supports ref forwarding.
|
|
38
|
+
*/
|
|
39
|
+
export type HoverCardTargetProps = MantineHoverCardTargetProps;
|
|
40
|
+
declare const HoverCardTarget: {
|
|
41
|
+
(props: HoverCardTargetProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
displayName: string;
|
|
43
|
+
};
|
|
44
|
+
/** The dropdown panel displayed when hovering over the target. */
|
|
45
|
+
export type HoverCardDropdownProps = RecursicaOverStyled<MantineHoverCardDropdownProps>;
|
|
46
|
+
declare const HoverCardDropdown: {
|
|
47
|
+
({ overStyled, ...rest }: HoverCardDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
48
|
+
displayName: string;
|
|
49
|
+
};
|
|
50
|
+
type HoverCardComponent = typeof HoverCardBase & {
|
|
51
|
+
Target: typeof HoverCardTarget;
|
|
52
|
+
Dropdown: typeof HoverCardDropdown;
|
|
53
|
+
};
|
|
54
|
+
export declare const HoverCard: HoverCardComponent;
|
|
55
|
+
export {};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { NumberInputProps as MantineNumberInputProps } from '@mantine/core';
|
|
3
|
+
import { ReadOnlyControlProps } from '@recursica/adapter-common';
|
|
4
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
5
|
+
import { RecursicaFormControlWrapperProps } from '../FormControlWrapper/FormControlWrapper';
|
|
6
|
+
export interface RecursicaNumberInputProps extends Omit<MantineNumberInputProps, "size" | "variant" | "radius" | "wrapperProps" | "classNames" | "styles">, Pick<RecursicaFormControlWrapperProps, "assistiveText" | "assistiveWithIcon" | "formLayout" | "labelSize" | "labelAlignment" | "labelOptionalText" | "labelWithEditIcon" | "onLabelEditClick">, ReadOnlyControlProps {
|
|
7
|
+
/** Enables/disables the controls to increment and decrement the value */
|
|
8
|
+
hideControls?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export type NumberInputProps = RecursicaOverStyled<RecursicaNumberInputProps>;
|
|
11
|
+
export declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -1,3 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Drawer as MantineDrawer, DrawerProps as MantineDrawerProps } from '@mantine/core';
|
|
2
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
3
|
+
/**
|
|
4
|
+
* Recursica Panel root props. Extends Mantine Drawer.
|
|
5
|
+
*/
|
|
6
|
+
export type PanelProps = RecursicaOverStyled<MantineDrawerProps>;
|
|
7
|
+
/**
|
|
8
|
+
* Recursica Panel component wrapping Mantine's Drawer.
|
|
9
|
+
*
|
|
10
|
+
* Panels slide in or expand from the edge of the screen to reveal
|
|
11
|
+
* additional content or functionality. They are commonly used to provide
|
|
12
|
+
* supplementary information, navigation options, or toolsets without
|
|
13
|
+
* cluttering the main interface.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Panel opened={opened} onClose={close} title="Panel Title" position="right">
|
|
17
|
+
* <Panel.Body>
|
|
18
|
+
* Content goes here
|
|
19
|
+
* </Panel.Body>
|
|
20
|
+
* </Panel>
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Mantine Drawer sub-components available via dot-notation:
|
|
24
|
+
* - `Panel.Header` — Top section with title and close button
|
|
25
|
+
* - `Panel.Title` — Title text within the header
|
|
26
|
+
* - `Panel.CloseButton` — Close button within the header
|
|
27
|
+
* - `Panel.Body` — Scrollable body content area
|
|
28
|
+
* - `Panel.Content` — Outer content container
|
|
29
|
+
* - `Panel.Overlay` — Background overlay
|
|
30
|
+
* - `Panel.Root` — Root element for advanced composition
|
|
31
|
+
* - `Panel.Stack` — Stacked drawer context
|
|
32
|
+
*/
|
|
33
|
+
declare const PanelBase: {
|
|
34
|
+
({ overStyled, position, keepMounted, ...rest }: PanelProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
displayName: string;
|
|
36
|
+
};
|
|
37
|
+
export type PanelFooterProps = RecursicaOverStyled<React.HTMLAttributes<HTMLDivElement>>;
|
|
38
|
+
/**
|
|
39
|
+
* Panel footer section with action buttons.
|
|
40
|
+
* Separated from the body by a divider. Remains fixed at the bottom.
|
|
41
|
+
* This is a Recursica-specific sub-component; Mantine Drawer does not
|
|
42
|
+
* natively provide a footer.
|
|
43
|
+
*/
|
|
44
|
+
export declare const PanelFooter: import('react').ForwardRefExoticComponent<PanelFooterProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
45
|
+
type PanelComponent = typeof PanelBase & {
|
|
46
|
+
Root: typeof MantineDrawer.Root;
|
|
47
|
+
Overlay: typeof MantineDrawer.Overlay;
|
|
48
|
+
Content: typeof MantineDrawer.Content;
|
|
49
|
+
Header: typeof MantineDrawer.Header;
|
|
50
|
+
Title: typeof MantineDrawer.Title;
|
|
51
|
+
CloseButton: typeof MantineDrawer.CloseButton;
|
|
52
|
+
Body: typeof MantineDrawer.Body;
|
|
53
|
+
Stack: typeof MantineDrawer.Stack;
|
|
54
|
+
Footer: typeof PanelFooter;
|
|
55
|
+
};
|
|
56
|
+
export declare const Panel: PanelComponent;
|
|
57
|
+
export {};
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Tooltip as MantineTooltip, TooltipProps as MantineTooltipProps } from '@mantine/core';
|
|
2
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
3
|
+
/**
|
|
4
|
+
* Recursica-specific props for Tooltip.
|
|
5
|
+
*/
|
|
6
|
+
export interface RecursicaTooltipProps {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to display a beak (arrow) pointing from the tooltip to the target.
|
|
9
|
+
* This is the Recursica equivalent of Mantine's `withArrow`.
|
|
10
|
+
* When both `withBeak` and `withArrow` are provided, `withBeak` takes precedence.
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
withBeak?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Recursica Tooltip component wrapping Mantine's Tooltip.
|
|
17
|
+
*
|
|
18
|
+
* Displays a floating label when the user hovers over or focuses a target element.
|
|
19
|
+
* Unlike HoverCard, Tooltip is a single component (not composable) — content is
|
|
20
|
+
* passed via the `label` prop, and the trigger is passed as `children`.
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <Tooltip label="Helpful information" withBeak>
|
|
24
|
+
* <Button>Hover me</Button>
|
|
25
|
+
* </Tooltip>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Static sub-components available via dot-notation:
|
|
29
|
+
* - `Tooltip.Floating` — Tooltip that follows the cursor
|
|
30
|
+
* - `Tooltip.Group` — Shared hover delay group for multiple tooltips
|
|
31
|
+
*/
|
|
32
|
+
export type TooltipProps = RecursicaOverStyled<MantineTooltipProps & RecursicaTooltipProps>;
|
|
33
|
+
declare const TooltipBase: {
|
|
34
|
+
({ overStyled, withBeak, ...rest }: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
displayName: string;
|
|
36
|
+
};
|
|
37
|
+
type TooltipComponent = typeof TooltipBase & {
|
|
38
|
+
Floating: typeof MantineTooltip.Floating;
|
|
39
|
+
Group: typeof MantineTooltip.Group;
|
|
40
|
+
};
|
|
41
|
+
export declare const Tooltip: TooltipComponent;
|
|
42
|
+
export {};
|
package/package.json
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# HoverCard – Implementation Notes
|
|
2
|
+
|
|
3
|
+
Decisions and design tweaks strictly tailored for the UI Kit's HoverCard wrapped against `@mantine/core`. This is a living document that tracks _why_ specific logic decisions exist.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Composable API Preservation (1:1 Mapping)
|
|
8
|
+
|
|
9
|
+
**Decision:** We maintain the exact library composition API structure (`<HoverCard>`, `<HoverCard.Target>`, `<HoverCard.Dropdown>`) as a 1:1 React component mapping.
|
|
10
|
+
|
|
11
|
+
**Implementation:** Mantine's HoverCard internally manages hover detection, open/close delays, Floating UI positioning, and portal rendering. By preserving the exact sub-component tree, Recursica safely inherits all of these behaviors without reimplementation.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. HoverCard.Target Pass-Through
|
|
16
|
+
|
|
17
|
+
**Decision:** `HoverCard.Target` is a transparent pass-through with no styling applied.
|
|
18
|
+
|
|
19
|
+
**Implementation:** The target wrapper exists solely to manage Mantine's ref forwarding and hover event binding for the trigger element. No `filterStylingProps` or CSS module classes are applied — the trigger's appearance is entirely controlled by whatever component the integrator places inside it (e.g., `<Button>`). This is identical to the `Menu.Target` pattern.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 3. Token Namespace: `hover-card-popover`
|
|
24
|
+
|
|
25
|
+
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_hover-card-popover_*` namespace.
|
|
26
|
+
|
|
27
|
+
**Implementation:** The Recursica token system defines a single shared namespace (`hover-card-popover`) for this component covering geometry (border-radius, border-size, padding, min/max-width), typography (content-text\_\*), elevation, and layer-aware colors (background, border-color, content). No tokens from other component namespaces are referenced.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 4. Hardcoded Values
|
|
32
|
+
|
|
33
|
+
**Decision:** Two hardcoded values exist in the component.
|
|
34
|
+
|
|
35
|
+
### `border-style: solid` (CSS module)
|
|
36
|
+
|
|
37
|
+
Mantine renders the dropdown using its `Paper` component, which does not set `border-style` natively. Without this hardcoded value, the border-width and border-color tokens would have no visible effect. This is the same pattern used in the Menu component's dropdown.
|
|
38
|
+
|
|
39
|
+
### `arrowSize` defaulted to `16` (HoverCard.tsx)
|
|
40
|
+
|
|
41
|
+
Mantine's `arrowSize` prop is a JavaScript number used for inline style calculations: it sets `width`, `height`, and a positioning offset (`-arrowSize/2`) directly on the arrow `<div>` element. These inline styles **cannot** be overridden via CSS without `!important`, and the positioning offset has no CSS equivalent. This means the beak size cannot be fully CSS-driven — it is one of the rare cases where a design token value must be mirrored as a JS prop.
|
|
42
|
+
|
|
43
|
+
The default value `16` matches the Recursica `beak-size` token (`--recursica_ui-kit_components_hover-card-popover_properties_beak-size: 16px`). Developers can override `arrowSize` if needed, but should be aware this is a design system concern. If the token value changes, the default in `HoverCard.tsx` must also be updated.
|
|
44
|
+
|
|
45
|
+
This is documented as an open issue in `docs/COMPONENT_ISSUES.md`.
|
|
46
|
+
|
|
47
|
+
**Note:** Mantine calls this the "arrow"; Recursica calls it the "beak". The Recursica prop `withBeak` (defaulting to `true`) maps to Mantine's `withArrow`. Both `withBeak` and `withArrow` are accepted; `withBeak` takes precedence.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 5. Minimal CSS Override Philosophy
|
|
52
|
+
|
|
53
|
+
**Decision:** The CSS module only overrides visual design tokens (colors, typography, spacing, borders, shadows). All structural layout properties are deferred to Mantine's native behavior.
|
|
54
|
+
|
|
55
|
+
**Implementation:** HoverCard is an overlay component where Mantine's native Floating UI positioning and Paper layout are already correct. We avoid setting:
|
|
56
|
+
|
|
57
|
+
- `overflow` on the dropdown (Mantine handles scroll behavior natively)
|
|
58
|
+
- `display`, `position`, `z-index` (Floating UI controls these)
|
|
59
|
+
- `pointer-events` (Mantine manages hover detection across target and dropdown)
|
|
60
|
+
|
|
61
|
+
**Rationale:** The Menu implementation demonstrated that aggressive structural resets (overflow, box-sizing) on overlay components cause layout breakage. Default to Mantine's native behavior and only override what the Recursica token system explicitly needs to control.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 6. ClassNames Merging on Root
|
|
66
|
+
|
|
67
|
+
**Decision:** The root `HoverCard` component binds CSS module classes via `classNames` on the Mantine root, identical to the Menu pattern.
|
|
68
|
+
|
|
69
|
+
**Implementation:** The root component receives `classNames={{ dropdown: styles.dropdown }}` and merges any consumer-provided `classNames` when `overStyled` is true. This ensures our token-driven styles are applied to the dropdown panel without wrapper divs, and the consumer's classes are additive.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 7. Default Position Override
|
|
74
|
+
|
|
75
|
+
**Decision:** Recursica defaults `position` to `"top"`. Mantine defaults to `"bottom"`.
|
|
76
|
+
|
|
77
|
+
**Implementation:** The `position="top"` default is set on the Mantine root element before the prop spread, so developer-provided `position` values still take precedence. This aligns with Recursica's design intent for overlay components to appear above their trigger by default.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- border-style: solid. Structural rendering rule for the dropdown border (Mantine uses Paper
|
|
3
|
+
which may not set border-style natively). Same pattern as Menu.
|
|
4
|
+
- arrowSize defaults to 16 in HoverCard.tsx. Mantine uses arrowSize for inline width/height
|
|
5
|
+
and positioning (-arrowSize/2) calculations that cannot be CSS-driven. The default matches
|
|
6
|
+
the Recursica beak-size token (16px). See COMPONENT_ISSUES.md for details.
|
|
7
|
+
- All structural layout (display, position, overflow) is deferred to Mantine's native
|
|
8
|
+
behavior. We only override visual design tokens (colors, typography, spacing, borders).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* ======================================
|
|
12
|
+
DROPDOWN CONTAINER
|
|
13
|
+
====================================== */
|
|
14
|
+
|
|
15
|
+
.dropdown {
|
|
16
|
+
background-color: var(
|
|
17
|
+
--recursica_ui-kit_components_hover-card-popover_colors_background
|
|
18
|
+
);
|
|
19
|
+
border-style: solid; /* HARDCODE: Mantine Paper does not set border-style natively */
|
|
20
|
+
border-width: var(
|
|
21
|
+
--recursica_ui-kit_components_hover-card-popover_properties_border-size
|
|
22
|
+
);
|
|
23
|
+
border-color: var(
|
|
24
|
+
--recursica_ui-kit_components_hover-card-popover_colors_border-color
|
|
25
|
+
);
|
|
26
|
+
border-radius: var(
|
|
27
|
+
--recursica_ui-kit_components_hover-card-popover_properties_border-radius
|
|
28
|
+
);
|
|
29
|
+
box-shadow: var(
|
|
30
|
+
--recursica_ui-kit_components_hover-card-popover_properties_elevation
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
min-width: var(
|
|
34
|
+
--recursica_ui-kit_components_hover-card-popover_properties_min-width
|
|
35
|
+
);
|
|
36
|
+
max-width: var(
|
|
37
|
+
--recursica_ui-kit_components_hover-card-popover_properties_max-width
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
padding: var(
|
|
41
|
+
--recursica_ui-kit_components_hover-card-popover_properties_vertical-padding
|
|
42
|
+
)
|
|
43
|
+
var(
|
|
44
|
+
--recursica_ui-kit_components_hover-card-popover_properties_horizontal-padding
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
/* Typography */
|
|
48
|
+
font-family: var(
|
|
49
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-family
|
|
50
|
+
);
|
|
51
|
+
font-size: var(
|
|
52
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-size
|
|
53
|
+
);
|
|
54
|
+
font-style: var(
|
|
55
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-style
|
|
56
|
+
);
|
|
57
|
+
font-weight: var(
|
|
58
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-weight
|
|
59
|
+
);
|
|
60
|
+
letter-spacing: var(
|
|
61
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_letter-spacing
|
|
62
|
+
);
|
|
63
|
+
line-height: var(
|
|
64
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_line-height
|
|
65
|
+
);
|
|
66
|
+
text-decoration: var(
|
|
67
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_text-decoration
|
|
68
|
+
);
|
|
69
|
+
text-transform: var(
|
|
70
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_text-transform
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
color: var(--recursica_ui-kit_components_hover-card-popover_colors_content);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ======================================
|
|
77
|
+
ARROW / BEAK
|
|
78
|
+
====================================== */
|
|
79
|
+
|
|
80
|
+
.arrow {
|
|
81
|
+
border-color: var(
|
|
82
|
+
--recursica_ui-kit_components_hover-card-popover_colors_border-color
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -1,17 +1,172 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { HoverCard } from "./HoverCard";
|
|
3
|
-
import {
|
|
3
|
+
import { Button } from "../Button";
|
|
4
|
+
import { Text } from "../Text/Text";
|
|
5
|
+
import { Group } from "../Group/Group";
|
|
6
|
+
import { Stack } from "../Stack/Stack";
|
|
7
|
+
import { Avatar } from "../Avatar";
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
/**
|
|
10
|
+
* HoverCard story axes:
|
|
11
|
+
* - position: dropdown alignment relative to target
|
|
12
|
+
* - withArrow: arrow indicator on the dropdown
|
|
13
|
+
* - openDelay / closeDelay: hover timing controls
|
|
14
|
+
* - content variations: plain text, rich content (avatar + text + actions)
|
|
15
|
+
* - layer: tested via the global Layer decorator (withLayer/layer args)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
type HoverCardStoryArgs = Record<string, any>;
|
|
20
|
+
|
|
21
|
+
const meta: Meta = {
|
|
22
|
+
title: "UI-Kit/HoverCard",
|
|
7
23
|
component: HoverCard,
|
|
8
24
|
tags: ["autodocs"],
|
|
25
|
+
argTypes: {
|
|
26
|
+
position: {
|
|
27
|
+
control: "select",
|
|
28
|
+
options: [
|
|
29
|
+
"bottom",
|
|
30
|
+
"bottom-start",
|
|
31
|
+
"bottom-end",
|
|
32
|
+
"top",
|
|
33
|
+
"top-start",
|
|
34
|
+
"top-end",
|
|
35
|
+
"left",
|
|
36
|
+
"left-start",
|
|
37
|
+
"left-end",
|
|
38
|
+
"right",
|
|
39
|
+
"right-start",
|
|
40
|
+
"right-end",
|
|
41
|
+
],
|
|
42
|
+
description: "The position of the dropdown relative to the target.",
|
|
43
|
+
},
|
|
44
|
+
withBeak: {
|
|
45
|
+
control: "boolean",
|
|
46
|
+
description:
|
|
47
|
+
"Whether to display a beak (arrow) pointing to the target. Recursica equivalent of Mantine's withArrow.",
|
|
48
|
+
},
|
|
49
|
+
offset: {
|
|
50
|
+
control: "number",
|
|
51
|
+
description:
|
|
52
|
+
"Distance in px between the dropdown and the target element.",
|
|
53
|
+
},
|
|
54
|
+
openDelay: {
|
|
55
|
+
control: "number",
|
|
56
|
+
description: "Delay in ms before the dropdown opens on hover.",
|
|
57
|
+
},
|
|
58
|
+
closeDelay: {
|
|
59
|
+
control: "number",
|
|
60
|
+
description: "Delay in ms before the dropdown closes when hover ends.",
|
|
61
|
+
},
|
|
62
|
+
disabled: {
|
|
63
|
+
control: "boolean",
|
|
64
|
+
description: "If set, the hover card dropdown will not be rendered.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
parameters: {
|
|
68
|
+
layout: "centered",
|
|
69
|
+
docs: {
|
|
70
|
+
description: {
|
|
71
|
+
component: `
|
|
72
|
+
The \`HoverCard\` component displays a popover-style dropdown when the user hovers over a target element. It wraps Mantine's composable \`HoverCard\` while enforcing strict Recursica design token styling.
|
|
73
|
+
|
|
74
|
+
### Composable API
|
|
75
|
+
|
|
76
|
+
HoverCard uses a dot-notation composition pattern:
|
|
77
|
+
- \`<HoverCard>\` — Root container managing open/close state on hover
|
|
78
|
+
- \`<HoverCard.Target>\` — Wrapper for the trigger element (must be a single element supporting ref)
|
|
79
|
+
- \`<HoverCard.Dropdown>\` — The popup panel displaying content on hover
|
|
80
|
+
|
|
81
|
+
### Key Behaviors
|
|
82
|
+
- The dropdown opens when the user hovers over the target and closes when they move away
|
|
83
|
+
- \`openDelay\` and \`closeDelay\` control the timing of open/close transitions
|
|
84
|
+
- The dropdown stays open while the user hovers over it, allowing interaction with its content
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
9
89
|
};
|
|
10
90
|
|
|
11
91
|
export default meta;
|
|
12
92
|
|
|
13
|
-
type Story = StoryObj<
|
|
93
|
+
type Story = StoryObj<HoverCardStoryArgs>;
|
|
14
94
|
|
|
15
95
|
export const Default: Story = {
|
|
16
|
-
|
|
96
|
+
args: {
|
|
97
|
+
position: "top",
|
|
98
|
+
withBeak: true,
|
|
99
|
+
offset: 5,
|
|
100
|
+
openDelay: 0,
|
|
101
|
+
closeDelay: 150,
|
|
102
|
+
},
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
104
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
105
|
+
return (
|
|
106
|
+
<HoverCard {...args}>
|
|
107
|
+
<HoverCard.Target>
|
|
108
|
+
<Button variant="solid">Hover me</Button>
|
|
109
|
+
</HoverCard.Target>
|
|
110
|
+
|
|
111
|
+
<HoverCard.Dropdown>
|
|
112
|
+
<Text>
|
|
113
|
+
This is a hover card with informational content that appears when
|
|
114
|
+
you hover over the target element.
|
|
115
|
+
</Text>
|
|
116
|
+
</HoverCard.Dropdown>
|
|
117
|
+
</HoverCard>
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const WithoutBeak: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
position: "top",
|
|
125
|
+
withBeak: false,
|
|
126
|
+
offset: 5,
|
|
127
|
+
},
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
129
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
130
|
+
return (
|
|
131
|
+
<HoverCard {...args}>
|
|
132
|
+
<HoverCard.Target>
|
|
133
|
+
<Button variant="outline">Without Beak</Button>
|
|
134
|
+
</HoverCard.Target>
|
|
135
|
+
|
|
136
|
+
<HoverCard.Dropdown>
|
|
137
|
+
<Text>
|
|
138
|
+
This hover card has the beak disabled, showing a clean dropdown
|
|
139
|
+
without the pointing indicator.
|
|
140
|
+
</Text>
|
|
141
|
+
</HoverCard.Dropdown>
|
|
142
|
+
</HoverCard>
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const RichContent: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
position: "top",
|
|
150
|
+
offset: 5,
|
|
151
|
+
},
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
153
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
154
|
+
return (
|
|
155
|
+
<HoverCard {...args}>
|
|
156
|
+
<HoverCard.Target>
|
|
157
|
+
<Button variant="solid">User Profile</Button>
|
|
158
|
+
</HoverCard.Target>
|
|
159
|
+
|
|
160
|
+
<HoverCard.Dropdown>
|
|
161
|
+
<Group>
|
|
162
|
+
<Avatar src={null} alt="User avatar" />
|
|
163
|
+
<Stack>
|
|
164
|
+
<Text>Jane Doe</Text>
|
|
165
|
+
<Text>Software Engineer at Recursica</Text>
|
|
166
|
+
</Stack>
|
|
167
|
+
</Group>
|
|
168
|
+
</HoverCard.Dropdown>
|
|
169
|
+
</HoverCard>
|
|
170
|
+
);
|
|
171
|
+
},
|
|
17
172
|
};
|