UNPKG

@spark-web/vertical-stepper

Version:

--- title: Vertical Stepper storybookPath: data-display-vertical-stepper isExperimentalPackage: true ---

327 lines (317 loc) 10.3 kB
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 };