mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
feat(Slideover): open programmatically (#1465)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
</template>
|
||||
</UNotifications>
|
||||
<UModals />
|
||||
<USlideovers />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -200,6 +200,10 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
src: resolve(runtimeDir, 'plugins', 'modals')
|
||||
})
|
||||
|
||||
addPlugin({
|
||||
src: resolve(runtimeDir, 'plugins', 'slideovers')
|
||||
})
|
||||
|
||||
// Components
|
||||
|
||||
addComponentsDir({
|
||||
|
||||
17
src/runtime/components/overlays/Slideovers.client.vue
Normal file
17
src/runtime/components/overlays/Slideovers.client.vue
Normal file
@@ -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
src/runtime/composables/useSlideover.ts
Normal file
55
src/runtime/composables/useSlideover.ts
Normal file
@@ -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
src/runtime/plugins/slideovers.ts
Normal file
13
src/runtime/plugins/slideovers.ts
Normal file
@@ -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
src/runtime/types/index.d.ts
vendored
1
src/runtime/types/index.d.ts
vendored
@@ -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'
|
||||
|
||||
17
src/runtime/types/slideover.d.ts
vendored
Normal file
17
src/runtime/types/slideover.d.ts
vendored
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user