Skip to content

Commit

Permalink
Merge pull request #250 from codex-team/popover
Browse files Browse the repository at this point in the history
feat(ui): popover
  • Loading branch information
neSpecc authored Jul 9, 2024
2 parents 9dc82f3 + 39e2859 commit df8a51e
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 2 deletions.
4 changes: 3 additions & 1 deletion codex-ui/dev/Playground.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@
<router-view />
</div>
</div>
<Popover />
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import {
VerticalMenu,
Tabbar
Tabbar,
Popover
} from '../src/vue';
import { useTheme } from '../src/vue/composables/useTheme';
Expand Down
105 changes: 105 additions & 0 deletions codex-ui/dev/pages/components/Popover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,117 @@
Component that will appear near a particular element. Can contain any content.
</template>
</PageHeader>
<Heading
:level="2"
>
Aligning
</Heading>
You can choose vertical aligning from <code>below</code> and <code>above</code> and horizontal aligning from <code>left</code> and <code>right</code>.
<div class="buttons">
<div>
<Button
secondary
@click="show($event.target, {vertically: 'below', horizontally: 'left'})"
>
Open below left
</Button>
</div>

<div>
<Button
secondary
@click="show($event.target, {vertically: 'below', horizontally: 'right'})"
>
Open below right
</Button>
</div>

<div>
<Button
secondary
@click="show($event.target, {vertically: 'above', horizontally: 'left'})"
>
Open above left
</Button>
</div>

<div>
<Button
secondary
@click="show($event.target, {vertically: 'above', horizontally: 'right'})"
>
Open above right
</Button>
</div>
</div>

<Heading
:level="2"
>
Width
</Heading>

By default, width of the popover depends on its content. You can also set it to <code>fit-target</code> to stretch to the width of the target.

<div class="buttons">
<div>
<Button
secondary
@click="show($event.target, {vertically: 'below', horizontally: 'left'}, 'auto')"
>
"auto" (default)
</Button>
</div>

<div>
<Button
secondary
@click.capture="show($event.target, {vertically: 'below', horizontally: 'left'}, 'fit-target')"
>
"fit-target" to stretch to the width of the target
</Button>
</div>
</div>
</template>

<script setup lang="ts">
import PageHeader from '../../components/PageHeader.vue';
import { usePopover, PopoverShowParams, Button, ContextMenu, Heading } from '../../../src/vue';
const { showPopover } = usePopover();
/**
* Example of working with Popover
*
* @param el - element to show popover near
* @param align - vertical and horizontal aligning
* @param width - allows to stretch the popover to the width of the target
*/
function show(el: HTMLElement, align: PopoverShowParams['align'], width?: PopoverShowParams['width']) {
showPopover({
targetEl: el,
with: {
component: ContextMenu,
props: {
items: [
{ title: 'Item 1' },
{ title: 'Item 2' },
{ title: 'Item 3' },
],
},
},
align,
width,
});
}
</script>

<style scoped>
.buttons {
display: grid;
gap: var(--spacing-xl);
margin: var(--spacing-xl) 0 var(--spacing-xxl);
grid-template-columns: repeat(2, max-content);
}
</style>
1 change: 1 addition & 0 deletions codex-ui/src/styles/index.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
@import './dimensions.pcss';
@import './typography.pcss';
@import './mixins.pcss';
@import './z-axis.pcss';
3 changes: 3 additions & 0 deletions codex-ui/src/styles/z-axis.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:root {
--z-popover: 3;
}
45 changes: 45 additions & 0 deletions codex-ui/src/vue/components/popover/Popover.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Component } from 'vue';

/**
* Popover content: component and props
*/
export interface PopoverContent {
/**
* Component to render in the popover
*/
component: Component;

/**
* Props to pass to the component
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
props: Record<string, any>;
}

/**
* Popover showing configuration
*/
export interface PopoverShowParams {
/**
* Element to move popover to
*/
targetEl: HTMLElement;

/**
* Popover content: component and props
*/
with: PopoverContent;

/**
* Vertical and horizontal alignment
*/
align: {
vertically: 'above' | 'below';
horizontally: 'left' | 'right';
};

/**
* Allows to stretch popover to the target element width
*/
width?: 'fit-target' | 'auto';
}
54 changes: 54 additions & 0 deletions codex-ui/src/vue/components/popover/Popover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<div
v-show="isOpen"
ref="popoverEl"
:class="$style.popover"
>
<component
:is="content.component"
v-if="content"
v-bind="content.props"
/>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { usePopover } from './usePopover';
import { onClickOutside } from '@vueuse/core';
/**
* Reference to the popover element
* Used to bind click-outside event
*/
const popoverEl = ref<HTMLDivElement | null>(null);
const {
isOpen,
position,
hide,
content,
width,
} = usePopover();
/**
* Close the popover when clicking outside of it
*/
onClickOutside(popoverEl, hide);
</script>

<style module>
.popover {
position: absolute;
z-index: var(--z-popover);
background-color: var(--base--bg-secondary);
border-radius: var(--radius-field);
border: 1px solid var(--base--border);
padding: var(--h-padding);
left: v-bind('position.left');
top: v-bind('position.top');
transform: v-bind('position.transform');
width: v-bind('width');
box-sizing: border-box;
}
</style>
5 changes: 5 additions & 0 deletions codex-ui/src/vue/components/popover/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Popover from './Popover.vue';

export * from './usePopover';
export * from './Popover.types';
export { Popover };
Loading

0 comments on commit df8a51e

Please sign in to comment.