Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
fatihsolhan authored Feb 9, 2024
2 parents a0bb9e6 + 8aa02b3 commit 79c7cac
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 17 deletions.
3 changes: 2 additions & 1 deletion demo/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 <strong>v-onboarding</strong> to show some information about your app, or to explain how to use it',
html: true
}
},
{
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/3.props/1.steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ title: steps
content: {
title: "..."
description: "..."
html: false
},
on: {
beforeStep: function (options) { ... },
Expand All @@ -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)) |
Expand Down
9 changes: 6 additions & 3 deletions docs/pages/3.props/2.options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -39,7 +40,8 @@ You can override `VOnboardingWrapper`'s options by passing options to `VOnboardi
previousButton: 'Previous',
nextButton: 'Next',
finishButton: 'Finish'
}
},
hideNextStepDuringHook: false
}
```
---
Expand All @@ -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' }` |
Expand All @@ -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` |



Expand Down
2 changes: 1 addition & 1 deletion docs/pages/3.props/3.hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/components/VOnboardingStep.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
</button>
</div>
<p
v-if="step.content.description"
v-if="step.content.description && step.content.html"
class="v-onboarding-item__description"
v-html="step.content.description"
/>
<p
v-else-if="step.content.description"
class="v-onboarding-item__description"
>{{ step.content.description }}</p>
<div class="v-onboarding-item__actions">
Expand Down Expand Up @@ -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) {
Expand Down
80 changes: 71 additions & 9 deletions src/components/VOnboardingWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div v-if="!isFinished" data-v-onboarding-wrapper>
<slot :key="index" :step="activeStep" :next="next" :previous="previous" :exit="exit" :is-first="isFirstStep" :is-last="isLastStep" :index="index">
<div v-if="!isFinished" data-v-onboarding-wrapper style="pointer-events: auto;">
<slot v-if="showStep" :key="index" :step="activeStep" :next="next" :previous="previous" :exit="exit"
:is-first="isFirstStep" :is-last="isLastStep" :index="index">
<VOnboardingStep :key="index" />
</slot>
</div>
Expand All @@ -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: {
Expand All @@ -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)) => {
Expand All @@ -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 = {
Expand All @@ -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]
Expand All @@ -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
})
Expand Down Expand Up @@ -97,7 +126,7 @@ export default defineComponent({
}
const state = computed(() => ({
step: activeStep,
options: computed(() => merge({}, defaultVOnboardingWrapperOptions, props.options)),
options: mergedOptions,
next,
previous,
finish,
Expand All @@ -116,7 +145,8 @@ export default defineComponent({
isFirstStep: state.value.isFirstStep,
isLastStep: state.value.isLastStep,
finish,
exit
exit,
showStep
}
}
})
Expand All @@ -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<VOnboardingWrapperOptions>) {
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)
}
Expand Down
1 change: 1 addition & 0 deletions src/types/StepEntity.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface StepEntity {
content: {
title: string;
description?: string;
html?: boolean
}
on?: {
beforeStep?: (options?: onBeforeStepOptions) => void | Promise<void>
Expand Down
6 changes: 5 additions & 1 deletion src/types/VOnboardingWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface SvgOverlayOptions {
rightBottom?: number;
leftBottom?: number;
}
preventOverlayInteraction?: boolean
}

export interface VOnboardingWrapperOptions {
Expand All @@ -34,6 +35,7 @@ export interface VOnboardingWrapperOptions {
nextButton?: string
finishButton?: string
}
hideNextStepDuringHook?: boolean
}

export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
Expand All @@ -42,6 +44,7 @@ export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
enabled: true,
padding: 0,
borderRadius: 0,
preventOverlayInteraction: true
},
scrollToStep: {
enabled: true,
Expand All @@ -61,5 +64,6 @@ export const defaultVOnboardingWrapperOptions: VOnboardingWrapperOptions = {
previous: false,
next: false,
exit: false
}
},
hideNextStepDuringHook: false
}

0 comments on commit 79c7cac

Please sign in to comment.