React Stepper 개요
React Stepper Component는 마법사와 같은 워크플로를 제공하며 번호가 매겨진 단계를 통해 진행 상황을 표시하는 데 사용됩니다. 개발자는 긴 콘텐츠를 일련의 논리적 단계로 나누어 최종 사용자가 전체 프로세스를 더 쉽게 탐색할 수 있도록 돕습니다. React Stepper는 수직 또는 수평 선으로 표시됩니다. React Stepper에는 단계 검증, 스타일링, 방향 및 키보드 탐색과 같은 여러 기능이 있습니다.
React Stepper 예제
아래의 Ignite UI for React 스테퍼 예제는 작동 중인 구성 요소를 보여줍니다. 최종 사용자가 몇 가지 연속 단계에 따라 주문 세부 정보를 구성하기 위해 거쳐야 하는 프로세스를 시각화합니다.
import React from "react" ;
import ReactDOM from "react-dom/client" ;
import "./index.css" ;
import {
IgrStepper,
IgrStep,
IgrRadio,
IgrRadioGroup,
IgrButton,
IgrSwitch,
IgrCheckboxChangeEventArgs,
IgrComponentValueChangedEventArgs,
IgrInput,
} from "@infragistics/igniteui-react" ;
import "igniteui-webcomponents/themes/light/bootstrap.css" ;
export default class LinearStepper extends React.Component <any, any> {
private stepperRef = React .createRef<IgrStepper > ();
private InfoForm = React .createRef<any > ();
private AddressForm = React .createRef<any > ();
private activeStepIndex = 0 ;
constructor (props: any ) {
super (props);
this .state = {
linear: false ,
firstStepInvalid: true ,
secondStepInvalid: true ,
};
this .onSwitchChange = this .onSwitchChange.bind(this );
}
componentDidMount() {
this .InfoForm.current.addEventListener("igcInput" , this .onInput.bind(this ));
this .AddressForm.current.addEventListener(
"igcInput" ,
this .onInput.bind(this )
);
}
public render (): JSX .Element {
return (
<div className ="container sample" >
<IgrSwitch onChange ={this.onSwitchChange} >
<span > Linear</span >
</IgrSwitch >
<IgrStepper ref ={this.stepperRef} linear ={this.state.linear} >
<IgrStep
invalid ={this.state.linear && this.state.firstStepInvalid }
>
<span slot ="title" >
Personal Info
</span >
<form ref ={this.InfoForm} >
<IgrInput
required
label ="Full Name"
type ="text"
name ="fullName"
> </IgrInput >
<IgrInput
required
label ="Email"
type ="email"
name ="email"
> </IgrInput >
<IgrButton
disabled ={this.state.linear && this.state.firstStepInvalid }
onClick ={() => {
this .stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep
invalid ={this.state.linear && this.state.secondStepInvalid }
>
<span slot ="title" >
Delivery address
</span >
<form ref ={this.AddressForm} >
<IgrInput
required
label ="City"
type ="text"
name ="city"
> </IgrInput >
<IgrInput
required
label ="Street"
type ="text"
name ="street"
> </IgrInput >
<IgrButton
onClick ={() => {
this .stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
disabled ={this.state.linear && this.state.secondStepInvalid }
onClick ={() => {
this .stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep optional >
<span slot ="title" >
Billing address
</span >
<span slot ="subtitle" >
(optional)
</span >
<form >
<IgrInput
required
label ="City"
type ="text"
name ="bill-city"
> </IgrInput >
<IgrInput
required
label ="Street"
type ="text"
name ="bill-street"
> </IgrInput >
<IgrButton
onClick ={() => {
this .stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
this .stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep >
<span slot ="title" >
Payment
</span >
<IgrRadioGroup >
<IgrRadio name ="payment" checked >
<span > PayPal (n@mail.com; 18 /02 /2021 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span > Visa (**** **** **** 1234 ; 12 /23 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span >
MasterCard (**** **** **** 5678 ; 12 /24 )
</span >
</IgrRadio >
</IgrRadioGroup >
<IgrButton
onClick ={() => {
this .stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
this .stepperRef.current.next();
}}
>
<span > SUBMIT</span >
</IgrButton >
</IgrStep >
<IgrStep >
<span slot ="title" >
Delivery status
</span >
<p >
Your order is on its way. Expect delivery on 25 th September 2021.
Delivery address: San Jose, CA 94243.
</p >
<IgrButton
onClick ={() => {
this .stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
this .stepperRef.current.reset();
}}
>
<span > RESET</span >
</IgrButton >
</IgrStep >
</IgrStepper >
</div >
);
}
public onSwitchChange(e: IgrCheckboxChangeEventArgs) {
this .setState({ linear: e.detail.checked });
if (e.detail.checked) {
this .checkActiveStepValidity();
}
}
public onInput(s: IgrInput, e: IgrComponentValueChangedEventArgs) {
if (!this .state.linear) return ;
this .checkActiveStepValidity();
}
private checkActiveStepValidity() {
const activeStep = this .activeStep;
if (activeStep && this .activeStepIndex === 0 ) {
const isInvalidForm = this .checkFormValidity(this .InfoForm);
this .setState({ firstStepInvalid: isInvalidForm });
}
if (activeStep && this .activeStepIndex === 1 ) {
const isInvalidForm = this .checkFormValidity(this .AddressForm);
this .setState({ secondStepInvalid: isInvalidForm });
}
}
private checkFormValidity(form: any ) {
let isInvalidForm = false ;
for (const element of form .current .children ) {
if (
element .tagName .toLowerCase () === "igc-input" &&
element.value === ""
) {
const oldInvalid = element.invalid;
const isElementInvalid = !element.checkValidity();
element.invalid = oldInvalid;
if (isElementInvalid) {
isInvalidForm = true ;
break ;
}
}
}
return isInvalidForm;
}
private get activeStep(): IgrStep | undefined {
return this .stepperRef.current.steps.find(
(step: IgrStep, index: number ) => {
this .activeStepIndex = index;
return step.active;
}
);
}
}
const root = ReactDOM.createRoot (document.getElementById("root" ));
root.render (<LinearStepper /> );
tsx コピー
.radio-groups {
display : flex;
align-items : center;
margin-bottom : 1rem ;
}
.radio-group {
margin-right : 2rem ;
}
.radio-group-container {
padding : 0.5rem ;
border : 1px solid gainsboro;
}
igc-switch {
margin : 0.5rem ;
}
igc-button {
margin : 1rem 0.5rem 0 0 ;
}
css コピー
React Stepper 시작하기
먼저, 다음 명령을 실행하여 Ignite UI for React 설치해야 합니다.
npm install igniteui-react
cmd
그런 다음 다음과 같이 와 필요한 CSS를 가져와야 IgrStepper 합니다.
import { IgrStepper, IgrStep } from 'igniteui-react' ;
import 'igniteui-webcomponents/themes/light/bootstrap.css' ;
tsx
이제 React IgrStepper 와 해당 단계의 기본 구성을 시작할 수 있습니다.
React Stepper를 사용하는 방법
에 IgrStep 속 IgrStepper 하는 모든 단계의 표현입니다. 단계는 비즈니스 요구 사항에 따라 단계 상태를 구성할 수 있는 기능을 제공하는 , active , optional 및 disabled complete 속성을 제공합니다 invalid .
React Stepper 선언하기
다음 접근 방식 중 하나를 사용하여 단계를 선언할 수 있습니다.
<IgrStepper >
{this .StepsData.map(item =>
<IgrStep key ={item.title} disabled ={item.disabled} >
<p slot ="title" > {item.title}</p >
</IgrStep >
}
</IgrStepper >
tsx
<IgrStepper >
<IgrStep >
<p slot ="title" > Step 1 </p >
</IgrStep >
<IgrStep >
<p slot ="title" > Step 2 </p >
</IgrStep >
</IgrStepper >
tsx
각 단계에서 사용자는 다음과 같이 Indicator, 제목 및 Subtitle 슬롯을 사용하여 표시기, Title 및 자막을 구성할 수 있습니다.
기본 IgrStep 슬롯은 단계의 내용을 렌더링합니다.
<IgrStepper >
<IgrStep >
<IgrIcon slot ="indicator" name ="home" collection ="material" />
<p slot ="title" > Home</p >
<p slot ="subtitle" > Home Sub Title</p >
<div >
Step Content
...
</div >
</IgrStep >
</IgrStepper >
tsx
React Stepper에서의 방향
노출된 orientation 속성을 통해 스테퍼 방향을 사용자 정의할 수 있습니다. 수평 (기본값) 또는 수직 으로 설정할 수 있습니다.
수평 스테퍼 방향
horizontal 은 IgrStepper orientation 속성의 기본값입니다. React stepper가 수평으로 방향이 지정되면 단계의 콘텐츠가 단계 헤더 위에 표시될지 아래에 표시될지 결정할 수 있습니다. 이는 IgrStepper contentTop 부울 속성을 설정하여 달성할 수 있으며, 기본값은 false 입니다. 활성화된 경우 단계의 콘텐츠가 단계 헤더 위에 표시됩니다.
수직 스테퍼 방향
가로 레이아웃에서 세로 레이아웃으로 쉽게 전환할 수 있습니다. 기본 방향을 변경하려면 orientation 속성을 수직 으로 설정해야 합니다.
아래 샘플은 스테퍼 방향과 제목 위치가 런타임에 어떻게 변경될 수 있는지 보여줍니다.
import React from 'react' ;
import ReactDOM from 'react-dom/client' ;
import './index.css' ;
import {
IgrButton,
IgrRadio,
IgrRadioChangeEventArgs,
IgrRadioGroup,
IgrStep,
IgrStepper,
StepperOrientation,
StepperTitlePosition,
} from "@infragistics/igniteui-react" ;
import 'igniteui-webcomponents/themes/light/bootstrap.css' ;
export interface StepperOrientationProps {
orientation: StepperOrientation;
titlePosition: StepperTitlePosition;
}
export default class StepperOrientationSample extends React.Component <any, StepperOrientationProps> {
private stepperRef = React .createRef<IgrStepper > ();
constructor (props: StepperOrientationProps) {
super (props);
this .state = { orientation: "horizontal" , titlePosition: "auto" };
this .handleTitlePositionChange = this .handleTitlePositionChange.bind(this );
this .handleOrientationChange = this .handleOrientationChange.bind(this );
}
public render (): JSX .Element {
return (
<div className ="container sample" >
<div className ="radio-groups" >
<div className ="radio-group" >
<label > Title position</label >
<div className ="radio-group-container" >
<IgrRadioGroup alignment ="horizontal" onChange ={this.handleTitlePositionChange} value ={this.state.titlePosition} >
<IgrRadio name ="title" value ="top" > <span > Top</span > </IgrRadio >
<IgrRadio name ="title" value ="bottom" > <span > Bottom</span > </IgrRadio >
<IgrRadio name ="title" value ="start" > <span > Start</span > </IgrRadio >
<IgrRadio name ="title" value ="end" > <span > End</span > </IgrRadio >
<IgrRadio name ="title" value ="auto" > <span > Auto (default )</span > </IgrRadio >
</IgrRadioGroup >
</div >
</div >
<div className ="radio-group" >
<label > Orientation</label >
<div className ="radio-group-container" >
<IgrRadioGroup alignment ="horizontal" onChange ={this.handleOrientationChange} value ={this.state.orientation} >
<IgrRadio name ="orientation" value ="horizontal" > <span > Horizontal</span > </IgrRadio >
<IgrRadio name ="orientation" value ="vertical" > <span > Vertical</span > </IgrRadio >
</IgrRadioGroup >
</div >
</div >
</div >
<IgrStepper ref ={this.stepperRef} orientation ={this.state.orientation} titlePosition ={this.state.titlePosition} >
<IgrStep >
<span slot ="title" > Order</span >
<IgrButton onClick ={() => { this .stepperRef.current.next(); }}><span > NEXT</span > </IgrButton >
</IgrStep >
<IgrStep >
<span slot ="title" > Payment</span >
<IgrButton onClick ={() => { this .stepperRef.current.prev(); }}><span > PREVIOUS</span > </IgrButton >
<IgrButton onClick ={() => { this .stepperRef.current.next(); }}><span > NEXT</span > </IgrButton >
</IgrStep >
<IgrStep >
<span slot ="title" > Confirmation</span >
<IgrButton onClick ={() => { this .stepperRef.current.prev(); }}><span > PREVIOUS</span > </IgrButton >
<IgrButton onClick ={() => { this .stepperRef.current.reset(); }}><span > RESET</span > </IgrButton >
</IgrStep >
</IgrStepper >
</div >
);
}
public handleTitlePositionChange(e: IgrRadioChangeEventArgs) {
const newTitlePosition = e.detail.value as StepperTitlePosition;
this .setState({ titlePosition: newTitlePosition });
}
public handleOrientationChange(e: IgrRadioChangeEventArgs) {
const newOrientation = e.detail.value as StepperOrientation;
this .setState({ orientation: newOrientation, titlePosition: "auto" });
}
}
const root = ReactDOM.createRoot (document.getElementById('root' ));
root.render (<StepperOrientationSample /> );
tsx コピー
.radio-groups {
display : flex;
align-items : center;
margin-bottom : 1rem ;
}
.radio-group {
margin-right : 2rem ;
}
.radio-group-container {
padding : 0.5rem ;
border : 1px solid gainsboro;
}
css コピー
단계 상태
React IgrStepper 5가지 단계 상태를 지원하며 각 단계 상태는 기본적으로 다른 스타일을 적용합니다.
active - 단계가 현재 표시되는지 여부를 결정합니다. 설계상, 사용자가 일부 단계의 활성 속성을 명시적으로 true 로 설정하지 않은 경우 초기 활성 단계는 비활성화되지 않은 첫 번째 단계가 됩니다.
비활성화됨 - 단계가 다루기 어려운지 여부를 결정합니다. 기본적으로 단계의 비활성화된 속성은 false 로 설정됩니다.
유효하지 않음 - 단계가 유효한지 여부를 결정합니다. 해당 값에 따라 사용자가 선형 스테퍼 모드에서 앞으로 이동할 수 있는지 여부가 결정됩니다. 기본값은 false 입니다.
선택사항 - 기본적으로 단계의 선택사항 속성은 false 로 설정됩니다. 선형 스테퍼에서 단계의 유효성이 필요하지 않은 경우 단계 유효성과 독립적으로 앞으로 나아갈 수 있도록 선택적 속성을 활성화할 수 있습니다.
완료 - 기본적으로 단계의 완료 속성은 false 를 반환합니다. 그러나 사용자는 필요에 따라 완료 속성을 설정하여 이 기본 완료 동작을 재정의할 수 있습니다. 단계가 완료로 표시되면 기본적으로 단계 헤더의 스타일이 변경될 뿐만 아니라 완료된 단계와 다음 단계 사이의 진행 라인 스타일도 변경됩니다.
선형 React 스테퍼
React IgrStepper linear 속성을 사용하여 단계 흐름을 설정할 수 있는 기회를 제공합니다. 기본적으로 linear는 false 로 설정되고 사용자는 IgrStepper 에서 비활성화되지 않은 단계를 선택할 수 있습니다.
<IgrStepper linear ={true} >
<IgrStep >
<p slot ="title" > Step 1 </p >
</IgrStep >
<IgrStep >
<p slot ="title" > Step 2 </p >
</IgrStep >
</IgrStepper >
tsx
선형 속성이 true 로 설정된 경우 스테퍼는 다음 단계로 진행하기 전에 현재 선택 사항이 아닌 단계가 유효해야 합니다.
현재 비선택적 단계가 유효하지 않은 경우 현재 단계를 확인할 때까지 다음 단계로 진행할 수 없습니다.
앞으로 나아갈 때 선택적 단계 유효성은 고려되지 않습니다.
단계 상호작용
IgrStepper 에서는 단계 상호 작용에 대해 다음과 같은 API 메서드를 제공합니다.
NavigateTo – 주어진 인덱스로 단계를 활성화합니다.
next - 비활성화되지 않은 다음 단계를 활성화합니다.
prev – 비활성화되지 않은 이전 단계를 활성화합니다.
재설정 – 스테퍼를 초기 상태로 재설정합니다.
재설정 방법은 스테퍼를 초기 상태로 재설정합니다. 즉, 첫 번째 단계를 활성화합니다. 단계의 내용은 지워지지 않습니다. 이 작업은 수동으로 수행해야 합니다.
단계 사용자 정의
Ignite UI for React Stepper는 제목, 표시기 등에 대한 다양한 옵션을 구성할 수 있는 기능을 제공합니다.
이것은 의 속성을 통해 stepType 달성 될 수 있습니다 IgrStepper . 다음 값을 사용합니다.
가득한
제목과 부제목이 정의된 경우 이 설정을 사용하면 표시기와 제목이 모두 렌더링됩니다.
또한 사용자는 단계 제목의 위치를 정의할 수 있으므로 단계 표시기 앞, 뒤, 위 또는 아래에 제목을 배치할 수 있습니다. 사용자는 titlePosition 속성을 사용하여 제목 위치를 구성할 수 있습니다. 다음 값을 사용합니다.
정의되지 않음 (기본값)
끝
시작
맨 아래
맨 위
React IgrStepper 가로 방향으로 배치되고 제목 위치가 정의되지 않은 경우 제목은 표시기 아래에 표시됩니다.
방향이 세로로 설정되고 제목 위치가 정의되지 않은 경우 제목은 표시기 뒤에 표시됩니다.
titlePosition 속성은 스테퍼 stepType 속성이 full로 설정된 경우에만 적용 가능합니다.
지시자
단계에 대한 표시기만 표시하려면 stepType 옵션을 표시기 로 설정하십시오.
단계 표시기는 모든 콘텐츠를 지원하지만 크기가 항상 24픽셀 이라는 제한이 있습니다. 이를 염두에 두고 또는 IgrAvatar 단계 표시기로 사용하는 IgrIcon 것이 좋습니다.
제목
단계의 제목만 표시하려면 stepType 옵션을 title 로 설정하세요.
이런 방식으로 자막이 정의되면 단계 제목 아래에도 렌더링됩니다.
이 컨테이너는 크기 제한 없이 요구 사항에 따라 다시 템플릿을 만들 수 있습니다. 예를 들어 내부에 24픽셀보다 큰 크기의 표시기를 추가할 수 있습니다.
아래 샘플은 노출된 모든 단계 유형과 변경 방법을 보여줍니다.
import React , { useState } from 'react' ;
import ReactDOM from 'react-dom/client' ;
import './index.css' ;
import { IgrStepper, IgrStep, IgrRadio, IgrRadioGroup, StepperStepType, IgrRadioChangeEventArgs } from "@infragistics/igniteui-react" ;
import 'igniteui-webcomponents/themes/light/bootstrap.css' ;
export default function StepperStepTypes() {
const [stepType , setStepType ] = useState<StepperStepType > ("full" );
const onStepTypeChange = (e: IgrRadioChangeEventArgs) => {
const newStepType = e.detail.value as StepperStepType;
setStepType(newStepType);
}
return (
<div className ="container sample" >
<label > Step type</label >
<div className ="radio-group-container" >
<IgrRadioGroup alignment ="horizontal" >
<IgrRadio name ="type" value ="indicator" onChange ={onStepTypeChange} > <span > Indicator</span > </IgrRadio >
<IgrRadio name ="type" value ="title" onChange ={onStepTypeChange} > <span > Title</span > </IgrRadio >
<IgrRadio name ="type" value ="full" onChange ={onStepTypeChange} checked ={stepType === 'full' }> <span > Full</span > </IgrRadio >
</IgrRadioGroup >
</div >
<IgrStepper stepType ={stepType} >
<IgrStep >
<span slot ="title" > Pricing Plan</span >
</IgrStep >
<IgrStep >
<span slot ="title" > Car Details</span >
</IgrStep >
<IgrStep >
<span slot ="title" > Payment</span >
</IgrStep >
</IgrStepper >
</div >
);
}
const root = ReactDOM.createRoot (document.getElementById('root' ));
root.render (<StepperStepTypes /> );
tsx コピー
.radio-group-container {
width : fit-content;
padding : 0.5rem ;
border : 1px solid gainsboro;
margin-bottom : 1rem ;
}
css コピー
스테퍼 애니메이션
React IgrStepper Animations는 최종 사용자에게 정의된 단계와 상호 작용하는 아름다운 경험을 제공합니다. 사용 가능한 애니메이션 옵션은 스테퍼의 방향에 따라 다릅니다.
스테퍼가 가로 방향이면 기본적으로 애니메이션을 slide 사용하도록 구성됩니다. 대안으로도 지원합니다 fade. 애니메이션은 입력을 horizontalAnimation 통해 구성됩니다.
세로 방향 레이아웃에서는 속성을 사용하여 verticalAnimation 애니메이션 형식을 정의할 수 있습니다. 기본적으로 해당 값은 로 grow 설정되며 사용자도 이 값을 설정할 fade 수 있습니다.
두 애니메이션 유형 입력 모두에 none 설정하면 스테퍼 애니메이션이 비활성화됩니다.
이 IgrStepper 구성 요소는 단계 간 전환 기간을 구성할 수 있는 기능도 제공합니다. 이것은 숫자를 인수로 사용하는 속성을 통해 animationDuration 달성 할 수 있으며 두 방향 모두에 공통적입니다. 기본값은 320ms로 설정됩니다.
import React , { useRef, useState } from "react" ;
import ReactDOM from "react-dom/client" ;
import "./index.css" ;
import {
IgrStepper,
IgrStep,
IgrRadio,
IgrRadioGroup,
IgrButton,
IgrInput,
IgrSelect,
IgrSelectItem,
IgrSelectItemComponentEventArgs,
IgrComponentValueChangedEventArgs,
StepperOrientation,
HorizontalTransitionAnimation,
StepperVerticalAnimation,
} from "@infragistics/igniteui-react" ;
import "igniteui-webcomponents/themes/light/bootstrap.css" ;
export default function StepperAnimations() {
const stepperRef = useRef<IgrStepper > (null );
const [orientation , setOrientation ] = useState<StepperOrientation > ("horizontal" );
const [horizontalAnimation , setHorizontalAnimation ] = useState<HorizontalTransitionAnimation > ("slide" );
const [verticalAnimation , setVerticalAnimation ] = useState<StepperVerticalAnimation > ("grow" );
const [animationDuration , setAnimationDuration ] = useState("320" );
const orientationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as StepperOrientation;
setOrientation(selectedValue);
}
const horizontalAnimationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as HorizontalTransitionAnimation;
setHorizontalAnimation(selectedValue);
}
const verticalAnimationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as StepperVerticalAnimation;
setVerticalAnimation(selectedValue);
}
const animationDurationChange = (e: IgrComponentValueChangedEventArgs) => {
const animationDuration = e.detail;
setAnimationDuration(animationDuration);
}
return (
<div className ="container sample" >
<article className ="settings" >
<IgrSelect label ="Orienation" onChange ={orientationChange} >
<IgrSelectItem value ="horizontal" selected ={orientation === 'horizontal' }>
<span > Horizontal</span >
</IgrSelectItem >
<IgrSelectItem value ="vertical" >
<span > Vertical</span >
</IgrSelectItem >
</IgrSelect >
<IgrSelect
label ="Vertical Animation"
onChange ={verticalAnimationChange}
>
<IgrSelectItem value ="grow" selected ={verticalAnimation === 'grow' }>
<span > Grow</span >
</IgrSelectItem >
<IgrSelectItem value ="fade" >
<span > Fade</span >
</IgrSelectItem >
<IgrSelectItem value ="none" >
<span > None</span >
</IgrSelectItem >
</IgrSelect >
<IgrSelect
label ="Horizontal Animation"
onChange ={horizontalAnimationChange}
>
<IgrSelectItem value ="slide" selected ={horizontalAnimation === 'slide' }>
<span > Slide</span >
</IgrSelectItem >
<IgrSelectItem value ="fade" >
<span > Fade</span >
</IgrSelectItem >
<IgrSelectItem value ="none" >
<span > None</span >
</IgrSelectItem >
</IgrSelect >
<IgrInput
type ="number"
value ={animationDuration}
label ="Duration"
onChange ={animationDurationChange}
>
<span slot ="suffix" > ms</span >
</IgrInput >
</article >
<IgrStepper
ref ={stepperRef}
orientation ={orientation}
horizontalAnimation ={horizontalAnimation}
verticalAnimation ={verticalAnimation}
animationDuration ={+animationDuration}
>
<IgrStep >
<span slot ="title" > Personal Info</span >
<form >
<IgrInput
label ="Full Name"
type ="text"
name ="fullName"
> </IgrInput >
<IgrInput label ="Email" type ="email" name ="email" > </IgrInput >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep >
<span slot ="title" > Delivery address</span >
<form >
<IgrInput label ="City" type ="text" name ="city" > </IgrInput >
<IgrInput label ="Street" type ="text" name ="street" > </IgrInput >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep >
<span slot ="title" > Payment</span >
<IgrRadioGroup >
<IgrRadio name ="payment" checked >
<span > PayPal (n@mail.com; 18 /02 /2021 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span > Visa (**** **** **** 1234 ; 12 /23 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span > MasterCard (**** **** **** 5678 ; 12 /24 )</span >
</IgrRadio >
</IgrRadioGroup >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > SUBMIT</span >
</IgrButton >
</IgrStep >
<IgrStep >
<span slot ="title" > Delivery status</span >
<p >
Your order is on its way. Expect delivery on 25 th September 2021.
Delivery address: San Jose, CA 94243.
</p >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.reset();
}}
>
<span > RESET</span >
</IgrButton >
</IgrStep >
</IgrStepper >
</div >
);
}
const root = ReactDOM.createRoot (document.getElementById("root" ));
root.render (<StepperAnimations /> );
tsx コピー
.settings {
display : grid;
grid-template-columns : repeat (4 , 1 fr);
gap: 1.125rem ;
background : hsl (var (--ig-gray-100 ));
padding : 1.125rem ;
border : 1px solid hsl (var (--ig-gray-300 ));
border-radius : .25rem ;
margin-bottom : 2rem ;
}
igc-button {
margin : 1rem 0.5rem 0 0 ;
}
css コピー
키보드 탐색
Ignite UI for React Stepper는 최종 사용자에게 다양한 키보드 상호 작용을 제공합니다. 이 기능은 기본적으로 활성화되어 있으며 최종 사용자가 단계를 쉽게 탐색할 수 있도록 합니다. 더 React IgrStepper 내비게이션은 다음을 준수합니다. W3 접근성 표준 사용하기 편리합니다.
주요 조합
TAB - 포커스를 다음 탭 가능한 요소로 이동합니다.
SHIFT + TAB - 포커스를 이전 탭 가능 요소로 이동합니다.
↓ - 스테퍼가 수직 방향 일 때 포커스를 다음 액세스 가능한 단계의 헤더로 이동합니다.
↑ - 스테퍼가 수직 방향 일 때 액세스 가능한 이전 단계의 헤더로 포커스를 이동합니다.
← - 두 방향 모두에서 액세스 가능한 이전 단계의 헤더로 초점을 이동합니다.
→ - 초점을 두 방향 모두에서 액세스 가능한 다음 단계의 헤더로 이동합니다.
HOME - 포커스를 스테퍼에서 FIRST 활성화 단계의 헤더로 이동합니다.
END - 포커스를 스테퍼에서 LAST 활성화 단계의 헤더로 이동합니다.
ENTER 또는 SPACE - 현재 포커스가 있는 단계를 활성화합니다.
React Stepper 스타일링
아래에 나열된 노출된 CSS 부분 중 일부를 사용하여 모양을 변경할 수 있습니다. IgrStep
부품명
설명
header-container
단계 헤더 및 해당 구분 기호의 래퍼입니다.
disabled
비활성화된 상태를 나타냅니다. 헤더 컨테이너에 적용됩니다.
complete-start
현재 단계의 전체 상태를 나타냅니다. 헤더 컨테이너에 적용됩니다.
complete-end
이전 단계의 전체 상태를 나타냅니다. 헤더 컨테이너에 적용됩니다.
optional
선택적 상태를 나타냅니다. 헤더 컨테이너에 적용됩니다.
invalid
잘못된 상태를 나타냅니다. 헤더 컨테이너에 적용됩니다.
top
제목이 표시기 위에 있어야 함을 나타냅니다. 헤더 컨테이너에 적용됩니다.
bottom
제목이 표시기 아래에 있어야 함을 나타냅니다. 헤더 컨테이너에 적용됩니다.
start
제목이 표시기 앞에 와야 함을 나타냅니다. 헤더 컨테이너에 적용됩니다.
end
제목이 표시자 뒤에 와야 함을 나타냅니다. 헤더 컨테이너에 적용됩니다.
header
단계 표시기 및 텍스트의 래퍼입니다.
indicator
단계의 표시기입니다.
text
단계 제목 및 부제목의 래퍼입니다.
empty
단계에 제목과 부제목이 제공되지 않았음을 나타냅니다. 텍스트에 적용됩니다.
title
단계의 제목입니다.
subtitle
단계의 부제목입니다.
body
단계 콘텐츠의 래퍼입니다.
content
단계 내용.
이러한 CSS 부분을 사용하여 다음과 같이 구성 요소의 모양을 IgrStepper 사용자 지정할 수 있습니다.
igc-step::part (title) {
color : var (--ig-primary-500 );
}
igc-step[active] ::part (indicator) {
background-color : var (--ig-primary-500 );
}
igc-step::part (indicator) {
background-color : var (--ig-surface-500 );
}
css
import React , { useEffect, useRef, useState } from "react" ;
import ReactDOM from "react-dom/client" ;
import "./index.css" ;
import {
IgrStepper,
IgrStep,
IgrRadio,
IgrRadioGroup,
IgrButton,
IgrInput,
IgrSelect,
IgrSelectItem,
IgrSelectItemComponentEventArgs,
IgrComponentValueChangedEventArgs,
StepperOrientation,
HorizontalTransitionAnimation,
StepperVerticalAnimation,
IgrIcon,
registerIconFromText,
} from "@infragistics/igniteui-react" ;
import "igniteui-webcomponents/themes/light/bootstrap.css" ;
const personalInfoIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 12c2.7 0 4.8-2.1 4.8-4.8S14.7 2.4 12 2.4 7.2 4.5 7.2 7.2 9.3 12 12 12zm0 2.4c-3.2 0-9.6 1.6-9.6 4.8v2.4h19.2v-2.4c0-3.2-6.4-4.8-9.6-4.8z"/></svg>' ;
const addressIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C8.1 2 5 5.1 5 9c0 5.3 7 13 7 13s7-7.7 7-13c0-3.9-3.1-7-7-7zm0 9.5c-1.4 0-2.5-1.1-2.5-2.5S10.6 6.5 12 6.5s2.5 1.1 2.5 2.5S13.4 11.5 12 11.5z"/></svg>' ;
const paymentIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v2h20V6c0-1.1-.9-2-2-2zM2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-8H2v8zm4-3h4v2H6v-2z"/></svg>' ;
const deliveryStatusIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 8h-3V4H3c-1.1 0-2 .9-2 2v11h2a2 2 0 1 0 4 0h8a2 2 0 1 0 4 0h3v-5l-4-4zm-5 5H4V6h11v7zm2-4.17L19.17 13H17V8.83zM6 18a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm12 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></svg>' ;
export default function StepperStyling() {
const stepperRef = useRef<IgrStepper > (null );
const [orientation , setOrientation ] =
useState<StepperOrientation > ("horizontal" );
const [horizontalAnimation , setHorizontalAnimation ] =
useState<HorizontalTransitionAnimation > ("slide" );
const [verticalAnimation , setVerticalAnimation ] =
useState<StepperVerticalAnimation > ("grow" );
const [animationDuration , setAnimationDuration ] = useState("320" );
useEffect(() => {
registerIconFromText("personal" , personalInfoIcon, "material" );
registerIconFromText("address" , addressIcon, "material" );
registerIconFromText("payment" , paymentIcon, "material" );
registerIconFromText("delivery" , deliveryStatusIcon, "material" );
}, []);
const orientationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as StepperOrientation;
setOrientation(selectedValue);
};
const horizontalAnimationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as HorizontalTransitionAnimation;
setHorizontalAnimation(selectedValue);
};
const verticalAnimationChange = (e: IgrSelectItemComponentEventArgs) => {
const selectedValue = e.detail.value as StepperVerticalAnimation;
setVerticalAnimation(selectedValue);
};
const animationDurationChange = (e: IgrComponentValueChangedEventArgs) => {
const animationDuration = e.detail;
setAnimationDuration(animationDuration);
};
return (
<div className ="container sample" >
<article className ="settings" >
<IgrSelect label ="Orienation" onChange ={orientationChange} >
<IgrSelectItem
value ="horizontal"
selected ={orientation === "horizontal" }
>
<span > Horizontal</span >
</IgrSelectItem >
<IgrSelectItem value ="vertical" >
<span > Vertical</span >
</IgrSelectItem >
</IgrSelect >
<IgrSelect
label ="Vertical Animation"
onChange ={verticalAnimationChange}
>
<IgrSelectItem value ="grow" selected ={verticalAnimation === "grow" }>
<span > Grow</span >
</IgrSelectItem >
<IgrSelectItem value ="fade" >
<span > Fade</span >
</IgrSelectItem >
<IgrSelectItem value ="none" >
<span > None</span >
</IgrSelectItem >
</IgrSelect >
<IgrSelect
label ="Horizontal Animation"
onChange ={horizontalAnimationChange}
>
<IgrSelectItem
value ="slide"
selected ={horizontalAnimation === "slide" }
>
<span > Slide</span >
</IgrSelectItem >
<IgrSelectItem value ="fade" >
<span > Fade</span >
</IgrSelectItem >
<IgrSelectItem value ="none" >
<span > None</span >
</IgrSelectItem >
</IgrSelect >
<IgrInput
type ="number"
value ={animationDuration}
label ="Duration"
onChange ={animationDurationChange}
>
<span slot ="suffix" > ms</span >
</IgrInput >
</article >
<IgrStepper
ref ={stepperRef}
orientation ={orientation}
horizontalAnimation ={horizontalAnimation}
verticalAnimation ={verticalAnimation}
animationDuration ={+animationDuration}
>
<IgrStep >
<IgrIcon slot ="indicator" name ="personal" collection ="material" />
<p slot ="title" > Personal Info</p >
<form >
<IgrInput label ="Full Name" type ="text" name ="fullName" > </IgrInput >
<IgrInput label ="Email" type ="email" name ="email" > </IgrInput >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep >
<IgrIcon slot ="indicator" name ="address" collection ="material" />
<span slot ="title" > Delivery address</span >
<form >
<IgrInput label ="City" type ="text" name ="city" > </IgrInput >
<IgrInput label ="Street" type ="text" name ="street" > </IgrInput >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > NEXT</span >
</IgrButton >
</form >
</IgrStep >
<IgrStep >
<IgrIcon slot ="indicator" name ="payment" collection ="material" />
<span slot ="title" > Payment</span >
<IgrRadioGroup >
<IgrRadio name ="payment" checked >
<span > PayPal (n@mail.com; 18 /02 /2021 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span > Visa (**** **** **** 1234 ; 12 /23 )</span >
</IgrRadio >
<IgrRadio name ="payment" >
<span > MasterCard (**** **** **** 5678 ; 12 /24 )</span >
</IgrRadio >
</IgrRadioGroup >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.next();
}}
>
<span > SUBMIT</span >
</IgrButton >
</IgrStep >
<IgrStep >
<IgrIcon slot ="indicator" name ="delivery" collection ="material" />
<span slot ="title" > Delivery status</span >
<p >
Your order is on its way. Expect delivery on 25 th September 2021.
Delivery address: San Jose, CA 94243.
</p >
<IgrButton
onClick ={() => {
stepperRef.current.prev();
}}
>
<span > PREVIOUS</span >
</IgrButton >
<IgrButton
onClick ={() => {
stepperRef.current.reset();
}}
>
<span > RESET</span >
</IgrButton >
</IgrStep >
</IgrStepper >
</div >
);
}
const root = ReactDOM.createRoot (document.getElementById("root" ));
root.render (<StepperStyling /> );
tsx コピー
.settings {
display : grid;
grid-template-columns : repeat (4 , 1 fr);
gap: 1.125rem ;
background : hsl (var (--ig-gray-100 ));
padding : 1.125rem ;
border : 1px solid hsl (var (--ig-gray-300 ));
border-radius : .25rem ;
margin-bottom : 2rem ;
}
:root {
--color -teal: rgba (77 , 182 , 172 , 1 );
--color -dark-navy: rgba (26 , 35 , 126 , 1 );
--color -aqua-gray: rgba (208 , 236 , 236 , 1 );
--color -white: rgba (255 , 255 , 255 , 1 );
--color -teal-hover: rgba (26 , 35 , 126 , 1 );
--color -teal-shadow: rgba (77 , 182 , 172 , 0.5 );
}
igc-button ::part (base) {
margin : 1rem 0.5rem 0 0 ;
background-color : var (--color-teal);
color : var (--color-white);
font-weight : 600 ;
transition : background-color 0.25s ease, transform 0.1s ease;
}
igc-button :hover ::part (base) {
background-color : var (--color-dark-navy);
}
igc-button :active ::part (base) {
transform : scale (0.96 );
}
igc-step::part (title) {
color : var (--color-dark-navy);
font-variant : small-caps;
font-weight : bold;
}
igc-step::part (indicator) {
border-radius : 12px 6px 12px 6px ;
background-color : var (--color-aqua-gray);
color : var (--color-dark-navy);
transition : all 0.2s ease;
}
igc-step[active] ::part (indicator) {
background-color : var (--color-teal);
box-shadow : 0 2px 8px var (--color-teal-shadow);
transform : scale (1.04 );
}
igc-step[active] :active ::part (indicator) {
transform : scale (1.08 );
}css コピー
API 참조
추가 리소스