diff --git a/demo/src/App.vue b/demo/src/App.vue
index 3768b62..55e35ba 100644
--- a/demo/src/App.vue
+++ b/demo/src/App.vue
@@ -77,7 +77,8 @@ export default defineComponent({
},
content: {
title: 'Nice to see you here!',
- description: 'You can use v-onboarding to show some information about your app, or to explain how to use it',
+ description: 'You can use v-onboarding to show some information about your app, or to explain how to use it',
+ html: true
}
},
{
diff --git a/docs/pages/3.props/1.steps.md b/docs/pages/3.props/1.steps.md
index ec3b271..6d6c739 100644
--- a/docs/pages/3.props/1.steps.md
+++ b/docs/pages/3.props/1.steps.md
@@ -13,6 +13,7 @@ title: steps
content: {
title: "..."
description: "..."
+ html: false
},
on: {
beforeStep: function (options) { ... },
@@ -29,6 +30,7 @@ title: steps
| `content` | `Object` | **Optional** |
| `content.title` | `String` | **Optional** | Title to use in onboarding step |
| `content.description` | `String` | **Optional** | Description to use in onboarding step |
+| `content.html` | `Boolean` | **Optional** | If its set to `true`, the `content.description` will be rendered in the default template using [`v-html`](https://vuejs.org/guide/essentials/template-syntax.html#raw-html) |
| `on` | `Object` | **Optional** |
| `on.beforeStep` | `Function` `AsyncFunction` | **Optional** | Function to run before showing the step ([More information](/props/hooks#onBeforeStep)) |
| `on.afterStep ` | `Function` `AsyncFunction` | **Optional** | Function to run after showing the step ([More information](/props/hooks#onAfterStep)) |
diff --git a/docs/pages/3.props/2.options.md b/docs/pages/3.props/2.options.md
index b78b93c..fb3c857 100644
--- a/docs/pages/3.props/2.options.md
+++ b/docs/pages/3.props/2.options.md
@@ -19,7 +19,8 @@ You can override `VOnboardingWrapper`'s options by passing options to `VOnboardi
overlay: {
enabled: true,
padding: 0,
- borderRadius: 0
+ borderRadius: 0,
+ preventOverlayInteraction: true
},
scrollToStep: {
enabled: true,
@@ -39,7 +40,8 @@ You can override `VOnboardingWrapper`'s options by passing options to `VOnboardi
previousButton: 'Previous',
nextButton: 'Next',
finishButton: 'Finish'
- }
+ },
+ hideNextStepDuringHook: false
}
```
---
@@ -50,6 +52,7 @@ You can override `VOnboardingWrapper`'s options by passing options to `VOnboardi
| `overlay.enabled` | `Boolean` | `true` |
| `overlay.padding` | `Number` `{ top: 0, right: 0, bottom: 0, left: 0 }` | `0` |
| `overlay.borderRadius` | `Number` `{ leftTop: 0, rightTop: 0, rightBottom: 0, leftBottom: 0 }` | `0` |
+| `overlay.preventOverlayInteraction` | `Boolean` | `true` |
| `scrollToStep` | | |
| `scrollToStep.enabled` | `Boolean` | `true` |
| `scrollToStep.options` | [Scroll Into View Options](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) | `{ behavior: 'smooth', block: 'center', inline: 'center' }` |
@@ -62,7 +65,7 @@ You can override `VOnboardingWrapper`'s options by passing options to `VOnboardi
| `labels.previousButton` | `String` | `Previous` |
| `labels.nextButton` | `String` | `Next` |
| `labels.finishButton` | `String` | `Finish` |
-
+| `hideNextStepDuringHook` | `Boolean` | `false` |
diff --git a/docs/pages/3.props/3.hooks.md b/docs/pages/3.props/3.hooks.md
index c1cad5f..4b7e862 100644
--- a/docs/pages/3.props/3.hooks.md
+++ b/docs/pages/3.props/3.hooks.md
@@ -32,7 +32,7 @@ It runs before the step is 'closed'.
```js
{
on: {
- beforeStep: function (options) {
+ afterStep: function (options) {
// The logic written here will run before hiding the step, and it can be customized with settings
}
}
diff --git a/src/components/VOnboardingStep.vue b/src/components/VOnboardingStep.vue
index a71c103..01c0892 100644
--- a/src/components/VOnboardingStep.vue
+++ b/src/components/VOnboardingStep.vue
@@ -29,7 +29,12 @@
+ {{ step.content.description }}
@@ -93,7 +98,7 @@ export default defineComponent({
if (element && stepElement.value) {
show.value = true
if (mergedOptions.value?.scrollToStep?.enabled) {
- element.scrollIntoView(mergedOptions.value?.scrollToStep?.options)
+ element.scrollIntoView?.(mergedOptions.value?.scrollToStep?.options)
}
createPopper(element, stepElement.value, mergedOptions.value.popper);
if (mergedOptions.value?.overlay?.enabled) {
diff --git a/src/components/VOnboardingWrapper.vue b/src/components/VOnboardingWrapper.vue
index f379616..3f8a874 100644
--- a/src/components/VOnboardingWrapper.vue
+++ b/src/components/VOnboardingWrapper.vue
@@ -1,6 +1,7 @@
-
-
+
+
@@ -12,7 +13,7 @@ import { OnboardingState, Direction, STATE_INJECT_KEY } from '@/types';
import type { StepEntity, onBeforeStepOptions, onAfterStepOptions } from '@/types/StepEntity';
import { defaultVOnboardingWrapperOptions, VOnboardingWrapperOptions } from '@/types/VOnboardingWrapper';
import merge from 'lodash.merge';
-import { computed, defineComponent, PropType, provide, ref, watch } from 'vue';
+import { computed, ComputedRef, defineComponent, PropType, provide, ref, watch } from 'vue';
export default defineComponent({
name: 'VOnboardingWrapper',
components: {
@@ -30,6 +31,8 @@ export default defineComponent({
},
emits: ['finish', 'exit'],
setup(props, { expose, emit }) {
+ const mergedOptions = computed(() => merge({}, defaultVOnboardingWrapperOptions, props.options))
+ const showStep = ref(true)
const index = ref(OnboardingState.IDLE)
const privateIndex = ref(index.value)
const setIndex = (value: number | ((_: number) => number)) => {
@@ -39,8 +42,14 @@ export default defineComponent({
index.value = value;
}
}
- const { beforeHook, afterHook } = useStepHooks()
const activeStep = computed(() => props.steps?.[privateIndex.value])
+ const activeStepMergedOptions = computed(() => {
+ return activeStep.value ? merge({}, mergedOptions.value, activeStep.value.options) : mergedOptions.value
+ })
+ const mergeOptions = (step: StepEntity) => {
+ return merge({}, mergedOptions.value, step.options)
+ }
+ const { beforeHook, afterHook } = useStepHooks(activeStepMergedOptions)
watch(index, async (newIndex, oldIndex) => {
const direction: number = newIndex < oldIndex ? Direction.BACKWARD : Direction.FORWARD
const globalHookOptions = {
@@ -56,6 +65,7 @@ export default defineComponent({
index: oldIndex,
step: oldStep,
}
+ removePointerEvents(useGetElement(oldStep.attachTo.element) as HTMLElement)
await afterHook(oldStep, afterHookOptions)
}
const newStep = props.steps?.[newIndex]
@@ -66,10 +76,29 @@ export default defineComponent({
index: newIndex,
step: newStep,
}
+ removePointerEvents(useGetElement(newStep.attachTo.element) as HTMLElement)
+ if (mergeOptions(newStep)?.hideNextStepDuringHook) {
+ showStep.value = false
+ }
await beforeHook(newStep, beforeHookOptions)
}
privateIndex.value = newIndex
+ showStep.value = true
+ removePointerEvents(useGetElement('body') as HTMLElement)
+ if (activeStepMergedOptions.value.overlay?.preventOverlayInteraction) {
+ updateBodyPointerEvents()
+ }
})
+ const { addPointerEvents, removePointerEvents } = useSetPointerEvents()
+ const updateBodyPointerEvents = () => {
+ const body = useGetElement('body') as HTMLBodyElement | null
+ if (!body) return;
+ if ([OnboardingState.IDLE, OnboardingState.FINISHED].includes(privateIndex.value)) {
+ removePointerEvents(body)
+ } else {
+ addPointerEvents(body, 'none')
+ }
+ }
const isFinished = computed(() => {
return privateIndex.value === OnboardingState.FINISHED
})
@@ -97,7 +126,7 @@ export default defineComponent({
}
const state = computed(() => ({
step: activeStep,
- options: computed(() => merge({}, defaultVOnboardingWrapperOptions, props.options)),
+ options: mergedOptions,
next,
previous,
finish,
@@ -116,7 +145,8 @@ export default defineComponent({
isFirstStep: state.value.isFirstStep,
isLastStep: state.value.isLastStep,
finish,
- exit
+ exit,
+ showStep
}
}
})
@@ -131,15 +161,47 @@ function useSetElementClassName() {
}
return { setClassName, unsetClassName }
}
-function useStepHooks() {
+function useSetPointerEvents() {
+ const pointerEventsDataAttribute = 'data-v-onboarding-pointer-events'
+ const addPointerEvents = (element: HTMLElement, value = 'auto') => {
+ if (!element) return;
+ const currentPointerEvents = element.style.pointerEvents
+ if (currentPointerEvents) {
+ element.setAttribute(pointerEventsDataAttribute, currentPointerEvents)
+ }
+ element.style.setProperty('pointer-events', value)
+ }
+ const removePointerEvents = (element: HTMLElement) => {
+ if (!element) return;
+ const storedPointerEvent = element.getAttribute(pointerEventsDataAttribute)
+ if (storedPointerEvent) {
+ element.style.setProperty('pointer-events', storedPointerEvent)
+ element.removeAttribute(pointerEventsDataAttribute)
+ } else {
+ element.style.removeProperty('pointer-events')
+ }
+ }
+ return { addPointerEvents, removePointerEvents }
+}
+function useStepHooks(stepOptions: ComputedRef) {
const { setClassName, unsetClassName } = useSetElementClassName()
+ const { addPointerEvents, removePointerEvents } = useSetPointerEvents()
+
const beforeHook = (step: StepEntity, options: onBeforeStepOptions) => {
- setClassName({ element: useGetElement(step.attachTo.element), classList: step.attachTo.classList });
+ const element = useGetElement(step.attachTo.element)
+ if (stepOptions.value?.overlay?.preventOverlayInteraction) {
+ addPointerEvents(element as HTMLElement)
+ }
+ setClassName({ element, classList: step.attachTo.classList });
return step.on?.beforeStep?.(options)
}
const afterHook = (step: StepEntity, options: onAfterStepOptions) => {
- unsetClassName({ element: useGetElement(step.attachTo.element), classList: step.attachTo.classList });
+ const element = useGetElement(step.attachTo.element)
+ if (stepOptions.value?.overlay?.preventOverlayInteraction) {
+ removePointerEvents(element as HTMLElement)
+ }
+ unsetClassName({ element, classList: step.attachTo.classList });
return step.on?.afterStep?.(options)
}
diff --git a/src/types/StepEntity.d.ts b/src/types/StepEntity.d.ts
index 46c66c1..d8ceba2 100644
--- a/src/types/StepEntity.d.ts
+++ b/src/types/StepEntity.d.ts
@@ -20,6 +20,7 @@ export interface StepEntity {
content: {
title: string;
description?: string;
+ html?: boolean
}
on?: {
beforeStep?: (options?: onBeforeStepOptions) => void | Promise
diff --git a/src/types/VOnboardingWrapper.ts b/src/types/VOnboardingWrapper.ts
index 70aebb2..be44251 100644
--- a/src/types/VOnboardingWrapper.ts
+++ b/src/types/VOnboardingWrapper.ts
@@ -14,6 +14,7 @@ export interface SvgOverlayOptions {
rightBottom?: number;
leftBottom?: number;
}
+ preventOverlayInteraction?: boolean
}
export interface VOnboardingWrapperOptions {
@@ -34,6 +35,7 @@ export interface VOnboardingWrapperOptions {
nextButton?: string
finishButton?: string
}
+ hideNextStepDuringHook?: boolean
}
export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
@@ -42,6 +44,7 @@ export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
enabled: true,
padding: 0,
borderRadius: 0,
+ preventOverlayInteraction: true
},
scrollToStep: {
enabled: true,
@@ -61,5 +64,6 @@ export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
previous: false,
next: false,
exit: false
- }
+ },
+ hideNextStepDuringHook: false
}