From d67b4656a03a7052edc04d9bb5b33f56f7bd320c Mon Sep 17 00:00:00 2001 From: Guillermo Date: Tue, 20 Feb 2024 09:36:30 +0100 Subject: [PATCH] feature(composables): create useNoElementRender composable --- .../__tests__/use-no-element-render.spec.ts | 79 +++++++++++++++++++ .../x-components/src/composables/index.ts | 1 + .../src/composables/use-no-element-render.ts | 17 ++++ 3 files changed, 97 insertions(+) create mode 100644 packages/x-components/src/composables/__tests__/use-no-element-render.spec.ts create mode 100644 packages/x-components/src/composables/use-no-element-render.ts diff --git a/packages/x-components/src/composables/__tests__/use-no-element-render.spec.ts b/packages/x-components/src/composables/__tests__/use-no-element-render.spec.ts new file mode 100644 index 0000000000..80c39124e7 --- /dev/null +++ b/packages/x-components/src/composables/__tests__/use-no-element-render.spec.ts @@ -0,0 +1,79 @@ +import Vue, { ComponentOptions, defineComponent } from 'vue'; +import { mount, Wrapper } from '@vue/test-utils'; +import { Dictionary } from '@empathyco/x-utils'; +import { useNoElementRender } from '../use-no-element-render'; +import { getDataTestSelector } from '../../__tests__/utils'; + +const renderUseNoElementRender = ({ + slots, + component +}: RenderUseNoElementRenderOptions = {}): Wrapper => { + const wrapper = mount( + component ?? + (defineComponent({ + render() { + return useNoElementRender(this.$slots); + } + }) as ComponentOptions), + { + slots + } + ); + + return wrapper; +}; + +describe('testing useNoElementRender composable', () => { + it('renders as empty if there are no slots', () => { + let wrapper = renderUseNoElementRender(); + + expect(wrapper.html()).toBe(''); + + wrapper = renderUseNoElementRender({ + slots: { + nonDefault: '
' + } + }); + + expect(wrapper.html()).toBe(''); + }); + + it('renders the default slot if there is any', () => { + const wrapper = renderUseNoElementRender({ + slots: { + default: '
', + nonDefault: '
' + } + }); + + expect(wrapper.find(getDataTestSelector('default-slot')).exists()).toBe(true); + }); + + it('also works from the `setup` function', () => { + const component = defineComponent({ + setup(_, { slots }) { + return () => useNoElementRender(slots); + } + }); + + let wrapper = renderUseNoElementRender({ + component + }); + + expect(wrapper.html()).toBe(''); + + wrapper = renderUseNoElementRender({ + slots: { + default: '
' + }, + component + }); + + expect(wrapper.find(getDataTestSelector('default-slot')).exists()).toBe(true); + }); +}); + +type RenderUseNoElementRenderOptions = { + slots?: Dictionary; + component?: ComponentOptions; +}; diff --git a/packages/x-components/src/composables/index.ts b/packages/x-components/src/composables/index.ts index 13ead653d3..61e2a8b492 100644 --- a/packages/x-components/src/composables/index.ts +++ b/packages/x-components/src/composables/index.ts @@ -1,4 +1,5 @@ export * from './create-use-device.composable'; +export * from './use-no-element-render'; export * from './use-$x'; export * from './use-register-x-module'; export * from './use-on-display'; diff --git a/packages/x-components/src/composables/use-no-element-render.ts b/packages/x-components/src/composables/use-no-element-render.ts new file mode 100644 index 0000000000..5e1d9a2951 --- /dev/null +++ b/packages/x-components/src/composables/use-no-element-render.ts @@ -0,0 +1,17 @@ +import { h, SetupContext } from 'vue'; +import { VNode } from 'vue/types/vnode'; + +/** + * Returns a render function that returns the default slot or nothing if it's not defined. + * + * @param slots - The slots object from the component. + * @returns The result of the rendering function to use. + */ +export function useNoElementRender( + slots: { [key: string]: VNode[] | undefined } | SetupContext['slots'] +): VNode { + const defaultSlotContent = + typeof slots.default === 'function' ? slots.default()?.[0] : slots.default?.[0]; + + return defaultSlotContent ?? h(); +}