diff --git a/.eslintrc.js b/.eslintrc.js index 8d674ee..d5c80d7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,6 +15,7 @@ module.exports = { rules: { 'simple-import-sort/imports': 'error', 'sort-imports': 'off', - 'import/order': 'off' + 'import/order': 'off', + 'jsdoc/require-param-type': 'off', } }; diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..7d9a15d --- /dev/null +++ b/global.d.ts @@ -0,0 +1 @@ +declare var __DEV__: boolean; diff --git a/jest.config.js b/jest.config.js index bb8ab6b..424fcc8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,7 @@ module.exports = { // https://github.com/testing-library/jest-native/issues/46#issuecomment-748674706 setupFilesAfterEnv: ['/test/setup.ts'], + globals: { + __DEV__: 'development', + }, }; diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..ecf8579 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,23 @@ +import { LogLevel } from './types'; +/** + * Log messages in the console with a corresponding urgency + * + * @param level The urgency of the message + * @param message The message to log in the console + */ +export const log = (level: LogLevel, message: string) => { + if (__DEV__) { + const packageName = '[react-use-wizard]'; + + switch (level) { + case 'warn': + console.warn(`${packageName} ${message}`); + break; + case 'error': + console.error(`${packageName} ${message}`); + break; + default: + console.log(`${packageName} ${message}`); + } + } +}; diff --git a/src/reducer.ts b/src/reducer.ts deleted file mode 100644 index ccead35..0000000 --- a/src/reducer.ts +++ /dev/null @@ -1,18 +0,0 @@ -// export const initialState = { activeStep: 0, isLoading: false }; - -// type ACTIONTYPE = -// | { type: 'loading'; payload: boolean } -// | { type: 'step'; payload: number }; - -// const reducer = (state: typeof initialState, action: ACTIONTYPE) => { -// switch (action.type) { -// case 'loading': -// return { ...state, loading: action.payload }; -// case 'step': -// return { ...state, activeStep: action.payload }; -// default: -// throw new Error(); -// } -// }; - -// export default reducer; diff --git a/src/types.ts b/src/types.ts index 0f228d8..48c6cc0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,4 +34,7 @@ export type WizardValues = { isFirstStep: boolean; /** Indicate if the current step is the last step (aka no next step) */ isLastStep: boolean; -} | null; +}; + +/** Console log levels */ +export type LogLevel = 'info' | 'error' | 'warn'; diff --git a/src/useWizard.ts b/src/useWizard.ts index 82077d8..c01016e 100644 --- a/src/useWizard.ts +++ b/src/useWizard.ts @@ -1,14 +1,15 @@ import * as React from 'react'; +import { WizardValues } from './types'; import WizardContext from './wizardContext'; const useWizard = () => { const context = React.useContext(WizardContext); - if (!context) { - throw Error('Wrap your component with `Wizard`'); + if (!context && __DEV__) { + throw Error('Wrap your step with `Wizard`'); } else { - return context; + return context as WizardValues; } }; diff --git a/src/wizard.tsx b/src/wizard.tsx index 56c4168..b1afaf2 100644 --- a/src/wizard.tsx +++ b/src/wizard.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; +import * as logger from './logger'; import { Handler, WizardProps } from './types'; import WizardContext from './wizardContext'; @@ -62,10 +63,33 @@ const Wizard: React.FC = React.memo( [doNextStep, previousStep, isLoading, handleStep, activeStep], ); - const activeStepContent = React.useMemo( - () => React.Children.toArray(children)[activeStep], - [activeStep, children], - ); + const activeStepContent = React.useMemo(() => { + const reactChildren = React.Children.toArray(children); + + if (__DEV__) { + // No steps passed + if (reactChildren.length === 0) { + logger.log( + 'warn', + 'Make sure to pass your steps as children in your ', + ); + } + // The passed start index is invalid + if (activeStep > reactChildren.length) { + logger.log('warn', 'An invalid startIndex is passed to '); + } + // Invalid header element + if (header && !React.isValidElement(header)) { + logger.log('error', 'Invalid header passed to '); + } + // Invalid footer element + if (footer && !React.isValidElement(footer)) { + logger.log('error', 'Invalid footer passed to '); + } + } + + return reactChildren[activeStep]; + }, [activeStep, children, header, footer]); return ( diff --git a/src/wizardContext.ts b/src/wizardContext.ts index 5417044..e1391bc 100644 --- a/src/wizardContext.ts +++ b/src/wizardContext.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { WizardValues } from './types'; -const WizardContext = React.createContext(null); +const WizardContext = React.createContext(null); WizardContext.displayName = 'WizardContext'; export default WizardContext; diff --git a/tsconfig.json b/tsconfig.json index 2c85b2d..8da7ede 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs - "include": ["src", "types"], + "include": ["src", "global.d.ts"], "compilerOptions": { "module": "esnext", "lib": ["dom", "esnext"],