Initial commit for Greenlens
This commit is contained in:
77
context/CoachMarksContext.tsx
Normal file
77
context/CoachMarksContext.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import React, { createContext, useContext, useState, useCallback, useRef } from 'react';
|
||||
import { LayoutRectangle } from 'react-native';
|
||||
|
||||
export interface CoachStep {
|
||||
elementKey: string;
|
||||
title: string;
|
||||
description: string;
|
||||
tooltipSide: 'above' | 'below' | 'left' | 'right';
|
||||
}
|
||||
|
||||
interface CoachMarksState {
|
||||
isActive: boolean;
|
||||
currentStep: number;
|
||||
steps: CoachStep[];
|
||||
layouts: Record<string, LayoutRectangle>;
|
||||
registerLayout: (key: string, layout: LayoutRectangle) => void;
|
||||
startTour: (steps: CoachStep[]) => void;
|
||||
next: () => void;
|
||||
skip: () => void;
|
||||
}
|
||||
|
||||
const CoachMarksContext = createContext<CoachMarksState | null>(null);
|
||||
|
||||
export const useCoachMarks = () => {
|
||||
const ctx = useContext(CoachMarksContext);
|
||||
if (!ctx) throw new Error('useCoachMarks must be within CoachMarksProvider');
|
||||
return ctx;
|
||||
};
|
||||
|
||||
export const CoachMarksProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [steps, setSteps] = useState<CoachStep[]>([]);
|
||||
const layouts = useRef<Record<string, LayoutRectangle>>({});
|
||||
const [, forceRender] = useState(0);
|
||||
|
||||
const registerLayout = useCallback((key: string, layout: LayoutRectangle) => {
|
||||
layouts.current[key] = layout;
|
||||
forceRender(n => n + 1);
|
||||
}, []);
|
||||
|
||||
const startTour = useCallback((newSteps: CoachStep[]) => {
|
||||
setSteps(newSteps);
|
||||
setCurrentStep(0);
|
||||
setIsActive(true);
|
||||
}, []);
|
||||
|
||||
const next = useCallback(() => {
|
||||
setCurrentStep(prev => {
|
||||
if (prev + 1 >= steps.length) {
|
||||
setIsActive(false);
|
||||
return 0;
|
||||
}
|
||||
return prev + 1;
|
||||
});
|
||||
}, [steps.length]);
|
||||
|
||||
const skip = useCallback(() => {
|
||||
setIsActive(false);
|
||||
setCurrentStep(0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<CoachMarksContext.Provider value={{
|
||||
isActive,
|
||||
currentStep,
|
||||
steps,
|
||||
layouts: layouts.current,
|
||||
registerLayout,
|
||||
startTour,
|
||||
next,
|
||||
skip,
|
||||
}}>
|
||||
{children}
|
||||
</CoachMarksContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user