Skip to content

Commit

Permalink
feat(Slideover): open programmatically (#1465)
Browse files Browse the repository at this point in the history
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
  • Loading branch information
genu and benjamincanac committed Mar 21, 2024
1 parent b0ecac5 commit e769759
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
</template>
</UNotifications>
<UModals />
<USlideovers />
</div>
</template>

Expand Down
30 changes: 30 additions & 0 deletions docs/components/content/examples/SlideoverExampleComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts" setup>
const props = defineProps({
count: {
type: Number,
default: 0
}
})
const emits = defineEmits<{
close: [];
}>()
</script>

<template>
<USlideover>
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Opened programmatically: {{ props.count }} times
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="emits('close')" />
</div>
</template>

<Placeholder class="h-full" />
</UCard>
</USlideover>
</template>
16 changes: 16 additions & 0 deletions docs/components/content/examples/SlideoverExampleComposable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
import { SlideoverExampleComponent } from '#components'
const slideover = useSlideover()
const count = ref(0)
function openSlideover () {
count.value += 1
slideover.open(SlideoverExampleComponent, {
count: count.value,
onClose: slideover.close
})
}
</script>

<template>
<UButton label="Reveal slideover" @click="openSlideover" />
</template>
20 changes: 19 additions & 1 deletion docs/content/2.components/slideover.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Set the `transition` prop to `false` to disable it.

### Prevent close

Use the `prevent-close` prop to disable the outside click alongside the `esc` keyboard shortcut. A `close-prevented` event will be emitted when the user tries to close the modal.
Use the `prevent-close` prop to disable the outside click alongside the `esc` keyboard shortcut. A `close-prevented` event will be emitted when the user tries to close the slideover.

:component-example{component="slideover-example-prevent-close"}

Expand All @@ -53,6 +53,24 @@ defineShortcuts({
</script>
```

### Control programmatically

First of all, add the `USlideovers` component to your app, preferably inside `app.vue`.

```vue [app.vue]
<template>
<div>
<UContainer>
<NuxtPage />
</UContainer>
<USlideovers />
</div>
</template>
```

Then, you can use the `useSlideover` composable to control your slideovers within your app.

:component-example{component="slideover-example-composable"}
## Props

:component-props
Expand Down
4 changes: 4 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ export default defineNuxtModule<ModuleOptions>({
src: resolve(runtimeDir, 'plugins', 'modals')
})

addPlugin({
src: resolve(runtimeDir, 'plugins', 'slideovers')
})

// Components

addComponentsDir({
Expand Down
17 changes: 17 additions & 0 deletions src/runtime/components/overlays/Slideovers.client.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<component
:is="slideoverState.component"
v-if="slideoverState"
v-bind="slideoverState.props"
v-model="isOpen"
/>
</template>

<script lang="ts" setup>
import { inject } from 'vue'
import { useSlideover, slidOverInjectionKey } from '../../composables/useSlideover'
const slideoverState = inject(slidOverInjectionKey)
const { isOpen } = useSlideover()
</script>
55 changes: 55 additions & 0 deletions src/runtime/composables/useSlideover.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ref, inject } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import type { ComponentProps } from '../types/component'
import type { Slideover, SlideoverState } from '../types/slideover'

export const slidOverInjectionKey: InjectionKey<ShallowRef<SlideoverState>> =
Symbol('nuxt-ui.slideover')

function _useSlideover () {
const slideoverState = inject(slidOverInjectionKey)
const isOpen = ref(false)

function open<T extends Component> (component: T, props?: Slideover & ComponentProps<T>) {
if (!slideoverState) {
throw new Error('useSlideover() is called without provider')
}

slideoverState.value = {
component,
props: props ?? {}
}

isOpen.value = true
}

function close () {
if (!slideoverState) return

isOpen.value = false
}

/**
* Allows updating the slideover props
*/
function patch<T extends Component = {}> (props: Partial<Slideover & ComponentProps<T>>) {
if (!slideoverState) return

slideoverState.value = {
...slideoverState.value,
props: {
...slideoverState.value.props,
...props
}
}
}
return {
open,
close,
patch,
isOpen
}
}

export const useSlideover = createSharedComposable(_useSlideover)
13 changes: 13 additions & 0 deletions src/runtime/plugins/slideovers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineNuxtPlugin } from '#imports'
import { shallowRef } from 'vue'
import { slidOverInjectionKey } from '../composables/useSlideover'
import type { SlideoverState } from '../types/slideover'

export default defineNuxtPlugin((nuxtApp) => {
const slideoverState = shallowRef<SlideoverState>({
component: 'div',
props: {}
})

nuxtApp.vueApp.provide(slidOverInjectionKey, slideoverState)
})
1 change: 1 addition & 0 deletions src/runtime/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './kbd'
export * from './link'
export * from './meter'
export * from './modal'
export * from './slideover'
export * from './notification'
export * from './popper'
export * from './progress'
Expand Down
17 changes: 17 additions & 0 deletions src/runtime/types/slideover.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Component } from 'vue'

interface Slideover {
ui?: any;
side?: 'right' | 'left';
transition?: boolean;
appear?: boolean;
overlay?: boolean;
preventClose?: boolean;
modelValue?: boolean;
}

interface SlideoverState {
component: Component | string;
props: Slideover;
}

0 comments on commit e769759

Please sign in to comment.