@moneyforward/mfui-components 3.21.0 → 3.23.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/dist/src/Dialog/Dialog.d.ts +1 -1
- package/dist/src/Dialog/Dialog.types.d.ts +7 -1
- package/dist/src/FormFooter/FormFooter.types.d.ts +2 -3
- package/dist/src/SidePane/SidePane.d.ts +1 -1
- package/dist/src/SidePane/SidePane.types.d.ts +1 -3
- package/dist/src/Stepper/DoneStepIcon.d.ts +9 -0
- package/dist/src/Stepper/DoneStepIcon.js +11 -0
- package/dist/src/Stepper/Step/Step.d.ts +7 -0
- package/dist/src/Stepper/Step/Step.js +47 -0
- package/dist/src/Stepper/Step/Step.types.d.ts +20 -0
- package/dist/src/Stepper/Step/Step.types.js +1 -0
- package/dist/src/Stepper/Step/index.d.ts +2 -0
- package/dist/src/Stepper/Step/index.js +1 -0
- package/dist/src/Stepper/StepContext.d.ts +10 -0
- package/dist/src/Stepper/StepContext.js +2 -0
- package/dist/src/Stepper/Stepper.d.ts +26 -0
- package/dist/src/Stepper/Stepper.js +49 -0
- package/dist/src/Stepper/Stepper.types.d.ts +21 -0
- package/dist/src/Stepper/Stepper.types.js +1 -0
- package/dist/src/Stepper/StepperContext.d.ts +5 -0
- package/dist/src/Stepper/StepperContext.js +2 -0
- package/dist/src/Stepper/index.d.ts +3 -0
- package/dist/src/Stepper/index.js +1 -0
- package/dist/src/Tooltip/Tooltip.js +12 -3
- package/dist/src/Tooltip/hooks/useTooltipDisplayController.d.ts +1 -0
- package/dist/src/Tooltip/hooks/useTooltipDisplayController.js +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/styled-system/recipes/form-footer-slot-recipe.d.ts +1 -1
- package/dist/styled-system/recipes/form-footer-slot-recipe.js +0 -1
- package/dist/styled-system/recipes/index.d.ts +1 -0
- package/dist/styled-system/recipes/index.js +1 -0
- package/dist/styled-system/recipes/stepper-slot-recipe.d.ts +44 -0
- package/dist/styled-system/recipes/stepper-slot-recipe.js +118 -0
- package/dist/styled-system/tokens/index.js +892 -44
- package/dist/styled-system/tokens/tokens.d.ts +4 -4
- package/dist/styles.css +199 -34
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -7,8 +7,14 @@ export type DialogProps = {
|
|
|
7
7
|
children?: ReactNode;
|
|
8
8
|
/**
|
|
9
9
|
* The heading title of the dialog.
|
|
10
|
+
*
|
|
11
|
+
* Accepts a string or any `ReactNode` (e.g. a `<Skeleton />` shown while the
|
|
12
|
+
* title is loading asynchronously). Keep the node heading-appropriate —
|
|
13
|
+
* inline text, status indicators, or icons — because the dialog uses
|
|
14
|
+
* `aria-labelledby` to announce the title and screen readers will read the
|
|
15
|
+
* entire subtree. Avoid placing interactive controls inside `title`.
|
|
10
16
|
*/
|
|
11
|
-
title:
|
|
17
|
+
title: ReactNode;
|
|
12
18
|
/**
|
|
13
19
|
* Whether the dialog is shown or not.
|
|
14
20
|
* This prop is optional and should be passed when using the dialog as a controlled component.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
export type FormFooterPosition = '
|
|
2
|
+
export type FormFooterPosition = 'stacking' | 'sticky';
|
|
3
3
|
export type FormFooterSectionPosition = 'fill' | 'center';
|
|
4
4
|
export type FormFooterProps = {
|
|
5
5
|
/**
|
|
@@ -10,8 +10,7 @@ export type FormFooterProps = {
|
|
|
10
10
|
* It's for controlling the position of the component.
|
|
11
11
|
*
|
|
12
12
|
* - `"stacking"`: Displayed inline at the bottom of its container. Use for creation forms where preventing mid-session abandonment is important.
|
|
13
|
-
* - `"
|
|
14
|
-
* - `"sticky"`: Sits inline below the last form field, and pins to the bottom of the nearest scrolling ancestor (e.g. inside `SidePane`) when the form overflows. Use inside scrollable containers such as `SidePane`.
|
|
13
|
+
* - `"sticky"`: Sits inline below the last form field, and pins to the bottom of the nearest scrolling ancestor when the form overflows. Use inside scrollable containers such as `SidePane`.
|
|
15
14
|
*
|
|
16
15
|
* @default "stacking"
|
|
17
16
|
*/
|
|
@@ -18,7 +18,7 @@ export declare const SidePane: import("react").ForwardRefExoticComponent<{
|
|
|
18
18
|
disableBackdropClose?: boolean;
|
|
19
19
|
enableAutoUnmount?: boolean;
|
|
20
20
|
formFooterProps?: Pick<import("..").FormFooterProps, "optionsSlot" | "actionsSlot"> & {
|
|
21
|
-
position?:
|
|
21
|
+
position?: import("..").FormFooterProps["position"];
|
|
22
22
|
};
|
|
23
23
|
insideProps?: {
|
|
24
24
|
className?: string;
|
|
@@ -116,12 +116,10 @@ export type SidePaneProps = {
|
|
|
116
116
|
* - `position: 'sticky'` (default): the footer is always pinned to the pane bottom, outside the scrollable content area.
|
|
117
117
|
* - `position: 'stacking'`: the footer flows after the content inside the scroll area.
|
|
118
118
|
*
|
|
119
|
-
* `position: 'fixed'` is not supported here because it anchors to the viewport rather than the pane.
|
|
120
|
-
*
|
|
121
119
|
* @default undefined
|
|
122
120
|
*/
|
|
123
121
|
formFooterProps?: Pick<FormFooterProps, 'optionsSlot' | 'actionsSlot'> & {
|
|
124
|
-
position?:
|
|
122
|
+
position?: FormFooterProps['position'];
|
|
125
123
|
};
|
|
126
124
|
/**
|
|
127
125
|
* Additional props to apply to the inside container element of the SidePane.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type SVGProps } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Checkmark icon used inside the `done`-state step indicator.
|
|
4
|
+
*
|
|
5
|
+
* This component is private to `Stepper` and not exported from the package.
|
|
6
|
+
*
|
|
7
|
+
* @param props - SVG props forwarded to the root `<svg>`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function DoneStepIcon(props: SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Checkmark icon used inside the `done`-state step indicator.
|
|
4
|
+
*
|
|
5
|
+
* This component is private to `Stepper` and not exported from the package.
|
|
6
|
+
*
|
|
7
|
+
* @param props - SVG props forwarded to the root `<svg>`.
|
|
8
|
+
*/
|
|
9
|
+
export function DoneStepIcon(props) {
|
|
10
|
+
return (_jsx("svg", { width: 18, height: 18, viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M14.0002 6.00001C14.2764 6.27616 14.2764 6.72387 14.0002 7.00001L8.00024 13L3.99894 8.99871C3.72279 8.72257 3.7241 8.27616 4.00024 8.00001C4.27638 7.72387 4.7241 7.72387 5.00024 8.00001L8.00024 11L13.0002 6.00001C13.2764 5.72387 13.7241 5.72387 14.0002 6.00001Z", fill: "currentColor" }) }));
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type StepperStepProps } from './Step.types';
|
|
2
|
+
/**
|
|
3
|
+
* A single step inside `Stepper`. Rendered either as a static container, a
|
|
4
|
+
* `<button>` (when `onClick` is provided), or an `<a>`/custom link (when
|
|
5
|
+
* `href` is provided).
|
|
6
|
+
*/
|
|
7
|
+
export declare function Step({ children, onClick, href, customLinkComponent }: StepperStepProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createElement, useContext } from 'react';
|
|
4
|
+
import { cx } from '../../../styled-system/css';
|
|
5
|
+
import { stepperSlotRecipe } from '../../../styled-system/recipes';
|
|
6
|
+
import { FocusIndicator } from '../../FocusIndicator';
|
|
7
|
+
import { Typography } from '../../Typography';
|
|
8
|
+
import { DoneStepIcon } from '../DoneStepIcon';
|
|
9
|
+
import { StepperContext } from '../StepperContext';
|
|
10
|
+
import { StepContext } from '../StepContext';
|
|
11
|
+
/**
|
|
12
|
+
* A single step inside `Stepper`. Rendered either as a static container, a
|
|
13
|
+
* `<button>` (when `onClick` is provided), or an `<a>`/custom link (when
|
|
14
|
+
* `href` is provided).
|
|
15
|
+
*/
|
|
16
|
+
export function Step({ children, onClick, href, customLinkComponent }) {
|
|
17
|
+
const stepperContext = useContext(StepperContext);
|
|
18
|
+
const stepContext = useContext(StepContext);
|
|
19
|
+
if (!stepperContext || !stepContext) {
|
|
20
|
+
throw new Error('Stepper.Step must be rendered inside a Stepper.');
|
|
21
|
+
}
|
|
22
|
+
const { labelPosition } = stepperContext;
|
|
23
|
+
const { index, status, isLast } = stepContext;
|
|
24
|
+
const interactive = onClick !== undefined || href !== undefined;
|
|
25
|
+
const classes = stepperSlotRecipe({
|
|
26
|
+
labelPosition,
|
|
27
|
+
status,
|
|
28
|
+
interactive,
|
|
29
|
+
});
|
|
30
|
+
const indicatorContent = status === 'done' ? _jsx(DoneStepIcon, { "aria-hidden": true }) : _jsx("span", { "aria-hidden": true, children: index + 1 });
|
|
31
|
+
const labelVariant = status === 'current' ? 'strongBody' : 'body';
|
|
32
|
+
const inner = (_jsxs(_Fragment, { children: [_jsx("span", { className: cx(classes.indicator, 'mfui-Stepper__indicator'), "data-mfui-stepper-slot": "indicator", children: indicatorContent }), _jsx(Typography, { variant: labelVariant, className: cx(classes.label, 'mfui-Stepper__label'), "data-mfui-stepper-slot": "label", children: children })] }));
|
|
33
|
+
const ariaCurrent = status === 'current' ? 'step' : undefined;
|
|
34
|
+
const contentClassName = cx(classes.content, 'mfui-Stepper__content');
|
|
35
|
+
let contentElement;
|
|
36
|
+
if (!interactive) {
|
|
37
|
+
contentElement = (_jsx("div", { className: contentClassName, "aria-current": ariaCurrent, children: inner }));
|
|
38
|
+
}
|
|
39
|
+
else if (href !== undefined) {
|
|
40
|
+
const LinkTag = customLinkComponent ?? 'a';
|
|
41
|
+
contentElement = (_jsx(FocusIndicator, { children: createElement(LinkTag, { className: contentClassName, href, 'aria-current': ariaCurrent }, inner) }));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
contentElement = (_jsx(FocusIndicator, { children: _jsx("button", { type: "button", className: contentClassName, "aria-current": ariaCurrent, onClick: onClick, children: inner }) }));
|
|
45
|
+
}
|
|
46
|
+
return (_jsxs("li", { className: cx(classes.item, 'mfui-Stepper__item'), "data-mfui-is-last": isLast ? 'true' : undefined, "data-mfui-step-status": status, children: [contentElement, !isLast ? _jsx("span", { "aria-hidden": true, className: cx(classes.connector, 'mfui-Stepper__connector') }) : null] }));
|
|
47
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ElementType, type MouseEventHandler, type ReactNode } from 'react';
|
|
2
|
+
export type StepperStepProps = {
|
|
3
|
+
/** Step label content. */
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* When provided, the step renders as a `<button>` and triggers `onClick` when
|
|
7
|
+
* activated by mouse or keyboard. Ignored when `href` is also provided.
|
|
8
|
+
*/
|
|
9
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
10
|
+
/**
|
|
11
|
+
* When provided, the step renders as an `<a>` (or `customLinkComponent`) and
|
|
12
|
+
* navigates on activation.
|
|
13
|
+
*/
|
|
14
|
+
href?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Custom link component (e.g. Next.js `<Link>`). Only applied when `href` is
|
|
17
|
+
* also provided. Falls back to a plain `<a>` tag when omitted.
|
|
18
|
+
*/
|
|
19
|
+
customLinkComponent?: ElementType;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Step } from './Step';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type StepStatus = 'current' | 'done' | 'upcoming';
|
|
2
|
+
export type StepContextValue = {
|
|
3
|
+
/** 0-based step index. */
|
|
4
|
+
index: number;
|
|
5
|
+
/** Derived status of this step. */
|
|
6
|
+
status: StepStatus;
|
|
7
|
+
/** True when this step is the last in the list (no trailing connector). */
|
|
8
|
+
isLast: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare const StepContext: import("react").Context<StepContextValue | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Step } from './Step';
|
|
2
|
+
import { type StepperProps } from './Stepper.types';
|
|
3
|
+
declare function Base({ currentStepIndex, labelPosition, children, className, 'aria-label': ariaLabel, ...rest }: StepperProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
/**
|
|
5
|
+
* Stepper displays a wizard-style flow's overall steps and the user's current
|
|
6
|
+
* position within it. Steps are derived from `Stepper.Step` children, and each
|
|
7
|
+
* step's status (`done` / `current` / `upcoming`) is derived from
|
|
8
|
+
* `currentStepIndex`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <Stepper currentStepIndex={1}>
|
|
13
|
+
* <Stepper.Step>申請内容の入力</Stepper.Step>
|
|
14
|
+
* <Stepper.Step onClick={() => goto(1)}>内容の確認</Stepper.Step>
|
|
15
|
+
* <Stepper.Step>送信</Stepper.Step>
|
|
16
|
+
* </Stepper>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const Stepper: typeof Base & {
|
|
20
|
+
/**
|
|
21
|
+
* A single step. Use one `Stepper.Step` per step in the flow. Provide
|
|
22
|
+
* `onClick` or `href` to make the step interactive.
|
|
23
|
+
*/
|
|
24
|
+
Step: typeof Step;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Children, useMemo } from 'react';
|
|
4
|
+
import { cx } from '../../styled-system/css';
|
|
5
|
+
import { stepperSlotRecipe } from '../../styled-system/recipes';
|
|
6
|
+
import { StepperContext } from './StepperContext';
|
|
7
|
+
import { StepContext } from './StepContext';
|
|
8
|
+
import { Step } from './Step';
|
|
9
|
+
function deriveStatus(index, currentStepIndex) {
|
|
10
|
+
if (index < currentStepIndex)
|
|
11
|
+
return 'done';
|
|
12
|
+
if (index === currentStepIndex)
|
|
13
|
+
return 'current';
|
|
14
|
+
return 'upcoming';
|
|
15
|
+
}
|
|
16
|
+
function StepProvider({ index, status, isLast, children, }) {
|
|
17
|
+
const value = useMemo(() => ({ index, status, isLast }), [index, status, isLast]);
|
|
18
|
+
return _jsx(StepContext.Provider, { value: value, children: children });
|
|
19
|
+
}
|
|
20
|
+
function Base({ currentStepIndex, labelPosition = 'right', children, className, 'aria-label': ariaLabel = 'ステップ', ...rest }) {
|
|
21
|
+
const classes = stepperSlotRecipe({ labelPosition });
|
|
22
|
+
const stepperContextValue = useMemo(() => ({ labelPosition }), [labelPosition]);
|
|
23
|
+
// Filter out falsy children (booleans, null, undefined) so that conditional
|
|
24
|
+
// rendering of steps doesn't produce phantom indices.
|
|
25
|
+
const steps = Children.toArray(children);
|
|
26
|
+
return (_jsx(StepperContext.Provider, { value: stepperContextValue, children: _jsx("nav", { ...rest, className: cx(classes.root, 'mfui-Stepper__root', className), "aria-label": ariaLabel, children: _jsx("ol", { className: cx(classes.list, 'mfui-Stepper__list'), children: steps.map((child, index) => (_jsx(StepProvider, { index: index, status: deriveStatus(index, currentStepIndex), isLast: index === steps.length - 1, children: child }, index))) }) }) }));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Stepper displays a wizard-style flow's overall steps and the user's current
|
|
30
|
+
* position within it. Steps are derived from `Stepper.Step` children, and each
|
|
31
|
+
* step's status (`done` / `current` / `upcoming`) is derived from
|
|
32
|
+
* `currentStepIndex`.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <Stepper currentStepIndex={1}>
|
|
37
|
+
* <Stepper.Step>申請内容の入力</Stepper.Step>
|
|
38
|
+
* <Stepper.Step onClick={() => goto(1)}>内容の確認</Stepper.Step>
|
|
39
|
+
* <Stepper.Step>送信</Stepper.Step>
|
|
40
|
+
* </Stepper>
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const Stepper = Object.assign(Base, {
|
|
44
|
+
/**
|
|
45
|
+
* A single step. Use one `Stepper.Step` per step in the flow. Provide
|
|
46
|
+
* `onClick` or `href` to make the step interactive.
|
|
47
|
+
*/
|
|
48
|
+
Step,
|
|
49
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
2
|
+
export type StepperLabelPosition = 'right' | 'bottom';
|
|
3
|
+
export type StepperProps = {
|
|
4
|
+
/**
|
|
5
|
+
* 0-based index of the current step.
|
|
6
|
+
* Steps before this index are rendered as `done`, the step at this index
|
|
7
|
+
* is `current`, and steps after are `upcoming`.
|
|
8
|
+
*/
|
|
9
|
+
currentStepIndex: number;
|
|
10
|
+
/**
|
|
11
|
+
* Position of each step's label relative to its indicator.
|
|
12
|
+
*
|
|
13
|
+
* - `right` (default): label sits to the right of the indicator on the same line.
|
|
14
|
+
* - `bottom`: label is centered directly below the indicator.
|
|
15
|
+
*
|
|
16
|
+
* @default 'right'
|
|
17
|
+
*/
|
|
18
|
+
labelPosition?: StepperLabelPosition;
|
|
19
|
+
/** `Stepper.Step` elements. */
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
} & Omit<ComponentPropsWithoutRef<'nav'>, 'children'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Stepper } from './Stepper';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef, useId, useRef, isValidElement, cloneElement, useEffect } from 'react';
|
|
3
|
+
import { forwardRef, useId, useRef, isValidElement, cloneElement, useEffect, useMemo } from 'react';
|
|
4
4
|
import { getOverflowAncestors } from '@floating-ui/react-dom';
|
|
5
5
|
import { cx } from '../../styled-system/css';
|
|
6
6
|
import { tooltipSlotRecipe } from '../../styled-system/recipes';
|
|
7
7
|
import { Typography } from '../Typography';
|
|
8
8
|
import { mergeRefs } from '../utilities/dom/mergeRefs';
|
|
9
|
+
import { useOnClickOutside } from '../utilities/dom/useOnClickOutside';
|
|
9
10
|
import { useTooltipDisplayController } from './hooks/useTooltipDisplayController';
|
|
10
11
|
import { ArrowIcon } from './icons/ArrowIcon';
|
|
11
12
|
import { usePopoverController } from './hooks/usePopoverController';
|
|
@@ -46,11 +47,12 @@ export const DEFAULT_MAX_WIDTH = '268px';
|
|
|
46
47
|
export const Tooltip = forwardRef(({ children, open, onOpenStateChanged, content, targetDOMNode, placement, trigger = ['hover', 'focus'], disabled = false, hideFromScreenReader = false, maxWidth = DEFAULT_MAX_WIDTH, className, contentProps, ...wrapperProps }, ref) => {
|
|
47
48
|
const rootRef = useRef(null);
|
|
48
49
|
const arrowRef = useRef(null);
|
|
50
|
+
const tooltipRef = useRef(null);
|
|
49
51
|
const tooltipId = useId();
|
|
50
52
|
// Use automatic target resolution matching Portal.tsx pattern
|
|
51
53
|
// Resolution order: explicit prop → parent context → document.body fallback
|
|
52
54
|
const targetElement = useAutomaticTargetDomNode(targetDOMNode, rootRef.current);
|
|
53
|
-
const { open: calculatedOpen, rootAttributes, tooltipAttributes, closeImmediate, } = useTooltipDisplayController({
|
|
55
|
+
const { open: calculatedOpen, rootAttributes, tooltipAttributes, closeImmediate, closeWithManager, } = useTooltipDisplayController({
|
|
54
56
|
trigger,
|
|
55
57
|
wrapperProps,
|
|
56
58
|
tooltipOpen: open,
|
|
@@ -77,6 +79,13 @@ export const Tooltip = forwardRef(({ children, open, onOpenStateChanged, content
|
|
|
77
79
|
});
|
|
78
80
|
};
|
|
79
81
|
}, [calculatedOpen, closeImmediate]);
|
|
82
|
+
const hasClickTrigger = useMemo(() => (Array.isArray(trigger) ? trigger : [trigger]).includes('click'), [trigger]);
|
|
83
|
+
// Skip the trigger (rootRef) so the existing onClick toggle handles re-clicks —
|
|
84
|
+
// closing here would race with onClick and immediately reopen the tooltip.
|
|
85
|
+
useOnClickOutside(rootRef, closeWithManager, {
|
|
86
|
+
ignoreRefs: [tooltipRef],
|
|
87
|
+
disabled: !calculatedOpen || !hasClickTrigger || open !== undefined,
|
|
88
|
+
});
|
|
80
89
|
const triggerRef = mergeRefs(setTriggerReference, rootRef, ref);
|
|
81
90
|
const classes = tooltipSlotRecipe();
|
|
82
91
|
const ariaDescribedBy = !hideFromScreenReader && content != null ? tooltipId : undefined;
|
|
@@ -90,5 +99,5 @@ export const Tooltip = forwardRef(({ children, open, onOpenStateChanged, content
|
|
|
90
99
|
clip: 'rect(0, 0, 0, 0)',
|
|
91
100
|
whiteSpace: 'nowrap',
|
|
92
101
|
borderWidth: 0,
|
|
93
|
-
}, children: content }) })), calculatedOpen ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: setTooltipReference, className: cx(classes.tooltip, 'mfui-Tooltip__tooltip', contentProps?.className), role: "tooltip", id: tooltipId, "aria-hidden": hideFromScreenReader ? true : undefined, style: { maxWidth, ...tooltipStyles }, ...tooltipAttributes, children: [typeof content === 'string' ? _jsx(Typography, { variant: "helpMessage", children: content }) : content, _jsx(ArrowIcon, { ref: arrowRef, "aria-hidden": true, placement: calculatedPlacement, className: cx(classes.arrow, 'mfui-Tooltip__arrow'), style: arrowStyles })] }) })) : null] }));
|
|
102
|
+
}, children: content }) })), calculatedOpen ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: mergeRefs(setTooltipReference, tooltipRef), className: cx(classes.tooltip, 'mfui-Tooltip__tooltip', contentProps?.className), role: "tooltip", id: tooltipId, "aria-hidden": hideFromScreenReader ? true : undefined, style: { maxWidth, ...tooltipStyles }, ...tooltipAttributes, children: [typeof content === 'string' ? _jsx(Typography, { variant: "helpMessage", children: content }) : content, _jsx(ArrowIcon, { ref: arrowRef, "aria-hidden": true, placement: calculatedPlacement, className: cx(classes.arrow, 'mfui-Tooltip__arrow'), style: arrowStyles })] }) })) : null] }));
|
|
94
103
|
});
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import type { ConditionalValue } from '../types/index';
|
|
|
3
3
|
import type { DistributiveOmit, Pretty } from '../types/system-types';
|
|
4
4
|
|
|
5
5
|
interface FormFooterSlotRecipeVariant {
|
|
6
|
-
position: "stacking" | "
|
|
6
|
+
position: "stacking" | "sticky"
|
|
7
7
|
sectionPosition: "center" | "fill"
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -54,6 +54,7 @@ export * from './data-table-row-slot-recipe';
|
|
|
54
54
|
export * from './sub-navigation-slot-recipe';
|
|
55
55
|
export * from './progress-indicator-slot-recipe';
|
|
56
56
|
export * from './stack-slot-recipe';
|
|
57
|
+
export * from './stepper-slot-recipe';
|
|
57
58
|
export * from './multiple-select-box-slot-recipe';
|
|
58
59
|
export * from './multiple-select-box-trigger-recipe';
|
|
59
60
|
export * from './checkbox-card-slot-recipe';
|
|
@@ -53,6 +53,7 @@ export * from './data-table-row-slot-recipe.js';
|
|
|
53
53
|
export * from './sub-navigation-slot-recipe.js';
|
|
54
54
|
export * from './progress-indicator-slot-recipe.js';
|
|
55
55
|
export * from './stack-slot-recipe.js';
|
|
56
|
+
export * from './stepper-slot-recipe.js';
|
|
56
57
|
export * from './multiple-select-box-slot-recipe.js';
|
|
57
58
|
export * from './multiple-select-box-trigger-recipe.js';
|
|
58
59
|
export * from './checkbox-card-slot-recipe.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import type { ConditionalValue } from '../types/index';
|
|
3
|
+
import type { DistributiveOmit, Pretty } from '../types/system-types';
|
|
4
|
+
|
|
5
|
+
interface StepperSlotRecipeVariant {
|
|
6
|
+
/**
|
|
7
|
+
* @default "right"
|
|
8
|
+
*/
|
|
9
|
+
labelPosition: "right" | "bottom"
|
|
10
|
+
/**
|
|
11
|
+
* @default "upcoming"
|
|
12
|
+
*/
|
|
13
|
+
status: "current" | "done" | "upcoming"
|
|
14
|
+
/**
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
interactive: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type StepperSlotRecipeVariantMap = {
|
|
21
|
+
[key in keyof StepperSlotRecipeVariant]: Array<StepperSlotRecipeVariant[key]>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type StepperSlotRecipeSlot = "root" | "list" | "item" | "content" | "indicator" | "label" | "connector"
|
|
25
|
+
|
|
26
|
+
export type StepperSlotRecipeVariantProps = {
|
|
27
|
+
[key in keyof StepperSlotRecipeVariant]?: StepperSlotRecipeVariant[key] | undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface StepperSlotRecipeRecipe {
|
|
31
|
+
__slot: StepperSlotRecipeSlot
|
|
32
|
+
__type: StepperSlotRecipeVariantProps
|
|
33
|
+
(props?: StepperSlotRecipeVariantProps): Pretty<Record<StepperSlotRecipeSlot, string>>
|
|
34
|
+
raw: (props?: StepperSlotRecipeVariantProps) => StepperSlotRecipeVariantProps
|
|
35
|
+
variantMap: StepperSlotRecipeVariantMap
|
|
36
|
+
variantKeys: Array<keyof StepperSlotRecipeVariant>
|
|
37
|
+
splitVariantProps<Props extends StepperSlotRecipeVariantProps>(props: Props): [StepperSlotRecipeVariantProps, Pretty<DistributiveOmit<Props, keyof StepperSlotRecipeVariantProps>>]
|
|
38
|
+
getVariantProps: (props?: StepperSlotRecipeVariantProps) => StepperSlotRecipeVariantProps
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Slot class created for the MFUI Stepper component.
|
|
43
|
+
*/
|
|
44
|
+
export declare const stepperSlotRecipe: StepperSlotRecipeRecipe
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { compact, getSlotCompoundVariant, memo, splitProps } from '../helpers.js';
|
|
2
|
+
import { createRecipe } from './create-recipe.js';
|
|
3
|
+
const stepperSlotRecipeDefaultVariants = {
|
|
4
|
+
"labelPosition": "right",
|
|
5
|
+
"status": "upcoming",
|
|
6
|
+
"interactive": false
|
|
7
|
+
};
|
|
8
|
+
const stepperSlotRecipeCompoundVariants = [
|
|
9
|
+
{
|
|
10
|
+
"status": "done",
|
|
11
|
+
"interactive": true,
|
|
12
|
+
"css": {
|
|
13
|
+
"content": {
|
|
14
|
+
"&:hover > [data-mfui-stepper-slot=\"indicator\"], &:focus-visible > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
15
|
+
"backgroundColor": "mfui.color.primary.content.hovered"
|
|
16
|
+
},
|
|
17
|
+
"&:active > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
18
|
+
"backgroundColor": "mfui.color.primary.content.pressed"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"status": "current",
|
|
25
|
+
"interactive": true,
|
|
26
|
+
"css": {
|
|
27
|
+
"content": {
|
|
28
|
+
"&:hover > [data-mfui-stepper-slot=\"indicator\"], &:focus-visible > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
29
|
+
"backgroundColor": "mfui.color.primary.content.hovered"
|
|
30
|
+
},
|
|
31
|
+
"&:active > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
32
|
+
"backgroundColor": "mfui.color.primary.content.pressed"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"status": "upcoming",
|
|
39
|
+
"interactive": true,
|
|
40
|
+
"css": {
|
|
41
|
+
"content": {
|
|
42
|
+
"&:hover > [data-mfui-stepper-slot=\"indicator\"], &:focus-visible > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
43
|
+
"backgroundColor": "mfui.color.neutral.sub-background.hovered",
|
|
44
|
+
"color": "mfui.color.neutral.content.hovered"
|
|
45
|
+
},
|
|
46
|
+
"&:active > [data-mfui-stepper-slot=\"indicator\"]": {
|
|
47
|
+
"backgroundColor": "mfui.color.neutral.sub-background.pressed",
|
|
48
|
+
"color": "mfui.color.neutral.content.pressed"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
const stepperSlotRecipeSlotNames = [
|
|
55
|
+
[
|
|
56
|
+
"root",
|
|
57
|
+
"Stepper__root"
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"list",
|
|
61
|
+
"Stepper__list"
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"item",
|
|
65
|
+
"Stepper__item"
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
"content",
|
|
69
|
+
"Stepper__content"
|
|
70
|
+
],
|
|
71
|
+
[
|
|
72
|
+
"indicator",
|
|
73
|
+
"Stepper__indicator"
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"label",
|
|
77
|
+
"Stepper__label"
|
|
78
|
+
],
|
|
79
|
+
[
|
|
80
|
+
"connector",
|
|
81
|
+
"Stepper__connector"
|
|
82
|
+
]
|
|
83
|
+
];
|
|
84
|
+
const stepperSlotRecipeSlotFns = /* @__PURE__ */ stepperSlotRecipeSlotNames.map(([slotName, slotKey]) => [slotName, createRecipe(slotKey, stepperSlotRecipeDefaultVariants, getSlotCompoundVariant(stepperSlotRecipeCompoundVariants, slotName))]);
|
|
85
|
+
const stepperSlotRecipeFn = memo((props = {}) => {
|
|
86
|
+
return Object.fromEntries(stepperSlotRecipeSlotFns.map(([slotName, slotFn]) => [slotName, slotFn.recipeFn(props)]));
|
|
87
|
+
});
|
|
88
|
+
const stepperSlotRecipeVariantKeys = [
|
|
89
|
+
"labelPosition",
|
|
90
|
+
"status",
|
|
91
|
+
"interactive"
|
|
92
|
+
];
|
|
93
|
+
const getVariantProps = (variants) => ({ ...stepperSlotRecipeDefaultVariants, ...compact(variants) });
|
|
94
|
+
export const stepperSlotRecipe = /* @__PURE__ */ Object.assign(stepperSlotRecipeFn, {
|
|
95
|
+
__recipe__: false,
|
|
96
|
+
__name__: 'stepperSlotRecipe',
|
|
97
|
+
raw: (props) => props,
|
|
98
|
+
classNameMap: {},
|
|
99
|
+
variantKeys: stepperSlotRecipeVariantKeys,
|
|
100
|
+
variantMap: {
|
|
101
|
+
"labelPosition": [
|
|
102
|
+
"right",
|
|
103
|
+
"bottom"
|
|
104
|
+
],
|
|
105
|
+
"status": [
|
|
106
|
+
"current",
|
|
107
|
+
"done",
|
|
108
|
+
"upcoming"
|
|
109
|
+
],
|
|
110
|
+
"interactive": [
|
|
111
|
+
"true"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
splitVariantProps(props) {
|
|
115
|
+
return splitProps(props, stepperSlotRecipeVariantKeys);
|
|
116
|
+
},
|
|
117
|
+
getVariantProps
|
|
118
|
+
});
|