From 5e185de0b1e3bd1b39e18cef2657257bcf39ef8b Mon Sep 17 00:00:00 2001 From: Jukka Raimovaara Date: Fri, 6 Jun 2025 12:13:31 +0300 Subject: [PATCH 1/4] draft of BApp --- packages/bootstrap-vue-next/src/App.vue | 14 +- .../src/components/BApp/BApp.vue | 248 ++++++++++++++++++ .../src/components/BApp/BAppOrchestrator.vue | 154 +++++++++++ .../src/components/BApp/bapp.spec.ts | 146 +++++++++++ .../src/components/BApp/index.ts | 1 + .../components/BModal/BModalOrchestrator.vue | 14 +- .../BPopover/BPopoverOrchestrator.vue | 20 +- .../components/BToast/BToastOrchestrator.vue | 15 +- .../src/components/index.ts | 1 + .../src/composables/shared.ts | 107 ++++++++ .../composables/useModalController/index.ts | 175 ++++++++++-- .../composables/usePopoverController/index.ts | 161 ++++++++++-- .../composables/useToastController/index.ts | 169 ++++++++++-- packages/bootstrap-vue-next/src/main.ts | 2 - .../src/plugins/modalController/index.ts | 221 +--------------- .../src/plugins/popoverController/index.ts | 203 +------------- .../src/plugins/toastController/index.ts | 220 +--------------- .../src/types/BootstrapVueOptions.ts | 2 + .../src/types/ComponentOrchestratorTypes.ts | 93 ++++++- .../src/types/ComponentProps.ts | 28 +- packages/bootstrap-vue-next/src/utils/keys.ts | 44 +--- 21 files changed, 1272 insertions(+), 766 deletions(-) create mode 100644 packages/bootstrap-vue-next/src/components/BApp/BApp.vue create mode 100644 packages/bootstrap-vue-next/src/components/BApp/BAppOrchestrator.vue create mode 100644 packages/bootstrap-vue-next/src/components/BApp/bapp.spec.ts create mode 100644 packages/bootstrap-vue-next/src/components/BApp/index.ts create mode 100644 packages/bootstrap-vue-next/src/composables/shared.ts diff --git a/packages/bootstrap-vue-next/src/App.vue b/packages/bootstrap-vue-next/src/App.vue index bef8a39fa..b59fab74c 100644 --- a/packages/bootstrap-vue-next/src/App.vue +++ b/packages/bootstrap-vue-next/src/App.vue @@ -1,13 +1,15 @@ diff --git a/packages/bootstrap-vue-next/src/components/BApp/BApp.vue b/packages/bootstrap-vue-next/src/components/BApp/BApp.vue new file mode 100644 index 000000000..1faeb10b9 --- /dev/null +++ b/packages/bootstrap-vue-next/src/components/BApp/BApp.vue @@ -0,0 +1,248 @@ + + + diff --git a/packages/bootstrap-vue-next/src/components/BApp/BAppOrchestrator.vue b/packages/bootstrap-vue-next/src/components/BApp/BAppOrchestrator.vue new file mode 100644 index 000000000..473ca811f --- /dev/null +++ b/packages/bootstrap-vue-next/src/components/BApp/BAppOrchestrator.vue @@ -0,0 +1,154 @@ + + + + diff --git a/packages/bootstrap-vue-next/src/components/BApp/bapp.spec.ts b/packages/bootstrap-vue-next/src/components/BApp/bapp.spec.ts new file mode 100644 index 000000000..c2d0df62b --- /dev/null +++ b/packages/bootstrap-vue-next/src/components/BApp/bapp.spec.ts @@ -0,0 +1,146 @@ +import {enableAutoUnmount, mount} from '@vue/test-utils' +import {afterEach, describe, expect, it} from 'vitest' +import BApp from './BApp.vue' + +describe('BApp', () => { + enableAutoUnmount(afterEach) + + it('renders correctly', () => { + const wrapper = mount(BApp, { + slots: { + default: '
Test content
', + }, + }) + + expect(wrapper.find('div').exists()).toBe(true) + expect(wrapper.text()).toContain('Test content') + }) + + it('includes orchestrator by default', () => { + const wrapper = mount(BApp) + + expect(wrapper.findComponent({name: 'BAppOrchestrator'}).exists()).toBe(true) + }) + + it('can disable orchestrator', () => { + const wrapper = mount(BApp, { + props: { + noOrchestrator: true, + }, + }) + // console.log(wrapper.html()) + + expect(wrapper.findComponent({name: 'BAppOrchestrator'}).exists()).toBe(false) + }) + + it('can disable individual orchestrators', () => { + const wrapper = mount(BApp, { + props: { + noModals: true, + noToasts: true, + noPopovers: true, + }, + }) + + // When all orchestrators are disabled, BAppOrchestrator should not exist + expect(wrapper.findComponent({name: 'BAppOrchestrator'}).exists()).toBe(false) + }) + + it('renders orchestrator when only some orchestrators are disabled', () => { + const wrapper = mount(BApp, { + props: { + noModals: true, + noToasts: false, // Keep toasts enabled + noPopovers: true, + }, + }) + + // When at least one orchestrator is enabled, BAppOrchestrator should exist + expect(wrapper.findComponent({name: 'BAppOrchestrator'}).exists()).toBe(true) + }) + + it('provides defaults to child components', () => { + const defaults = { + BButton: { + variant: 'primary' as const, + size: 'sm' as const, + }, + } + + const wrapper = mount(BApp, { + props: { + defaults, + }, + slots: { + default: '
Test content
', + }, + }) + + // The component should provide the defaults via Vue's provide/inject + expect(wrapper.vm).toBeDefined() + }) + + it('supports teleporting orchestrator', () => { + const wrapper = mount(BApp, { + props: { + teleportTo: 'body', + }, + }) + + const teleport = wrapper.findComponent({name: 'ConditionalTeleport'}) + expect(teleport.exists()).toBe(true) + expect(teleport.props('to')).toBe('body') + expect(teleport.props('disabled')).toBe(false) + }) + + it('supports RTL configuration', () => { + const rtlConfig = { + rtlInitial: true, + localeInitial: 'ar', + } + + const wrapper = mount(BApp, { + props: { + rtl: rtlConfig, + }, + slots: { + default: '
Test content
', + }, + }) + + expect(wrapper.vm).toBeDefined() + }) + + it('supports defaults merging', () => { + const defaults = { + BButton: { + variant: 'primary' as const, + }, + } + + const wrapper = mount(BApp, { + props: { + defaults, + mergeDefaults: true, + deepMerge: true, + }, + slots: { + default: '
Test content
', + }, + }) + + expect(wrapper.vm).toBeDefined() + }) + + it('supports append toast configuration', () => { + const wrapper = mount(BApp, { + props: { + appendToast: true, + }, + }) + + const orchestrator = wrapper.findComponent({name: 'BAppOrchestrator'}) + expect(orchestrator.exists()).toBe(true) + expect(orchestrator.props('appendToast')).toBe(true) + }) +}) diff --git a/packages/bootstrap-vue-next/src/components/BApp/index.ts b/packages/bootstrap-vue-next/src/components/BApp/index.ts new file mode 100644 index 000000000..33d8582e4 --- /dev/null +++ b/packages/bootstrap-vue-next/src/components/BApp/index.ts @@ -0,0 +1 @@ +export {default as BApp} from './BApp.vue' diff --git a/packages/bootstrap-vue-next/src/components/BModal/BModalOrchestrator.vue b/packages/bootstrap-vue-next/src/components/BModal/BModalOrchestrator.vue index df44d37d2..7a6236dd4 100644 --- a/packages/bootstrap-vue-next/src/components/BModal/BModalOrchestrator.vue +++ b/packages/bootstrap-vue-next/src/components/BModal/BModalOrchestrator.vue @@ -3,9 +3,9 @@
(), { const props = useDefaults(_props, 'BModalOrchestrator') const tools = useModalController() -tools._isOrchestratorInstalled.value = true +if (!tools._isOrchestratorInstalled.value) { + tools._isOrchestratorInstalled.value = true +} else { + console.warn( + 'BModalOrchestrator Or BApp is already installed, only one can be installed at a time' + ) +} defineExpose({ ...tools, diff --git a/packages/bootstrap-vue-next/src/components/BPopover/BPopoverOrchestrator.vue b/packages/bootstrap-vue-next/src/components/BPopover/BPopoverOrchestrator.vue index dbb7ef4ab..759e04aa7 100644 --- a/packages/bootstrap-vue-next/src/components/BPopover/BPopoverOrchestrator.vue +++ b/packages/bootstrap-vue-next/src/components/BPopover/BPopoverOrchestrator.vue @@ -2,12 +2,10 @@
(), { teleportDisabled: false, diff --git a/packages/bootstrap-vue-next/src/components/BToast/BToastOrchestrator.vue b/packages/bootstrap-vue-next/src/components/BToast/BToastOrchestrator.vue index 84b8b2950..d4260148b 100644 --- a/packages/bootstrap-vue-next/src/components/BToast/BToastOrchestrator.vue +++ b/packages/bootstrap-vue-next/src/components/BToast/BToastOrchestrator.vue @@ -1,3 +1,4 @@ +