All files / atoms/Stepper/mobile Stepper.native.tsx

100% Statements 39/39
95.12% Branches 39/41
100% Functions 5/5
100% Lines 31/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120            1x   1x                           6x   6x 6x 1x       6x 6x 6x 6x   6x         6x 6x   6x 13x 12x 11x 9x 5x     6x             13x 13x 13x 13x 13x 13x 13x 13x 13x             1x                                                   1x                                        
import React, { useEffect } from 'react';
import { View, Text, StyleSheet, Pressable } from 'react-native';
import type { StepperProps } from '../Stepper.types';
import { useTheme } from '../../../Themes/ThemeProvider';
import { colors as coloring } from '@sb/styles/colors';
 
const SEGMENT_GAP = 4;
 
const Stepper: React.FC<StepperProps> = ({
  id,
  steps,
  currentStep,
  onStepChange,
  readonly = false,
  header,
  extraSpacing = false,
  errorColor,
  activeColor,
  completedColor,
  stepSize = 'medium',
  forceErrorTest = false,
}) => {
  const stepCount = steps.length;
 
  useEffect(() => {
    if (stepCount < 1) {
      console.warn('Stepper requires at least one step.');
    }
  }, [stepCount]);
 
  const { theme } = useTheme();
  const finalErrorColor = errorColor || coloring[theme].colorStatus_Error;
  const finalActiveColor = activeColor || coloring[theme].colorAccent;
  const finalCompletedColor = completedColor || coloring[theme].colorAccent;
 
  const thicknessMap: Record<'small' | 'medium' | 'large', number> = {
    small: 2,
    medium: 4,
    large: 6,
  };
  const segmentThickness = thicknessMap[stepSize];
  const spacingMargin = extraSpacing ? 38 : 8;
 
  const getSegmentColor = (i: number): string => {
    if (forceErrorTest && i === currentStep) return finalErrorColor;
    if (steps[i].status === 'error') return finalErrorColor;
    if (i < currentStep) return finalCompletedColor;
    if (i === currentStep) return finalActiveColor;
    return coloring[theme].colorStepperFallback;
  };
 
  return (
    <View testID={id} style={[styles.container]}>
      <View
        accessibilityRole="tablist"
        style={[styles.segmentContainer, { marginBottom: spacingMargin }]}
      >
        {steps.map((_, i) => {
          const color = getSegmentColor(i);
          const isLast = i === stepCount - 1;
          const isFirst = i === 0;
          const isSelected = i === currentStep;
          let label = `Step ${i + 1}`;
          if (isFirst) label += ', First step';
          if (isLast) label += ', Final step';
          if (isSelected) label += ', Selected';
          return (
            <Pressable
              key={`segment-${i}`}
              accessibilityRole="tab"
              accessibilityLabel={label}
              accessibilityState={{ disabled: readonly, selected: isSelected }}
              onPress={() => {
                Eif (!readonly && onStepChange) onStepChange(i);
              }}
              disabled={readonly}
              style={[
                styles.segment,
                {
                  height: segmentThickness,
                  backgroundColor: color,
                  marginRight: isLast ? 0 : SEGMENT_GAP,
                },
              ]}
            />
          );
        })}
      </View>
      {header && typeof header === 'string' && header.length ? (
        <Text style={[styles.headerText, { color: coloring[theme].colorLoader_Text }]}>
          {header}
        </Text>
      ) : (
        header
      )}
    </View>
  );
};
 
const styles = StyleSheet.create({
  container: {
    width: '100%',
    flexDirection: 'column',
    alignItems: 'flex-start',
  },
  segmentContainer: {
    flexDirection: 'row',
    width: '100%',
  },
  segment: {
    flex: 1,
  },
  headerText: {
    fontWeight: 'bold',
    textAlign: 'left',
  },
});
 
export default Stepper;