diff --git a/codex-ui/dev/Playground.vue b/codex-ui/dev/Playground.vue index 5c4d86d6..a171bef5 100644 --- a/codex-ui/dev/Playground.vue +++ b/codex-ui/dev/Playground.vue @@ -30,6 +30,7 @@ + @@ -38,7 +39,8 @@ import { computed } from 'vue'; import { VerticalMenu, Tabbar, - Popover + Popover, + Popup } from '../src/vue'; import { useTheme } from '../src/vue/composables/useTheme'; @@ -197,6 +199,16 @@ const pages = computed(() => [ onActivate: () => router.push('/components/editor'), isActive: route.path === '/components/editor', }, + { + title: 'Popup', + onActivate: () => router.push('/components/popup'), + isActive: route.path === '/components/popup', + }, + { + title: 'Confirm', + onActivate: () => router.push('/components/confirm'), + isActive: route.path === '/components/confirm', + }, ], }, ]); diff --git a/codex-ui/dev/pages/components/Confirm.vue b/codex-ui/dev/pages/components/Confirm.vue new file mode 100644 index 00000000..caefff8a --- /dev/null +++ b/codex-ui/dev/pages/components/Confirm.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/codex-ui/dev/pages/components/Popup.vue b/codex-ui/dev/pages/components/Popup.vue new file mode 100644 index 00000000..6e5c5f87 --- /dev/null +++ b/codex-ui/dev/pages/components/Popup.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/codex-ui/dev/pages/components/StubText.vue b/codex-ui/dev/pages/components/StubText.vue new file mode 100644 index 00000000..3d0f6518 --- /dev/null +++ b/codex-ui/dev/pages/components/StubText.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/codex-ui/dev/routes.ts b/codex-ui/dev/routes.ts index 0ab61454..8334a2c2 100644 --- a/codex-ui/dev/routes.ts +++ b/codex-ui/dev/routes.ts @@ -28,6 +28,8 @@ import VerticalMenu from './pages/components/VerticalMenu.vue'; import ContextMenu from './pages/components/ContextMenu.vue'; import Editor from './pages/components/Editor.vue'; import ThemePreview from './pages/components/ThemePreview.vue'; +import Popup from './pages/components/Popup.vue'; +import Confirm from './pages/components/Confirm.vue'; /** * Vue router routes list @@ -145,6 +147,14 @@ const routes: RouteRecordRaw[] = [ path: '/components/theme-preview', component: ThemePreview as Component, }, + { + path: '/components/popup', + component: Popup as Component, + }, + { + path: '/components/confirm', + component: Confirm as Component, + }, ]; export default routes; diff --git a/codex-ui/src/styles/z-axis.pcss b/codex-ui/src/styles/z-axis.pcss index 0e7ac9c8..b818278f 100644 --- a/codex-ui/src/styles/z-axis.pcss +++ b/codex-ui/src/styles/z-axis.pcss @@ -1,3 +1,4 @@ :root { --z-popover: 3; + --z-popup: calc(var(--z-popover) + 1); } diff --git a/codex-ui/src/vue/components/confirm/Confirm.vue b/codex-ui/src/vue/components/confirm/Confirm.vue new file mode 100644 index 00000000..ff236dc4 --- /dev/null +++ b/codex-ui/src/vue/components/confirm/Confirm.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/codex-ui/src/vue/components/confirm/index.ts b/codex-ui/src/vue/components/confirm/index.ts new file mode 100644 index 00000000..fa42cc59 --- /dev/null +++ b/codex-ui/src/vue/components/confirm/index.ts @@ -0,0 +1,4 @@ +import Confirm from './Confirm.vue'; +export * from './useConfirm'; + +export { Confirm }; diff --git a/codex-ui/src/vue/components/confirm/useConfirm.ts b/codex-ui/src/vue/components/confirm/useConfirm.ts new file mode 100644 index 00000000..64049ee4 --- /dev/null +++ b/codex-ui/src/vue/components/confirm/useConfirm.ts @@ -0,0 +1,40 @@ +import { createSharedComposable } from '@vueuse/core'; +import { usePopup } from '../popup'; +import { Confirm } from '.'; + +export const useConfirm = createSharedComposable(() => { + /** + * Used to create a Popup component that will display the current Confirm + */ + const { showPopup, hidePopup } = usePopup(); + + /** + * @param title - title of the confirm window + * @param text - message to be displayed in confirm window + * @returns user selection result + */ + async function confirm(title: string, text: string): Promise { + return new Promise((resolve) => { + showPopup({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + component: Confirm, + props: { + title: title, + text: text, + onCancel: () => { + resolve(false); + hidePopup(); + }, + onConfirm: () => { + resolve(true); + hidePopup(); + }, + }, + }); + }); + } + + return { + confirm, + }; +}); diff --git a/codex-ui/src/vue/components/popup/Popup.types.ts b/codex-ui/src/vue/components/popup/Popup.types.ts new file mode 100644 index 00000000..e46fbb32 --- /dev/null +++ b/codex-ui/src/vue/components/popup/Popup.types.ts @@ -0,0 +1,14 @@ +import type { Component } from 'vue'; + +export interface PopupContent { + /** + * Component to render in the popup + */ + component: Component; + + /** + * Props to pass to the component + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + props: Record; +} diff --git a/codex-ui/src/vue/components/popup/Popup.vue b/codex-ui/src/vue/components/popup/Popup.vue new file mode 100644 index 00000000..22dbb5c3 --- /dev/null +++ b/codex-ui/src/vue/components/popup/Popup.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/codex-ui/src/vue/components/popup/index.ts b/codex-ui/src/vue/components/popup/index.ts new file mode 100644 index 00000000..ee05b748 --- /dev/null +++ b/codex-ui/src/vue/components/popup/index.ts @@ -0,0 +1,6 @@ +import Popup from './Popup.vue'; + +export * from './usePopup'; +export * from './Popup.types'; + +export { Popup }; diff --git a/codex-ui/src/vue/components/popup/usePopup.ts b/codex-ui/src/vue/components/popup/usePopup.ts new file mode 100644 index 00000000..2234a97c --- /dev/null +++ b/codex-ui/src/vue/components/popup/usePopup.ts @@ -0,0 +1,75 @@ +import { createSharedComposable } from '@vueuse/core'; +import { ref, shallowRef } from 'vue'; +import type { PopupContent } from './Popup.types'; + +/** + * Shared composable for the Popup component + * + * Popup is component empty container that appears on top of other components and contain any component + * @example + * function show() { + * showPopup({ + * component: Confirm, + * props: { + * title: 'CodeX', + * body: 'Are you sure you want to delete the page?', + * onCancel: onCancelFunction, + * onConfirm: onConfirmFunction, + * }, + * }); + * } + */ +export const usePopup = createSharedComposable(() => { + /** + * Popup open state + */ + const isOpen = ref(false); + + /** + * Popup content: component and props + */ + const content = shallowRef(null); + + /** + * Method for attaching a component to the popup + * @param component - component to attach + * @param props - props to pass to the component + */ + function mountComponent(component: PopupContent['component'], props: PopupContent['props']): void { + content.value = { + component, + props, + }; + } + + /** + * Show popup + */ + function show(): void { + isOpen.value = true; + } + + /** + * Mount component into popup and show it + * @param params - popup showing configuration + */ + function showPopup(params: PopupContent): void { + mountComponent(params.component, params.props); + show(); + } + + /** + * Сlear the content inside the popup and hide popup + */ + function hidePopup(): void { + content.value = null; + isOpen.value = false; + } + + return { + isOpen, + showPopup, + hidePopup, + content, + }; +}); diff --git a/codex-ui/src/vue/index.ts b/codex-ui/src/vue/index.ts index 64ae4d4c..38b8786c 100644 --- a/codex-ui/src/vue/index.ts +++ b/codex-ui/src/vue/index.ts @@ -16,4 +16,6 @@ export * from './components/vertical-menu'; export * from './components/colorShemeIcons'; export * from './components/theme-preview'; export * from './components/popover'; +export * from './components/popup'; +export * from './components/confirm'; export * from './composables/useTheme'; diff --git a/src/App.vue b/src/App.vue index 734172df..f90a7158 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,12 +2,13 @@
+