Package Exports
- react-rtg
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-rtg) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
About
The idea for this library was to create a trip component library that is created in react way rather than json config, while still keeping the style in a separate css file built in such way that they can be easily overwritten and customized.
Demo page
TLTR
npm install react-rtg
Basic usage
import "./../../node_modules/react_rtg/build/index.css"
import React, {useState} from "react";
import {Tour, Step} from "react-rtg";
const TourGuide = ({isOpen, setOpen}) => {
return (
<Tour isOpen={isOpen}
onClose={setOpen.bind(null, false)}
onOpen={setOpen.bind(null, true)}>
<Step placement="top-center">
<p>First step of tutorial placed on cenetr top of window</p>
</Step>
<Step selector="#buttonId" placement="bottom">
<p>Second on is under selected target element</p>
</Step>
</Tour>
)
};
const App = () => {
const [isTourOpen, setIsTourOpen] = useState(false)
return (
<TourGuide isOpen={isTourOpen} setOpen={setIsTourOpen}/>
<button id="buttonId" onClick={setIsTourOpen.bind(null, ture)}>
Start Tour
</button>
)
}
with context
import "./../../node_modules/react_rtg/build/index.css"
import React, {useState} from "react";
import {Tour, Step, TourRoot, useTour} from "react-rtg";
const TourGuide = ({isOpen, setOpen}) => {
return (
<Tour id="tourId">
<Step placement="top-center">
<p>First step of tutorial placed on cenetr top of window</p>
</Step>
<Step selector="#buttonId" placement="bottom">
<p>Second on is under selected target element</p>
</Step>
</Tour>
)
};
const Menu = () => {
const [tour] = useTour("tourId")
return (
<ul>
<li onClick={tour.next}> Go to next</li>
<li onClick={tour.open}> Sart tour</li>
<li onClick={tour.close}> Finish tour</li>
</ul>
)
}
const Logger = () =>{
const [tour] = useTour("tourId");
const [log, setLog] = useSate("");
useEffect(()=>{
const onNext = (current, next, lenght) => {
setLog(
`current step is ${current}
next will be ${next},
is ${lenght} steps`
)
}
tour.on("next", onNext);
return () => tour.un("next", onNext);
}, [tour, setLog])
return (<span>{log}</span>)
}
const App = () => {
return (
<TourRoot>
<TourGuide/>
<Menu/>
<Logger/>
</TourRoot>
)
}
Spec
Tour component
Tour.propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // tour id used in useTourControl
children: PropTypes.arrayOf(PropTypes.element),
className: PropTypes.string, //container className
isOpen: PropTypes.bool,
onBeforeClose: PropTypes.func, // before close if return falseable the cancel close
onBeforeOpen: PropTypes.func, // before open if return falseable then cancel open
onClose: PropTypes.func, // after close
onOpen: PropTypes.func, // after open eg. from click in pin
onAfterClose: PropTypes.func,// called when modal dialog is not visible
onAfterOpen: PropTypes.func, // called when modal dialog is visible
onNext: PropTypes.func,// called before change.: onNext(current, next, length): next: number
onChange: PropTypes.func, // fired on every step change, - before scroll animation start
onAfterScroll: PropTypes.func, // fired on every step change, - after scroll animation is finished
onFinish: PropTypes.func, // called onClose if is on last step
onLock: PropTypes.func, // called when user try to navigate to lock steps
startAt: PropTypes.number,
closeOnBackdrop: PropTypes.bool, // if true then click on the backdrop mask will close tour
offset: PropTypes.number, // offset of modal from target default 30
offsetX: PropTypes.number, // by default not set, so it has general default 30
offsetY: PropTypes.number, // ... similar like in x
backdropOffset: PropTypes.number, // offset backdrop layer from target element
backdropOffsetY: PropTypes.number, // vertical offset backdrop layer ....
backdropOffsetX: PropTypes.number, // horizontal...
pin: PropTypes.bool, // be default false, if true then after closing it shows pin button
pinText: PropTypes.oneOfType([
PropTypes.bool, // if is false then on hover don't show tool tip
PropTypes.bool, // text on tool tip over pin button
]),
pinOffset: PropTypes.number, // by default 0, offset from base placement of pin
badge: PropTypes.oneOfType([
PropTypes.bool, // if false then badge is hidden,
PropTypes.func, // badge(current, length): string | customizing badge text
]),
badgeClassName: PropTypes.string,
closeButton: PropTypes.oneOfType([
PropTypes.bool,// if false then closing button is hidden,
PropTypes.func // closeButton(close : func) : react.element // function with close handle
]),
closeButtonContent: PropTypes.oneOfType([
PropTypes.string, // text content of button
PropTypes.element, // react.element as content of button eg. svg element like fontawesome icon
]),
closeButtonClassName: PropTypes.string,
controller: PropTypes.func,// export controlling functions : ({set, pre, next})
controls: PropTypes.func,// controls({set, prev, next, current, length, close, lock}): rect.element
// you can return your own step selector/paginator
// which have set, prev, next function and current, length values to disposition
controlButtonsContent: PropTypes.shape({
// for each button you can set custom content
prev: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
next: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
selector: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
selectorCurrent: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
}),
lastStepControls: PropTypes.oneOfType([
PropTypes.func,// onFinishControls({close, prev, set}) : component
PropTypes.element // react component
]),
controlNumbers: PropTypes.bool, // if false hide number over 'step selector'
modalRefreshTimeout: PropTypes.number, // advanced
// If you change transition time on modal element from .8s to some bigger value
// probably you have to increase as well refresh timeout.
// By default value is 801 ms after this time Modal check to 'see' that
// it have enough space or it have to change place, this is important on mobile device.
scrollHiddenOverflow: PropTypes.bool, // by default true, if you pass false
// then if some content is overflowed container and it will be out of visible
// box then container will not be scrolled
scrollTarget: PropTypes.instanceOf(HTMLElement),//by default is window
// but you can set other element like body
}
Step component
Step.propTypes = {
className: PropTypes.string, // class name for step wrapper
selector: PropTypes.string, // css selector
// if is not provided then modal will be located in relation to window
placement: PropTypes.oneOf([
"center",
"top", "bottom", "right", "left",
"top-right", "top-left",
"bottom-right", "bottom-left"
]),
onBeforeShow: PropTypes.func, // called before show, you can prepare some action here
onBeforeNext: PropTypes.func, // if return false block go to next step
approve: PropTypes.oneOfType([
PropTypes.bool, // if you pass just 'approve=true'
// it will take click event on 'selector' element
PropTypes.shape({
event: PropTypes.string,
target: PropTypes.string,
callback: PropTypes.func, // if callback return true then is approved
promise: PropTypes.func, // a function which have to return promise, if promise is resolved then is approved
lock: PropTypes.bool, // lock go next step until task is not done
})
]),
closeOnBackdrop: PropTypes.bool, // close on backdrop click - eg. you can set it on last step
backdropOffset: PropTypes.number, // if is not set will take default value 5
backdropOffsetX: PropTypes.number, // similar lik in general case
backdropOffsetY: PropTypes.number, // ..like in x
scroll: PropTypes.bool, //if false then on this step page is not scrolled
scrollOffset: PropTypes.number, // by default scroll to display element on center of screen
scrollOffsetX: PropTypes.number, // from horizontal screen center
scrollOffsetY: PropTypes.number, // from vertical screen center
offset: PropTypes.number, // if is not set will take general default value 30
offsetX: PropTypes.number, // by default not set so it hase general default 30
offsetY: PropTypes.number, // ... similar like in x
pinPlacement: PropTypes.oneOf([
"center", // if is pin option on, and this is not set then it will take modal placement
"top", "bottom", "right", "left",
"top-right", "top-left",
"bottom-right", "bottom-left"
]),
pinOffset: PropTypes.number, // offset from pin placement. default = 0;
pinText: PropTypes.oneOfType([
PropTypes.bool, // false hide tooltip, true and unset will shown it
PropTypes.string, // text over hover pin if you pass empty string then tool tip will be hidden
]),
}
useTour(id | null)
const [tour] = useTour(tourId);
//or
const [tour] = useTour();
const _tour = tour.get(tourId);
//or
const [tour] = useTour(someId);
const tour2 = tour.get(otherId);
tour.open();
tour.isOpen// true
tour2.isOpen // false
tour2.open()
tour2.isOpen //ture
///------------------
tour.open();
tour.close(force: bool);//if force is true, even if the pin mode is true, it will not be displayed
tour.next();
tour.prev();
tour.set(index: number); // jump to step number index
tour.step.index // current index read onlny
tour.step.props // curretn step compoment props - read onlny
tour.step.target // current step target (html node)
tour.isOpen // boolean read onlny
tour.length // steps amount
function onClose(){
console.log("RTG dialog closed")
tour.un("close", onClose);
}
tour.on("close", onClose);
tour.on("beforeClose", () => console.log("before close dialog"));
tour.on("afterScroll", () => console.log("aftetr scrolling window to target position"));
hooks order:
- Open tour dialog first time
- onBeforeOpen // befre open process start - if it's return false then opening will be aborded
- onNext // before next is evalued - onNext(current, next, length): index|null
- onBeforeShow (on Step component) - called before given step is displayed - this can be onlny added to Step component
- onOpen // called in during opening process
- onChange // after current displayed step is changed onChange(index, Step.props)
- onAfterOpen // called when step is visible all process of rendering are finished
- Next step
- onNext // you can return index of next step
- onLock// called while trying to chnage step index on locked one
- onBeforeNext (on Step component) - called before change given step on next one
- onChange // called after step is changed with onChange(index, Step.props)
- onAfterScroll // called when scrolling to target element is over
- Close tour dialog
- onBeforeClose // on closing process start - if you return false then closing will be aborded
- onClose // on closing but still before
- onFinish // on close on last step
- onAfterClose // dialog is closed
Styling
@import "../../node_modules/react-rtg/build/index.css"
.rtg__conatiner{
--primary-color: #0b708b;
--pin-color: #0fa9d0;
--arrow-size: 15px;
}
// you can change style of each step
.rtg__container--step-3 .rtg__modal{
--arrow-size: 30px;
}
.my-class.rtg.__container{}
.rtg__modal{
background: black;
color: white;
p {
color:white;
}
max-width: 350px;
}
.rtg__modal--top-center:after {
content: none // remove arrov indecates target under modal dialog
}
.rtg__button--close{}
.rtg__button--open{}
.rtg__button--next{}
.rtg__button--prev{}
.rtg__button--selector{}
.rtg__button--current{}
.rtg__badge{} // plate with current step info counter
.rtg__control {} // control button container
.rtg__pin {} // pin button after temporary closing modal
.rtg__backdrop{
border-radius: 0px; // change backdrop hool border radius
}
Customization button icons
import React from "react"
import {Tour, Step} from "react-rtg"
const TourGuide = () => {
return (
<Tour id={"tourId"}
closeButtonContent={<span>{"close"}</span>}
controlButtonsContent = {{
prev: "prev",
next: <span>{"next"}</span>
selector: "*"
current: "@"
}}
badge={(current, length) => current + " from " + length}
lastStepControls={close => (
<button onClick={close.bind(null, true)}>Congratulations</button>
)}
pin
pinText="Clik heart to open tutorail agina">
<Step placement={"center"}}>
<p>
This tip is on center of screen <br/>
</p>
</Step>
</Tour>
)
}
export default TourGuide
Full custom - control buttons component
import React, {useCallback} from "react";
import {Tour, Step} from "react-rtg";
const TourGuide = () => {
const controls = useCallback(({prev, next, close, current, length})=>{
return (
<div className={"some-class__controls"}>
<button onClick={close.bind(null, true)}
className={"btn btn--skip"}>
skip
</button>
{current !== 0 &&
<button onClick={prev}
className={"btn btn--prev"}>
Prev
</button>
}
<button onClick={next}
className={"btn btn--next"}>
{ ((current === length - 1) ? "Last" : "Next") + ` ${current + 1} / ${length}`}
</button>
</div>
)
}, [])
return (
<Tour id={"tourId"}
closeButton={false}
badge={false}
controls={controls}
closeOnBackdrop
pin>
<Step placement={"center"}}>
<p>
This tip is on center of screen <br/>
If you click on backdrop then modal will be closed.
Check it to see pin !!!
</p>
</Step>
</Tour>
)
}