1- " use client" ;
1+ ' use client' ;
22
33/**
44 * Component: StepConnector / StepComponent
2727 * - --rail-x, --circle, --gap control rail position and circle size/spacing.
2828 */
2929
30- import { useEffect , useMemo , useRef , useState } from "react" ;
31- import styles from "./style.module.scss" ;
30+ import { useEffect , useMemo , useRef , useState } from 'react' ;
3231
33- type Persistence = "session" | "none" ;
32+ import styles from './style.module.scss' ;
33+
34+ type Persistence = 'session' | 'none' ;
3435
3536type Props = {
3637 children : React . ReactNode ;
37- /** Start numbering from this value. @defaultValue 1 */
38- startAt ?: number ;
39- /** Which heading level to connect (CSS selector). @defaultValue 'h2' */
40- selector ?: string ;
41- /** Show numeric labels inside circles. Set false for blank circles. @defaultValue true */
42- showNumbers ?: boolean ;
4338 /** Allow users to check off steps (circle becomes a button). @defaultValue false */
4439 checkable ?: boolean ;
4540 /** Completion storage: 'session' | 'none'. @defaultValue 'session' */
4641 persistence ?: Persistence ;
42+ /** Which heading level to connect (CSS selector). @defaultValue 'h2' */
43+ selector ?: string ;
44+ /** Show numeric labels inside circles. Set false for blank circles. @defaultValue true */
45+ showNumbers ?: boolean ;
4746 /** Show a small "Reset steps" action when checkable. @defaultValue true */
4847 showReset ?: boolean ;
48+ /** Start numbering from this value. @defaultValue 1 */
49+ startAt ?: number ;
4950} ;
5051
5152export function StepComponent ( {
5253 children,
5354 startAt = 1 ,
54- selector = "h2" ,
55+ selector = 'h2' ,
5556 showNumbers = true ,
5657 checkable = false ,
57- persistence = " session" ,
58+ persistence = ' session' ,
5859 showReset = true ,
5960} : Props ) {
6061 const containerRef = useRef < HTMLDivElement | null > ( null ) ;
6162 const [ completed , setCompleted ] = useState < Set < string > > ( new Set ( ) ) ;
6263
6364 const storageKey = useMemo ( ( ) => {
64- if ( typeof window === " undefined" || persistence !== " session" ) return null ;
65+ if ( typeof window === ' undefined' || persistence !== ' session' ) return null ;
6566 try {
66- const path = window . location ?. pathname ?? "" ;
67+ const path = window . location ?. pathname ?? '' ;
6768 return `stepConnector:${ path } :${ selector } :${ startAt } ` ;
6869 } catch {
6970 return null ;
@@ -83,24 +84,24 @@ export function StepComponent({
8384
8485 headings . forEach ( h => {
8586 h . classList . remove ( styles . stepHeading ) ;
86- h . removeAttribute ( " data-step" ) ;
87- h . removeAttribute ( " data-completed" ) ;
87+ h . removeAttribute ( ' data-step' ) ;
88+ h . removeAttribute ( ' data-completed' ) ;
8889 const existingToggle = h . querySelector ( `.${ styles . stepToggle } ` ) ;
8990 if ( existingToggle ) existingToggle . remove ( ) ;
9091 } ) ;
9192
9293 headings . forEach ( ( h , idx ) => {
9394 const stepNumber = startAt + idx ;
94- h . setAttribute ( " data-step" , String ( stepNumber ) ) ;
95+ h . setAttribute ( ' data-step' , String ( stepNumber ) ) ;
9596 h . classList . add ( styles . stepHeading ) ;
9697
9798 if ( checkable ) {
98- const btn = document . createElement ( " button" ) ;
99- btn . type = " button" ;
99+ const btn = document . createElement ( ' button' ) ;
100+ btn . type = ' button' ;
100101 btn . className = styles . stepToggle ;
101- btn . setAttribute ( " aria-label" , `Toggle completion for step ${ stepNumber } ` ) ;
102- btn . setAttribute ( " aria-pressed" , completed . has ( h . id ) ? " true" : " false" ) ;
103- btn . addEventListener ( " click" , ( ) => {
102+ btn . setAttribute ( ' aria-label' , `Toggle completion for step ${ stepNumber } ` ) ;
103+ btn . setAttribute ( ' aria-pressed' , completed . has ( h . id ) ? ' true' : ' false' ) ;
104+ btn . addEventListener ( ' click' , ( ) => {
104105 setCompleted ( prev => {
105106 const next = new Set ( prev ) ;
106107 if ( next . has ( h . id ) ) next . delete ( h . id ) ;
@@ -116,8 +117,8 @@ export function StepComponent({
116117 return ( ) => {
117118 headings . forEach ( h => {
118119 h . classList . remove ( styles . stepHeading ) ;
119- h . removeAttribute ( " data-step" ) ;
120- h . removeAttribute ( " data-completed" ) ;
120+ h . removeAttribute ( ' data-step' ) ;
121+ h . removeAttribute ( ' data-completed' ) ;
121122 const existingToggle = h . querySelector ( `.${ styles . stepToggle } ` ) ;
122123 if ( existingToggle ) existingToggle . remove ( ) ;
123124 } ) ;
@@ -144,10 +145,10 @@ export function StepComponent({
144145 ) ;
145146 headings . forEach ( h => {
146147 const isDone = completed . has ( h . id ) ;
147- if ( isDone ) h . setAttribute ( " data-completed" , " true" ) ;
148- else h . removeAttribute ( " data-completed" ) ;
148+ if ( isDone ) h . setAttribute ( ' data-completed' , ' true' ) ;
149+ else h . removeAttribute ( ' data-completed' ) ;
149150 const btn = h . querySelector ( `.${ styles . stepToggle } ` ) as HTMLButtonElement | null ;
150- if ( btn ) btn . setAttribute ( " aria-pressed" , isDone ? " true" : " false" ) ;
151+ if ( btn ) btn . setAttribute ( ' aria-pressed' , isDone ? ' true' : ' false' ) ;
151152 } ) ;
152153
153154 if ( storageKey && checkable ) {
@@ -174,7 +175,7 @@ export function StepComponent({
174175 < div
175176 ref = { containerRef }
176177 className = { styles . stepContainer }
177- data-shownumbers = { showNumbers ? " true" : " false" }
178+ data-shownumbers = { showNumbers ? ' true' : ' false' }
178179 >
179180 { checkable && showReset && (
180181 < div className = { styles . resetRow } >
@@ -192,4 +193,3 @@ export function StepComponent({
192193export function StepConnector ( props : Props ) {
193194 return < StepComponent { ...props } /> ;
194195}
195-
0 commit comments