@spark-web/vertical-stepper
Version:
--- title: Vertical Stepper storybookPath: data-display-vertical-stepper isExperimentalPackage: true ---
327 lines (317 loc) • 10.3 kB
JavaScript
import _taggedTemplateLiteral from '@babel/runtime/helpers/esm/taggedTemplateLiteral';
import { css } from '@emotion/react';
import { Box } from '@spark-web/box';
import { Stack } from '@spark-web/stack';
import { useTheme } from '@spark-web/theme';
import React, { useMemo, useContext, createContext } from 'react';
import { jsx, jsxs } from '@emotion/react/jsx-runtime';
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray';
import { useSpring, animated, a } from '@react-spring/web';
import useMeasure from 'react-use-measure';
import { Heading } from '@spark-web/heading';
import { CheckIcon } from '@spark-web/icon';
import { Text } from '@spark-web/text';
var StepperContext = /*#__PURE__*/createContext(null);
var StepperProvider = function StepperProvider(_ref) {
var activeIndex = _ref.activeIndex,
children = _ref.children;
return jsx(StepperContext.Provider, {
value: useMemo(function () {
return {
activeIndex: activeIndex
};
}, [activeIndex]),
children: children
});
};
var StepContext = /*#__PURE__*/createContext(null);
var StepProvider = function StepProvider(_ref2) {
var stepIndex = _ref2.stepIndex,
isActive = _ref2.isActive,
isCompleted = _ref2.isCompleted,
children = _ref2.children;
return jsx(StepContext.Provider, {
value: useMemo(function () {
return {
stepIndex: stepIndex,
isActive: isActive,
isCompleted: isCompleted
};
}, [stepIndex, isActive, isCompleted]),
children: children
});
};
var useStep = function useStep() {
var context = useContext(StepContext);
if (!context) {
throw new Error('useStep must be used within a <Step />');
}
return context;
};
var getProgressBackground = function getProgressBackground(_ref) {
var isCompleted = _ref.isCompleted,
isActive = _ref.isActive;
return isCompleted ? 'secondaryLow' : isActive ? 'primary' : 'inputPressed';
};
var STEP_LABEL_CIRCLE_SIZE = 28;
var StepCompletedContent = function StepCompletedContent(_ref) {
var children = _ref.children,
render = _ref.render;
var _useStep = useStep(),
isCompleted = _useStep.isCompleted,
stepIndex = _useStep.stepIndex;
var theme = useTheme();
var _useMeasure = useMeasure(),
_useMeasure2 = _slicedToArray(_useMeasure, 2),
completedContentRef = _useMeasure2[0],
completedContentViewHeight = _useMeasure2[1].height;
var activeContentAnimatedStyle = useSpring({
from: {
height: 0,
opacity: 0
},
to: {
height: isCompleted ? completedContentViewHeight : 0,
opacity: isCompleted ? 1 : 0
},
config: {
tension: 210,
friction: 20,
bounce: 0
}
});
return jsx(animated.div, {
style: _objectSpread(_objectSpread({}, activeContentAnimatedStyle), {}, {
paddingLeft: STEP_LABEL_CIRCLE_SIZE + theme.spacing.medium
}),
children: jsx(a.div, {
ref: completedContentRef,
children: render ? render({
stepIndex: stepIndex
}) : children
})
});
};
var StepContent = function StepContent(_ref) {
var children = _ref.children,
render = _ref.render;
var _useStep = useStep(),
isActive = _useStep.isActive,
stepIndex = _useStep.stepIndex;
var theme = useTheme();
var _useMeasure = useMeasure(),
_useMeasure2 = _slicedToArray(_useMeasure, 2),
activeContentRef = _useMeasure2[0],
activeContentViewHeight = _useMeasure2[1].height;
var activeContentAnimatedStyle = useSpring({
from: {
height: 0,
opacity: 0
},
to: {
height: isActive ? activeContentViewHeight : 0,
opacity: isActive ? 1 : 0
},
config: {
tension: 210,
friction: 20,
bounce: 0
}
});
return jsx(animated.div, {
style: _objectSpread(_objectSpread({}, activeContentAnimatedStyle), {}, {
paddingLeft: STEP_LABEL_CIRCLE_SIZE + theme.spacing.medium
}),
children: jsx(a.div, {
ref: activeContentRef,
children: render ? render({
stepIndex: stepIndex
}) : children
})
});
};
var StepDescription = function StepDescription(_ref) {
var children = _ref.children,
render = _ref.render;
var _useStep = useStep(),
isActive = _useStep.isActive,
stepIndex = _useStep.stepIndex;
var theme = useTheme();
var _useMeasure = useMeasure(),
_useMeasure2 = _slicedToArray(_useMeasure, 2),
activeContentRef = _useMeasure2[0],
activeContentViewHeight = _useMeasure2[1].height;
var activeContentAnimatedStyle = useSpring({
from: {
height: 0,
opacity: 0
},
to: {
height: isActive ? 0 : activeContentViewHeight,
opacity: isActive ? 0 : 1
},
config: {
tension: 210,
friction: 20,
bounce: 0
}
});
return jsx(animated.div, {
style: _objectSpread(_objectSpread({}, activeContentAnimatedStyle), {}, {
paddingLeft: STEP_LABEL_CIRCLE_SIZE + theme.spacing.medium
}),
children: jsx(a.div, {
ref: activeContentRef,
children: render ? render({
stepIndex: stepIndex
}) : children
})
});
};
var _templateObject$1;
var StepHeading = function StepHeading(_ref) {
var title = _ref.title,
actionButton = _ref.actionButton,
renderActionButton = _ref.renderActionButton,
renderStepNumber = _ref.renderStepNumber;
var _useStep = useStep(),
isActive = _useStep.isActive,
isCompleted = _useStep.isCompleted,
stepIndex = _useStep.stepIndex;
var progressBackground = getProgressBackground({
isCompleted: isCompleted,
isActive: isActive
});
var displayStepNumber = function displayStepNumber() {
if (renderStepNumber) {
return renderStepNumber({
isActive: isActive,
stepIndex: stepIndex
});
}
return jsx(Text, {
size: "xsmall",
tone: isActive ? 'neutral' : 'muted',
weight: "semibold",
children: stepIndex + 1
});
};
return jsxs(Box, {
display: "flex",
flexDirection: "row",
gap: "medium",
alignItems: "center",
children: [jsx(Box, {
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
background: progressBackground,
css: css(_templateObject$1 || (_templateObject$1 = _taggedTemplateLiteral(["\n width: ", "px;\n height: ", "px;\n border-radius: 50%;\n "])), STEP_LABEL_CIRCLE_SIZE, STEP_LABEL_CIRCLE_SIZE),
children: isCompleted ? jsx(CheckIcon, {
size: "xxsmall",
tone: "primary"
}) : displayStepNumber()
}), jsxs(Box, {
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "spaceBetween",
gap: "small",
height: "small",
width: "full",
children: [jsx(Heading, {
level: "3",
tone: isActive || isCompleted ? 'primary' : 'muted',
children: title
}), renderActionButton ? renderActionButton({
isCompleted: isCompleted,
isActive: isActive,
stepIndex: stepIndex
}) : actionButton]
})]
});
};
var _templateObject;
var getStepComponents = function getStepComponents(children) {
var stepHeading = null;
var stepContent = null;
var stepCompletedContent = null;
var stepDescription = null;
React.Children.map(children, function (child) {
if ( /*#__PURE__*/React.isValidElement(child)) {
if (child.type === StepHeading) {
stepHeading = child;
} else if (child.type === StepContent) {
stepContent = child;
} else if (child.type === StepCompletedContent) {
stepCompletedContent = child;
} else if (child.type === StepDescription) {
stepDescription = child;
}
}
});
return {
stepHeading: stepHeading,
stepContent: stepContent,
stepCompletedContent: stepCompletedContent,
stepDescription: stepDescription
};
};
var Step = function Step(_ref) {
var children = _ref.children;
var _useStep = useStep(),
isActive = _useStep.isActive,
isCompleted = _useStep.isCompleted;
var theme = useTheme();
var _getStepComponents = getStepComponents(children),
stepHeading = _getStepComponents.stepHeading,
stepContent = _getStepComponents.stepContent,
stepCompletedContent = _getStepComponents.stepCompletedContent,
stepDescription = _getStepComponents.stepDescription;
var progressBackground = getProgressBackground({
isCompleted: isCompleted,
isActive: isActive
});
return jsx(Box, {
position: "relative",
paddingBottom: "xsmall",
css: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n &:not(:last-child) {\n &:after {\n content: '';\n position: absolute;\n left: 13px;\n top: ", "px;\n bottom: 0px;\n z-index: 1;\n width: 3px;\n background-color: ", ";\n }\n }\n "])), STEP_LABEL_CIRCLE_SIZE, progressBackground ? theme.color.background[progressBackground] : 'initial'),
children: jsxs(Stack, {
gap: "medium",
children: [stepHeading, isActive && stepContent, isCompleted && stepCompletedContent, !isActive && !isCompleted && stepDescription]
})
});
};
Step.Heading = StepHeading;
Step.Content = StepContent;
Step.CompletedContent = StepCompletedContent;
Step.Description = StepDescription;
var VerticalStepper = function VerticalStepper(_ref) {
var children = _ref.children,
activeIndex = _ref.activeIndex;
var childArray = React.Children.toArray(children);
return jsx(StepperProvider, {
activeIndex: activeIndex,
children: jsx(Box, {
display: "flex",
flexDirection: "column",
gap: "small",
children: childArray.map(function (child, index) {
if ( /*#__PURE__*/React.isValidElement(child)) {
var active = index === activeIndex;
var completed = index < activeIndex;
return jsx(StepProvider, {
stepIndex: index,
isActive: active,
isCompleted: completed,
children: child
}, "step-".concat(index));
}
return null;
})
})
});
};
export { Step, VerticalStepper };