diff --git a/docs/app.vue b/docs/app.vue index 49572f54e2..c8a8f7faee 100644 --- a/docs/app.vue +++ b/docs/app.vue @@ -23,6 +23,7 @@ + diff --git a/docs/components/content/examples/SlideoverExampleComponent.vue b/docs/components/content/examples/SlideoverExampleComponent.vue new file mode 100644 index 0000000000..eb177b890c --- /dev/null +++ b/docs/components/content/examples/SlideoverExampleComponent.vue @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/docs/components/content/examples/SlideoverExampleComposable.vue b/docs/components/content/examples/SlideoverExampleComposable.vue new file mode 100644 index 0000000000..6eeabaed07 --- /dev/null +++ b/docs/components/content/examples/SlideoverExampleComposable.vue @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/docs/content/2.components/slideover.md b/docs/content/2.components/slideover.md index ab6528fa6d..0d7660c102 100644 --- a/docs/content/2.components/slideover.md +++ b/docs/content/2.components/slideover.md @@ -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({ ``` +### Control programmatically + +First of all, add the `USlideovers` component to your app, preferably inside `app.vue`. + +```vue [app.vue] + +``` + +Then, you can use the `useSlideover` composable to control your slideovers within your app. + +:component-example{component="slideover-example-composable"} ## Props :component-props diff --git a/src/module.ts b/src/module.ts index 5beb7c1348..4b41d2596a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -200,6 +200,10 @@ export default defineNuxtModule({ src: resolve(runtimeDir, 'plugins', 'modals') }) + addPlugin({ + src: resolve(runtimeDir, 'plugins', 'slideovers') + }) + // Components addComponentsDir({ diff --git a/src/runtime/components/overlays/Slideovers.client.vue b/src/runtime/components/overlays/Slideovers.client.vue new file mode 100644 index 0000000000..933c8e616b --- /dev/null +++ b/src/runtime/components/overlays/Slideovers.client.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/runtime/composables/useSlideover.ts b/src/runtime/composables/useSlideover.ts new file mode 100644 index 0000000000..3f221e2ca6 --- /dev/null +++ b/src/runtime/composables/useSlideover.ts @@ -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> = + Symbol('nuxt-ui.slideover') + +function _useSlideover () { + const slideoverState = inject(slidOverInjectionKey) + const isOpen = ref(false) + + function open (component: T, props?: Slideover & ComponentProps) { + 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 (props: Partial>) { + if (!slideoverState) return + + slideoverState.value = { + ...slideoverState.value, + props: { + ...slideoverState.value.props, + ...props + } + } + } + return { + open, + close, + patch, + isOpen + } +} + +export const useSlideover = createSharedComposable(_useSlideover) diff --git a/src/runtime/plugins/slideovers.ts b/src/runtime/plugins/slideovers.ts new file mode 100644 index 0000000000..950d4fbb7d --- /dev/null +++ b/src/runtime/plugins/slideovers.ts @@ -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({ + component: 'div', + props: {} + }) + + nuxtApp.vueApp.provide(slidOverInjectionKey, slideoverState) +}) diff --git a/src/runtime/types/index.d.ts b/src/runtime/types/index.d.ts index 21188a9ee1..3b90d85399 100644 --- a/src/runtime/types/index.d.ts +++ b/src/runtime/types/index.d.ts @@ -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' diff --git a/src/runtime/types/slideover.d.ts b/src/runtime/types/slideover.d.ts new file mode 100644 index 0000000000..291d20feca --- /dev/null +++ b/src/runtime/types/slideover.d.ts @@ -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; +} +