@umbra.ui/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/controls/Dropdown/types.d.ts +5 -0
- package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
- package/dist/components/controls/Dropdown/types.js +1 -0
- package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
- package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
- package/dist/components/controls/SegmentedControl/types.js +1 -0
- package/dist/components/dialogs/Alert/types.d.ts +7 -0
- package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
- package/dist/components/dialogs/Alert/types.js +1 -0
- package/dist/components/dialogs/Toast/types.d.ts +34 -0
- package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/types.js +10 -0
- package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
- package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/useToast.js +90 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/tooltip.js +33 -0
- package/dist/components/indicators/Tooltip/types.d.ts +14 -0
- package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/types.js +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
- package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
- package/dist/components/inputs/Tags/types.d.ts +93 -0
- package/dist/components/inputs/Tags/types.d.ts.map +1 -0
- package/dist/components/inputs/Tags/types.js +216 -0
- package/dist/components/inputs/search/types.d.ts +9 -0
- package/dist/components/inputs/search/types.d.ts.map +1 -0
- package/dist/components/inputs/search/types.js +1 -0
- package/dist/components/navigation/adaptive/types.d.ts +16 -0
- package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/types.js +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewResize.js +146 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
- package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
- package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
- package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
- package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
- package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/types.js +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/navigation/types.d.ts.map +1 -0
- package/dist/components/navigation/types.js +1 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
- package/dist/components/pickers/CollectionPicker/types.js +1 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
- package/dist/components/pickers/ColorPicker/colors.js +266 -0
- package/dist/components/pickers/FilePicker/types.d.ts +10 -0
- package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
- package/dist/components/pickers/FilePicker/types.js +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/theme.d.ts +73 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +279 -0
- package/dist/themes/blank.d.ts +7 -0
- package/dist/themes/blank.d.ts.map +1 -0
- package/dist/themes/blank.js +543 -0
- package/dist/themes/crimson-dark.d.ts +4 -0
- package/dist/themes/crimson-dark.d.ts.map +1 -0
- package/dist/themes/crimson-dark.js +552 -0
- package/dist/themes/cyan-light.d.ts +4 -0
- package/dist/themes/cyan-light.d.ts.map +1 -0
- package/dist/themes/cyan-light.js +552 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +551 -0
- package/dist/themes/gold-dark.d.ts +4 -0
- package/dist/themes/gold-dark.d.ts.map +1 -0
- package/dist/themes/gold-dark.js +552 -0
- package/dist/themes/grass-dark.d.ts +4 -0
- package/dist/themes/grass-dark.d.ts.map +1 -0
- package/dist/themes/grass-dark.js +552 -0
- package/dist/themes/indigo.d.ts +4 -0
- package/dist/themes/indigo.d.ts.map +1 -0
- package/dist/themes/indigo.js +552 -0
- package/dist/themes/light.d.ts +4 -0
- package/dist/themes/light.d.ts.map +1 -0
- package/dist/themes/light.js +551 -0
- package/dist/themes/orange-dark.d.ts +4 -0
- package/dist/themes/orange-dark.d.ts.map +1 -0
- package/dist/themes/orange-dark.js +551 -0
- package/dist/themes/orange-light.d.ts +4 -0
- package/dist/themes/orange-light.d.ts.map +1 -0
- package/dist/themes/orange-light.js +551 -0
- package/package.json +62 -0
- package/src/components/controls/Button/Button.vue +417 -0
- package/src/components/controls/Button/README.md +348 -0
- package/src/components/controls/Button/theme.css +200 -0
- package/src/components/controls/Checkbox/Checkbox.vue +164 -0
- package/src/components/controls/Checkbox/README.md +441 -0
- package/src/components/controls/Checkbox/theme.css +36 -0
- package/src/components/controls/Dropdown/Dropdown.vue +476 -0
- package/src/components/controls/Dropdown/README.md +370 -0
- package/src/components/controls/Dropdown/theme.css +50 -0
- package/src/components/controls/Dropdown/types.ts +6 -0
- package/src/components/controls/IconButton/IconButton.vue +267 -0
- package/src/components/controls/IconButton/README.md +502 -0
- package/src/components/controls/IconButton/theme.css +89 -0
- package/src/components/controls/Radio/README.md +591 -0
- package/src/components/controls/Radio/Radio.vue +89 -0
- package/src/components/controls/Radio/theme.css +14 -0
- package/src/components/controls/RangeSlider/README.md +608 -0
- package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
- package/src/components/controls/RangeSlider/theme.css +80 -0
- package/src/components/controls/SegmentedControl/README.md +587 -0
- package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
- package/src/components/controls/SegmentedControl/theme.css +60 -0
- package/src/components/controls/SegmentedControl/types.ts +5 -0
- package/src/components/controls/Slider/README.md +627 -0
- package/src/components/controls/Slider/Slider.vue +260 -0
- package/src/components/controls/Slider/theme.css +74 -0
- package/src/components/controls/Stepper/README.md +601 -0
- package/src/components/controls/Stepper/Stepper.vue +103 -0
- package/src/components/controls/Stepper/theme.css +53 -0
- package/src/components/controls/Switch/README.md +667 -0
- package/src/components/controls/Switch/Switch.vue +127 -0
- package/src/components/controls/Switch/theme.css +42 -0
- package/src/components/dialogs/Alert/Alert.vue +218 -0
- package/src/components/dialogs/Alert/README.md +450 -0
- package/src/components/dialogs/Alert/theme.css +44 -0
- package/src/components/dialogs/Alert/types.ts +11 -0
- package/src/components/dialogs/Toast/README.md +522 -0
- package/src/components/dialogs/Toast/Toast.vue +296 -0
- package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
- package/src/components/dialogs/Toast/theme.css +44 -0
- package/src/components/dialogs/Toast/types.ts +46 -0
- package/src/components/dialogs/Toast/useToast.ts +127 -0
- package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
- package/src/components/indicators/ProgressBar/README.md +744 -0
- package/src/components/indicators/ProgressBar/theme.css +36 -0
- package/src/components/indicators/Tooltip/README.md +723 -0
- package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
- package/src/components/indicators/Tooltip/theme.css +18 -0
- package/src/components/indicators/Tooltip/tooltip.ts +48 -0
- package/src/components/indicators/Tooltip/types.ts +15 -0
- package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
- package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
- package/src/components/inputs/AutogrowTextView/README.md +643 -0
- package/src/components/inputs/AutogrowTextView/theme.css +28 -0
- package/src/components/inputs/InputCard/InputCard.vue +600 -0
- package/src/components/inputs/InputCard/README.md +636 -0
- package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
- package/src/components/inputs/InputEmail/README.md +764 -0
- package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
- package/src/components/inputs/InputNumber/README.md +749 -0
- package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
- package/src/components/inputs/InputPhone/README.md +636 -0
- package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
- package/src/components/inputs/InputSecure/README.md +771 -0
- package/src/components/inputs/InputText/InputText.vue +225 -0
- package/src/components/inputs/InputText/README.md +844 -0
- package/src/components/inputs/OTP/OTP.vue +349 -0
- package/src/components/inputs/OTP/README.md +736 -0
- package/src/components/inputs/OTP/theme.css +50 -0
- package/src/components/inputs/StringCapture/README.md +718 -0
- package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
- package/src/components/inputs/StringCapture/theme.css +86 -0
- package/src/components/inputs/Tags/README.md +897 -0
- package/src/components/inputs/Tags/TagBar.vue +793 -0
- package/src/components/inputs/Tags/TagCreation.vue +219 -0
- package/src/components/inputs/Tags/TagPicker.vue +380 -0
- package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
- package/src/components/inputs/Tags/theme.css +121 -0
- package/src/components/inputs/Tags/types.ts +346 -0
- package/src/components/inputs/search/README.md +759 -0
- package/src/components/inputs/search/SearchBar.vue +394 -0
- package/src/components/inputs/search/SearchResults.vue +310 -0
- package/src/components/inputs/search/theme.css +187 -0
- package/src/components/inputs/search/types.ts +8 -0
- package/src/components/inputs/theme.css +102 -0
- package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
- package/src/components/menus/ActionMenu/README.md +825 -0
- package/src/components/menus/ActionMenu/theme.css +93 -0
- package/src/components/models/Popover/Popover.vue +551 -0
- package/src/components/models/Popover/README.md +885 -0
- package/src/components/models/Popover/theme.css +52 -0
- package/src/components/models/Sheet/README.md +1159 -0
- package/src/components/models/Sheet/Sheet.vue +465 -0
- package/src/components/models/Sheet/theme.css +72 -0
- package/src/components/models/Sidebar/README.md +1228 -0
- package/src/components/models/Sidebar/Sidebar.vue +480 -0
- package/src/components/models/Sidebar/theme.css +90 -0
- package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
- package/src/components/navigation/adaptive/README.md +768 -0
- package/src/components/navigation/adaptive/types.ts +19 -0
- package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
- package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
- package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
- package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
- package/src/components/navigation/adaptive/useViewResize.ts +211 -0
- package/src/components/navigation/navstack/NavigationStack.vue +180 -0
- package/src/components/navigation/navstack/README.md +994 -0
- package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
- package/src/components/navigation/slideover/README.md +1275 -0
- package/src/components/navigation/slideover/SlideoverController.vue +287 -0
- package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
- package/src/components/navigation/splitview/README.md +1115 -0
- package/src/components/navigation/splitview/SplitViewController.vue +176 -0
- package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
- package/src/components/navigation/tabcontroller/README.md +919 -0
- package/src/components/navigation/tabcontroller/TabController.vue +307 -0
- package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
- package/src/components/navigation/tabcontroller/types.ts +24 -0
- package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
- package/src/components/navigation/theme.css +91 -0
- package/src/components/navigation/types.ts +7 -0
- package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
- package/src/components/pickers/CollectionPicker/README.md +1115 -0
- package/src/components/pickers/CollectionPicker/theme.css +14 -0
- package/src/components/pickers/CollectionPicker/types.ts +11 -0
- package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
- package/src/components/pickers/ColorPicker/README.md +1439 -0
- package/src/components/pickers/ColorPicker/colors.ts +299 -0
- package/src/components/pickers/ColorPicker/theme.css +32 -0
- package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
- package/src/components/pickers/DatePicker/README.md +1195 -0
- package/src/components/pickers/DatePicker/theme.css +22 -0
- package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
- package/src/components/pickers/FilePicker/README.md +1542 -0
- package/src/components/pickers/FilePicker/theme.css +48 -0
- package/src/components/pickers/FilePicker/types.ts +10 -0
- package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
- package/src/components/pickers/IconPicker/README.md +1161 -0
- package/src/components/pickers/IconPicker/theme.css +28 -0
- package/src/components/pickers/theme.css +82 -0
- package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
- package/src/components/views/MarkdownViewer/README.md +833 -0
- package/src/components/views/MarkdownViewer/theme.css +130 -0
- package/src/index.ts +263 -0
- package/src/theme.ts +378 -0
- package/src/themes/crimson-dark.ts +556 -0
- package/src/themes/cyan-light.ts +556 -0
- package/src/themes/dark.ts +557 -0
- package/src/themes/gold-dark.ts +556 -0
- package/src/themes/grass-dark.ts +556 -0
- package/src/themes/indigo.ts +556 -0
- package/src/themes/light.ts +557 -0
- package/src/themes/orange-dark.ts +557 -0
- package/src/themes/orange-light.ts +557 -0
- package/src/vue.d.ts +45 -0
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
A flexible and feature-rich popover component built with Vue 3 Composition API and TypeScript. The Popover component provides a powerful interface for displaying contextual content with smart positioning, smooth animations, and comprehensive customization options.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Popover } from "@umbra-ui/core";
|
|
9
|
+
import type { PopoverProps } from "@umbra-ui/core";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Dependencies:**
|
|
13
|
+
|
|
14
|
+
- Vue 3.x
|
|
15
|
+
- @floating-ui/vue (for positioning)
|
|
16
|
+
- gsap (for animations)
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```vue
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { ref } from "vue";
|
|
23
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
24
|
+
|
|
25
|
+
const isPopoverOpen = ref(false);
|
|
26
|
+
|
|
27
|
+
const handleOpen = () => {
|
|
28
|
+
console.log("Popover opened");
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleClose = () => {
|
|
32
|
+
console.log("Popover closed");
|
|
33
|
+
};
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div>
|
|
38
|
+
<Popover
|
|
39
|
+
v-model="isPopoverOpen"
|
|
40
|
+
placement="bottom"
|
|
41
|
+
:show-arrow="true"
|
|
42
|
+
@open="handleOpen"
|
|
43
|
+
@close="handleClose"
|
|
44
|
+
>
|
|
45
|
+
<template #trigger>
|
|
46
|
+
<Button>Open Popover</Button>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<div class="popover-content">
|
|
50
|
+
<h3>Popover Title</h3>
|
|
51
|
+
<p>This is the popover content. It can contain any HTML elements.</p>
|
|
52
|
+
<Button @click="isPopoverOpen = false">Close</Button>
|
|
53
|
+
</div>
|
|
54
|
+
</Popover>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<style>
|
|
59
|
+
.popover-content {
|
|
60
|
+
padding: 1rem;
|
|
61
|
+
min-width: 200px;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Props
|
|
67
|
+
|
|
68
|
+
| Prop Name | Type | Required | Default | Description |
|
|
69
|
+
| ----------------------- | -------------------- | -------- | ---------- | --------------------------------------------- |
|
|
70
|
+
| `modelValue` | `boolean` | Yes | - | Controls the open/closed state of the popover |
|
|
71
|
+
| `placement` | `Placement` | No | `"bottom"` | Placement relative to trigger element |
|
|
72
|
+
| `offsetDistance` | `number` | No | `8` | Distance from trigger element in pixels |
|
|
73
|
+
| `dismissOnClickOutside` | `boolean` | No | `true` | Whether clicking outside closes the popover |
|
|
74
|
+
| `showArrow` | `boolean` | No | `true` | Whether to show an arrow pointing to trigger |
|
|
75
|
+
| `showOverlay` | `boolean` | No | `false` | Whether to show a backdrop overlay |
|
|
76
|
+
| `overlayOpacity` | `number` | No | `0.5` | Overlay opacity (0-1) |
|
|
77
|
+
| `animationDuration` | `number` | No | `0.2` | Animation duration in seconds |
|
|
78
|
+
| `zIndex` | `number` | No | `1000` | Z-index for the popover |
|
|
79
|
+
| `viewportPadding` | `number` | No | `16` | Padding from viewport edges |
|
|
80
|
+
| `maxWidth` | `string` | No | `"none"` | Maximum width of the popover |
|
|
81
|
+
| `maxHeight` | `string` | No | `"none"` | Maximum height of the popover |
|
|
82
|
+
| `trigger` | `"click" \| "hover"` | No | `"click"` | Trigger event type |
|
|
83
|
+
| `hoverShowDelay` | `number` | No | `0` | Delay before showing on hover (ms) |
|
|
84
|
+
| `hoverHideDelay` | `number` | No | `0` | Delay before hiding on hover (ms) |
|
|
85
|
+
|
|
86
|
+
## Events
|
|
87
|
+
|
|
88
|
+
| Event Name | Payload Type | Description |
|
|
89
|
+
| ------------------- | ------------ | ------------------------------------------- |
|
|
90
|
+
| `update:modelValue` | `boolean` | Emitted when the popover open state changes |
|
|
91
|
+
| `open` | `void` | Emitted when the popover opens |
|
|
92
|
+
| `close` | `void` | Emitted when the popover closes |
|
|
93
|
+
| `after-enter` | `void` | Emitted after the open animation completes |
|
|
94
|
+
| `after-leave` | `void` | Emitted after the close animation completes |
|
|
95
|
+
|
|
96
|
+
## Slots
|
|
97
|
+
|
|
98
|
+
| Slot Name | Description |
|
|
99
|
+
| --------- | ---------------------------------------- |
|
|
100
|
+
| `trigger` | The element that triggers the popover |
|
|
101
|
+
| `default` | The content displayed inside the popover |
|
|
102
|
+
|
|
103
|
+
## Exposed Methods/Refs
|
|
104
|
+
|
|
105
|
+
The Popover component exposes the following methods and properties via template refs:
|
|
106
|
+
|
|
107
|
+
| Method/Property | Type | Description |
|
|
108
|
+
| ---------------- | -------------- | -------------------------------------- |
|
|
109
|
+
| `open` | `() => void` | Opens the popover programmatically |
|
|
110
|
+
| `close` | `() => void` | Closes the popover programmatically |
|
|
111
|
+
| `isVisible` | `Ref<boolean>` | Reactive reference to visibility state |
|
|
112
|
+
| `isAnimating` | `Ref<boolean>` | Reactive reference to animation state |
|
|
113
|
+
| `updatePosition` | `() => void` | Updates the popover position |
|
|
114
|
+
|
|
115
|
+
### Example Usage
|
|
116
|
+
|
|
117
|
+
```vue
|
|
118
|
+
<script setup lang="ts">
|
|
119
|
+
import { ref } from "vue";
|
|
120
|
+
import { Popover } from "@umbra-ui/core";
|
|
121
|
+
|
|
122
|
+
const popoverRef = ref<InstanceType<typeof Popover> | null>(null);
|
|
123
|
+
|
|
124
|
+
const openPopover = () => {
|
|
125
|
+
popoverRef.value?.open();
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const closePopover = () => {
|
|
129
|
+
popoverRef.value?.close();
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const updatePosition = () => {
|
|
133
|
+
popoverRef.value?.updatePosition();
|
|
134
|
+
};
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<template>
|
|
138
|
+
<Popover ref="popoverRef" :model-value="false">
|
|
139
|
+
<template #trigger>
|
|
140
|
+
<button @click="openPopover">Open</button>
|
|
141
|
+
</template>
|
|
142
|
+
|
|
143
|
+
<div class="content">
|
|
144
|
+
<p>Popover content</p>
|
|
145
|
+
<button @click="closePopover">Close</button>
|
|
146
|
+
</div>
|
|
147
|
+
</Popover>
|
|
148
|
+
</template>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Placement Options
|
|
152
|
+
|
|
153
|
+
The `placement` prop accepts the following values from Floating UI:
|
|
154
|
+
|
|
155
|
+
- `"top"` - Above the trigger
|
|
156
|
+
- `"top-start"` - Above the trigger, aligned to start
|
|
157
|
+
- `"top-end"` - Above the trigger, aligned to end
|
|
158
|
+
- `"bottom"` - Below the trigger (default)
|
|
159
|
+
- `"bottom-start"` - Below the trigger, aligned to start
|
|
160
|
+
- `"bottom-end"` - Below the trigger, aligned to end
|
|
161
|
+
- `"left"` - To the left of the trigger
|
|
162
|
+
- `"left-start"` - To the left of the trigger, aligned to start
|
|
163
|
+
- `"left-end"` - To the left of the trigger, aligned to end
|
|
164
|
+
- `"right"` - To the right of the trigger
|
|
165
|
+
- `"right-start"` - To the right of the trigger, aligned to start
|
|
166
|
+
- `"right-end"` - To the right of the trigger, aligned to end
|
|
167
|
+
|
|
168
|
+
## CSS Customization
|
|
169
|
+
|
|
170
|
+
The Popover component uses CSS custom properties for theming and customization:
|
|
171
|
+
|
|
172
|
+
### Light Theme Variables
|
|
173
|
+
|
|
174
|
+
```css
|
|
175
|
+
/* Popover colors */
|
|
176
|
+
--popover-bg: #ffffff;
|
|
177
|
+
--popover-border: 1px solid rgba(0, 0, 0, 0.1);
|
|
178
|
+
--popover-shadow: none;
|
|
179
|
+
--popover-inset-shadow: rgba(255, 255, 255, 0.8);
|
|
180
|
+
|
|
181
|
+
/* Popover arrow colors */
|
|
182
|
+
--popover-arrow-bg: #ffffff;
|
|
183
|
+
--popover-arrow-shadow: rgba(0, 0, 0, 0.05);
|
|
184
|
+
|
|
185
|
+
/* Popover overlay colors */
|
|
186
|
+
--popover-overlay-bg: rgba(0, 0, 0, 0.5);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Dark Theme Variables
|
|
190
|
+
|
|
191
|
+
```css
|
|
192
|
+
/* Popover colors */
|
|
193
|
+
--popover-bg: #484848;
|
|
194
|
+
--popover-border: none;
|
|
195
|
+
--popover-shadow: rgba(0, 0, 0, 0.21);
|
|
196
|
+
--popover-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
197
|
+
|
|
198
|
+
/* Popover arrow colors */
|
|
199
|
+
--popover-arrow-bg: #484848;
|
|
200
|
+
--popover-arrow-shadow: rgba(0, 0, 0, 0.05);
|
|
201
|
+
|
|
202
|
+
/* Popover overlay colors */
|
|
203
|
+
--popover-overlay-bg: rgba(0, 0, 0, 0.5);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Key Features
|
|
207
|
+
|
|
208
|
+
### Smart Positioning
|
|
209
|
+
|
|
210
|
+
- **Floating UI Integration**: Uses Floating UI for intelligent positioning
|
|
211
|
+
- **Auto-flip**: Automatically flips to opposite side if no space available
|
|
212
|
+
- **Auto-shift**: Shifts position to stay within viewport bounds
|
|
213
|
+
- **Viewport Padding**: Respects viewport boundaries with configurable padding
|
|
214
|
+
|
|
215
|
+
### Animation System
|
|
216
|
+
|
|
217
|
+
- **GSAP Animations**: Smooth, performant animations using GSAP
|
|
218
|
+
- **Directional Animations**: Animations adapt to popover placement
|
|
219
|
+
- **Customizable Duration**: Configurable animation timing
|
|
220
|
+
- **Easing Functions**: Professional easing for natural motion
|
|
221
|
+
|
|
222
|
+
### Trigger Options
|
|
223
|
+
|
|
224
|
+
- **Click Trigger**: Standard click-to-toggle behavior
|
|
225
|
+
- **Hover Trigger**: Hover to show with configurable delays
|
|
226
|
+
- **Keyboard Support**: Escape key closes popover
|
|
227
|
+
- **Click Outside**: Configurable click-outside-to-close
|
|
228
|
+
|
|
229
|
+
### Visual Features
|
|
230
|
+
|
|
231
|
+
- **Arrow Support**: Optional arrow pointing to trigger element
|
|
232
|
+
- **Overlay Backdrop**: Optional semi-transparent overlay
|
|
233
|
+
- **Custom Styling**: Full CSS customization support
|
|
234
|
+
- **Z-index Management**: Configurable layering
|
|
235
|
+
|
|
236
|
+
## Examples
|
|
237
|
+
|
|
238
|
+
### Basic Popover
|
|
239
|
+
|
|
240
|
+
```vue
|
|
241
|
+
<script setup lang="ts">
|
|
242
|
+
import { ref } from "vue";
|
|
243
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
244
|
+
|
|
245
|
+
const isOpen = ref(false);
|
|
246
|
+
|
|
247
|
+
const handleOpen = () => {
|
|
248
|
+
console.log("Popover opened");
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const handleClose = () => {
|
|
252
|
+
console.log("Popover closed");
|
|
253
|
+
};
|
|
254
|
+
</script>
|
|
255
|
+
|
|
256
|
+
<template>
|
|
257
|
+
<div class="basic-popover">
|
|
258
|
+
<h3>Basic Popover</h3>
|
|
259
|
+
|
|
260
|
+
<Popover
|
|
261
|
+
v-model="isOpen"
|
|
262
|
+
placement="bottom"
|
|
263
|
+
:show-arrow="true"
|
|
264
|
+
@open="handleOpen"
|
|
265
|
+
@close="handleClose"
|
|
266
|
+
>
|
|
267
|
+
<template #trigger>
|
|
268
|
+
<Button>Click to Open</Button>
|
|
269
|
+
</template>
|
|
270
|
+
|
|
271
|
+
<div class="popover-content">
|
|
272
|
+
<h4>Popover Title</h4>
|
|
273
|
+
<p>This is a basic popover with default settings.</p>
|
|
274
|
+
<div class="actions">
|
|
275
|
+
<Button @click="isOpen = false" size="small">Close</Button>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</Popover>
|
|
279
|
+
|
|
280
|
+
<p class="status">Popover is {{ isOpen ? "open" : "closed" }}</p>
|
|
281
|
+
</div>
|
|
282
|
+
</template>
|
|
283
|
+
|
|
284
|
+
<style module>
|
|
285
|
+
.basic-popover {
|
|
286
|
+
padding: 2rem;
|
|
287
|
+
border: 1px solid #e0e0e0;
|
|
288
|
+
border-radius: 0.5rem;
|
|
289
|
+
max-width: 400px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.popover-content {
|
|
293
|
+
padding: 1rem;
|
|
294
|
+
min-width: 200px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.popover-content h4 {
|
|
298
|
+
margin: 0 0 0.5rem 0;
|
|
299
|
+
color: #333;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.popover-content p {
|
|
303
|
+
margin: 0 0 1rem 0;
|
|
304
|
+
color: #666;
|
|
305
|
+
line-height: 1.5;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.actions {
|
|
309
|
+
display: flex;
|
|
310
|
+
gap: 0.5rem;
|
|
311
|
+
justify-content: flex-end;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.status {
|
|
315
|
+
margin-top: 1rem;
|
|
316
|
+
color: #666;
|
|
317
|
+
font-size: 0.875rem;
|
|
318
|
+
}
|
|
319
|
+
</style>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Hover Popover
|
|
323
|
+
|
|
324
|
+
```vue
|
|
325
|
+
<script setup lang="ts">
|
|
326
|
+
import { ref } from "vue";
|
|
327
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
328
|
+
|
|
329
|
+
const isHoverOpen = ref(false);
|
|
330
|
+
</script>
|
|
331
|
+
|
|
332
|
+
<template>
|
|
333
|
+
<div class="hover-popover">
|
|
334
|
+
<h3>Hover Popover</h3>
|
|
335
|
+
<p>Hover over the button to see the popover:</p>
|
|
336
|
+
|
|
337
|
+
<Popover
|
|
338
|
+
v-model="isHoverOpen"
|
|
339
|
+
trigger="hover"
|
|
340
|
+
placement="top"
|
|
341
|
+
:hover-show-delay="300"
|
|
342
|
+
:hover-hide-delay="200"
|
|
343
|
+
:show-arrow="true"
|
|
344
|
+
>
|
|
345
|
+
<template #trigger>
|
|
346
|
+
<Button>Hover Me</Button>
|
|
347
|
+
</template>
|
|
348
|
+
|
|
349
|
+
<div class="popover-content">
|
|
350
|
+
<h4>Hover Popover</h4>
|
|
351
|
+
<p>This popover appears on hover with a delay.</p>
|
|
352
|
+
<ul>
|
|
353
|
+
<li>300ms delay before showing</li>
|
|
354
|
+
<li>200ms delay before hiding</li>
|
|
355
|
+
<li>Stays open while hovering over content</li>
|
|
356
|
+
</ul>
|
|
357
|
+
</div>
|
|
358
|
+
</Popover>
|
|
359
|
+
</div>
|
|
360
|
+
</template>
|
|
361
|
+
|
|
362
|
+
<style module>
|
|
363
|
+
.hover-popover {
|
|
364
|
+
padding: 2rem;
|
|
365
|
+
border: 1px solid #e0e0e0;
|
|
366
|
+
border-radius: 0.5rem;
|
|
367
|
+
max-width: 400px;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.popover-content {
|
|
371
|
+
padding: 1rem;
|
|
372
|
+
min-width: 250px;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.popover-content h4 {
|
|
376
|
+
margin: 0 0 0.5rem 0;
|
|
377
|
+
color: #333;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.popover-content p {
|
|
381
|
+
margin: 0 0 0.75rem 0;
|
|
382
|
+
color: #666;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.popover-content ul {
|
|
386
|
+
margin: 0;
|
|
387
|
+
padding-left: 1.25rem;
|
|
388
|
+
color: #666;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.popover-content li {
|
|
392
|
+
margin-bottom: 0.25rem;
|
|
393
|
+
}
|
|
394
|
+
</style>
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Popover with Overlay
|
|
398
|
+
|
|
399
|
+
```vue
|
|
400
|
+
<script setup lang="ts">
|
|
401
|
+
import { ref } from "vue";
|
|
402
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
403
|
+
|
|
404
|
+
const isOverlayOpen = ref(false);
|
|
405
|
+
</script>
|
|
406
|
+
|
|
407
|
+
<template>
|
|
408
|
+
<div class="overlay-popover">
|
|
409
|
+
<h3>Popover with Overlay</h3>
|
|
410
|
+
|
|
411
|
+
<Popover
|
|
412
|
+
v-model="isOverlayOpen"
|
|
413
|
+
placement="center"
|
|
414
|
+
:show-overlay="true"
|
|
415
|
+
:overlay-opacity="0.7"
|
|
416
|
+
:dismiss-on-click-outside="true"
|
|
417
|
+
:show-arrow="false"
|
|
418
|
+
>
|
|
419
|
+
<template #trigger>
|
|
420
|
+
<Button>Open Modal Popover</Button>
|
|
421
|
+
</template>
|
|
422
|
+
|
|
423
|
+
<div class="modal-content">
|
|
424
|
+
<h4>Modal Popover</h4>
|
|
425
|
+
<p>This popover has a backdrop overlay and behaves like a modal.</p>
|
|
426
|
+
<p>Click outside or press Escape to close.</p>
|
|
427
|
+
<div class="actions">
|
|
428
|
+
<Button @click="isOverlayOpen = false" variant="secondary"
|
|
429
|
+
>Cancel</Button
|
|
430
|
+
>
|
|
431
|
+
<Button @click="isOverlayOpen = false">Confirm</Button>
|
|
432
|
+
</div>
|
|
433
|
+
</div>
|
|
434
|
+
</Popover>
|
|
435
|
+
</div>
|
|
436
|
+
</template>
|
|
437
|
+
|
|
438
|
+
<style module>
|
|
439
|
+
.overlay-popover {
|
|
440
|
+
padding: 2rem;
|
|
441
|
+
border: 1px solid #e0e0e0;
|
|
442
|
+
border-radius: 0.5rem;
|
|
443
|
+
max-width: 400px;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.modal-content {
|
|
447
|
+
padding: 1.5rem;
|
|
448
|
+
min-width: 300px;
|
|
449
|
+
text-align: center;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.modal-content h4 {
|
|
453
|
+
margin: 0 0 1rem 0;
|
|
454
|
+
color: #333;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.modal-content p {
|
|
458
|
+
margin: 0 0 0.75rem 0;
|
|
459
|
+
color: #666;
|
|
460
|
+
line-height: 1.5;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.actions {
|
|
464
|
+
display: flex;
|
|
465
|
+
gap: 0.75rem;
|
|
466
|
+
justify-content: center;
|
|
467
|
+
margin-top: 1.5rem;
|
|
468
|
+
}
|
|
469
|
+
</style>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Different Placements
|
|
473
|
+
|
|
474
|
+
```vue
|
|
475
|
+
<script setup lang="ts">
|
|
476
|
+
import { ref } from "vue";
|
|
477
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
478
|
+
|
|
479
|
+
const placements = [
|
|
480
|
+
"top",
|
|
481
|
+
"top-start",
|
|
482
|
+
"top-end",
|
|
483
|
+
"bottom",
|
|
484
|
+
"bottom-start",
|
|
485
|
+
"bottom-end",
|
|
486
|
+
"left",
|
|
487
|
+
"left-start",
|
|
488
|
+
"left-end",
|
|
489
|
+
"right",
|
|
490
|
+
"right-start",
|
|
491
|
+
"right-end",
|
|
492
|
+
];
|
|
493
|
+
|
|
494
|
+
const openPopovers = ref<Record<string, boolean>>({});
|
|
495
|
+
|
|
496
|
+
const togglePopover = (placement: string) => {
|
|
497
|
+
openPopovers.value[placement] = !openPopovers.value[placement];
|
|
498
|
+
};
|
|
499
|
+
</script>
|
|
500
|
+
|
|
501
|
+
<template>
|
|
502
|
+
<div class="placement-demo">
|
|
503
|
+
<h3>Popover Placements</h3>
|
|
504
|
+
<p>Click the buttons to see different placement options:</p>
|
|
505
|
+
|
|
506
|
+
<div class="placement-grid">
|
|
507
|
+
<div
|
|
508
|
+
v-for="placement in placements"
|
|
509
|
+
:key="placement"
|
|
510
|
+
class="placement-item"
|
|
511
|
+
>
|
|
512
|
+
<Popover
|
|
513
|
+
v-model="openPopovers[placement]"
|
|
514
|
+
:placement="placement"
|
|
515
|
+
:show-arrow="true"
|
|
516
|
+
>
|
|
517
|
+
<template #trigger>
|
|
518
|
+
<Button @click="togglePopover(placement)" size="small">
|
|
519
|
+
{{ placement }}
|
|
520
|
+
</Button>
|
|
521
|
+
</template>
|
|
522
|
+
|
|
523
|
+
<div class="placement-content">
|
|
524
|
+
<h5>{{ placement }}</h5>
|
|
525
|
+
<p>This popover is positioned {{ placement }} of the trigger.</p>
|
|
526
|
+
</div>
|
|
527
|
+
</Popover>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
</div>
|
|
531
|
+
</template>
|
|
532
|
+
|
|
533
|
+
<style module>
|
|
534
|
+
.placement-demo {
|
|
535
|
+
padding: 2rem;
|
|
536
|
+
border: 1px solid #e0e0e0;
|
|
537
|
+
border-radius: 0.5rem;
|
|
538
|
+
max-width: 800px;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.placement-grid {
|
|
542
|
+
display: grid;
|
|
543
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
544
|
+
gap: 1rem;
|
|
545
|
+
margin-top: 1rem;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.placement-item {
|
|
549
|
+
display: flex;
|
|
550
|
+
justify-content: center;
|
|
551
|
+
align-items: center;
|
|
552
|
+
min-height: 60px;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.placement-content {
|
|
556
|
+
padding: 1rem;
|
|
557
|
+
min-width: 200px;
|
|
558
|
+
text-align: center;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.placement-content h5 {
|
|
562
|
+
margin: 0 0 0.5rem 0;
|
|
563
|
+
color: #333;
|
|
564
|
+
text-transform: capitalize;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.placement-content p {
|
|
568
|
+
margin: 0;
|
|
569
|
+
color: #666;
|
|
570
|
+
font-size: 0.875rem;
|
|
571
|
+
}
|
|
572
|
+
</style>
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Custom Styled Popover
|
|
576
|
+
|
|
577
|
+
```vue
|
|
578
|
+
<script setup lang="ts">
|
|
579
|
+
import { ref } from "vue";
|
|
580
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
581
|
+
|
|
582
|
+
const isCustomOpen = ref(false);
|
|
583
|
+
</script>
|
|
584
|
+
|
|
585
|
+
<template>
|
|
586
|
+
<div class="custom-popover">
|
|
587
|
+
<h3>Custom Styled Popover</h3>
|
|
588
|
+
|
|
589
|
+
<Popover
|
|
590
|
+
v-model="isCustomOpen"
|
|
591
|
+
placement="bottom"
|
|
592
|
+
:show-arrow="true"
|
|
593
|
+
:animation-duration="0.3"
|
|
594
|
+
max-width="400px"
|
|
595
|
+
>
|
|
596
|
+
<template #trigger>
|
|
597
|
+
<Button class="custom-trigger">Custom Style</Button>
|
|
598
|
+
</template>
|
|
599
|
+
|
|
600
|
+
<div class="custom-content">
|
|
601
|
+
<div class="custom-header">
|
|
602
|
+
<h4>Custom Popover</h4>
|
|
603
|
+
<button @click="isCustomOpen = false" class="close-btn">×</button>
|
|
604
|
+
</div>
|
|
605
|
+
<div class="custom-body">
|
|
606
|
+
<p>This popover has custom styling with:</p>
|
|
607
|
+
<ul>
|
|
608
|
+
<li>Custom colors and gradients</li>
|
|
609
|
+
<li>Rounded corners and shadows</li>
|
|
610
|
+
<li>Custom header with close button</li>
|
|
611
|
+
<li>Longer animation duration</li>
|
|
612
|
+
</ul>
|
|
613
|
+
</div>
|
|
614
|
+
<div class="custom-footer">
|
|
615
|
+
<Button @click="isCustomOpen = false" size="small">Got it!</Button>
|
|
616
|
+
</div>
|
|
617
|
+
</div>
|
|
618
|
+
</Popover>
|
|
619
|
+
</div>
|
|
620
|
+
</template>
|
|
621
|
+
|
|
622
|
+
<style module>
|
|
623
|
+
.custom-popover {
|
|
624
|
+
padding: 2rem;
|
|
625
|
+
border: 1px solid #e0e0e0;
|
|
626
|
+
border-radius: 0.5rem;
|
|
627
|
+
max-width: 400px;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.custom-trigger {
|
|
631
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
632
|
+
color: white;
|
|
633
|
+
border: none;
|
|
634
|
+
padding: 0.75rem 1.5rem;
|
|
635
|
+
border-radius: 0.5rem;
|
|
636
|
+
font-weight: 600;
|
|
637
|
+
transition: transform 0.2s;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.custom-trigger:hover {
|
|
641
|
+
transform: translateY(-2px);
|
|
642
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.custom-content {
|
|
646
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
647
|
+
color: white;
|
|
648
|
+
border-radius: 1rem;
|
|
649
|
+
overflow: hidden;
|
|
650
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.custom-header {
|
|
654
|
+
display: flex;
|
|
655
|
+
justify-content: space-between;
|
|
656
|
+
align-items: center;
|
|
657
|
+
padding: 1rem 1.5rem;
|
|
658
|
+
background: rgba(255, 255, 255, 0.1);
|
|
659
|
+
backdrop-filter: blur(10px);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.custom-header h4 {
|
|
663
|
+
margin: 0;
|
|
664
|
+
font-size: 1.125rem;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.close-btn {
|
|
668
|
+
background: none;
|
|
669
|
+
border: none;
|
|
670
|
+
color: white;
|
|
671
|
+
font-size: 1.5rem;
|
|
672
|
+
cursor: pointer;
|
|
673
|
+
padding: 0;
|
|
674
|
+
width: 24px;
|
|
675
|
+
height: 24px;
|
|
676
|
+
display: flex;
|
|
677
|
+
align-items: center;
|
|
678
|
+
justify-content: center;
|
|
679
|
+
border-radius: 50%;
|
|
680
|
+
transition: background-color 0.2s;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.close-btn:hover {
|
|
684
|
+
background: rgba(255, 255, 255, 0.2);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.custom-body {
|
|
688
|
+
padding: 1.5rem;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.custom-body p {
|
|
692
|
+
margin: 0 0 1rem 0;
|
|
693
|
+
opacity: 0.9;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.custom-body ul {
|
|
697
|
+
margin: 0;
|
|
698
|
+
padding-left: 1.25rem;
|
|
699
|
+
opacity: 0.9;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.custom-body li {
|
|
703
|
+
margin-bottom: 0.5rem;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.custom-footer {
|
|
707
|
+
padding: 1rem 1.5rem;
|
|
708
|
+
background: rgba(255, 255, 255, 0.1);
|
|
709
|
+
backdrop-filter: blur(10px);
|
|
710
|
+
display: flex;
|
|
711
|
+
justify-content: flex-end;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/* Override popover CSS variables */
|
|
715
|
+
:global(.custom-popover) {
|
|
716
|
+
--popover-bg: transparent;
|
|
717
|
+
--popover-border: none;
|
|
718
|
+
--popover-shadow: none;
|
|
719
|
+
--popover-inset-shadow: none;
|
|
720
|
+
--popover-arrow-bg: #f5576c;
|
|
721
|
+
}
|
|
722
|
+
</style>
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Form in Popover
|
|
726
|
+
|
|
727
|
+
```vue
|
|
728
|
+
<script setup lang="ts">
|
|
729
|
+
import { ref } from "vue";
|
|
730
|
+
import { Popover, Button } from "@umbra-ui/core";
|
|
731
|
+
|
|
732
|
+
const isFormOpen = ref(false);
|
|
733
|
+
const formData = ref({
|
|
734
|
+
name: "",
|
|
735
|
+
email: "",
|
|
736
|
+
message: "",
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const handleSubmit = () => {
|
|
740
|
+
console.log("Form submitted:", formData.value);
|
|
741
|
+
isFormOpen.value = false;
|
|
742
|
+
// Reset form
|
|
743
|
+
formData.value = { name: "", email: "", message: "" };
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
const handleCancel = () => {
|
|
747
|
+
isFormOpen.value = false;
|
|
748
|
+
// Reset form
|
|
749
|
+
formData.value = { name: "", email: "", message: "" };
|
|
750
|
+
};
|
|
751
|
+
</script>
|
|
752
|
+
|
|
753
|
+
<template>
|
|
754
|
+
<div class="form-popover">
|
|
755
|
+
<h3>Form in Popover</h3>
|
|
756
|
+
|
|
757
|
+
<Popover
|
|
758
|
+
v-model="isFormOpen"
|
|
759
|
+
placement="bottom-start"
|
|
760
|
+
:show-arrow="true"
|
|
761
|
+
:dismiss-on-click-outside="false"
|
|
762
|
+
max-width="400px"
|
|
763
|
+
>
|
|
764
|
+
<template #trigger>
|
|
765
|
+
<Button>Contact Us</Button>
|
|
766
|
+
</template>
|
|
767
|
+
|
|
768
|
+
<div class="form-content">
|
|
769
|
+
<h4>Send us a message</h4>
|
|
770
|
+
<form @submit.prevent="handleSubmit">
|
|
771
|
+
<div class="form-group">
|
|
772
|
+
<label for="name">Name</label>
|
|
773
|
+
<input
|
|
774
|
+
id="name"
|
|
775
|
+
v-model="formData.name"
|
|
776
|
+
type="text"
|
|
777
|
+
required
|
|
778
|
+
placeholder="Your name"
|
|
779
|
+
/>
|
|
780
|
+
</div>
|
|
781
|
+
|
|
782
|
+
<div class="form-group">
|
|
783
|
+
<label for="email">Email</label>
|
|
784
|
+
<input
|
|
785
|
+
id="email"
|
|
786
|
+
v-model="formData.email"
|
|
787
|
+
type="email"
|
|
788
|
+
required
|
|
789
|
+
placeholder="your@email.com"
|
|
790
|
+
/>
|
|
791
|
+
</div>
|
|
792
|
+
|
|
793
|
+
<div class="form-group">
|
|
794
|
+
<label for="message">Message</label>
|
|
795
|
+
<textarea
|
|
796
|
+
id="message"
|
|
797
|
+
v-model="formData.message"
|
|
798
|
+
required
|
|
799
|
+
placeholder="Your message..."
|
|
800
|
+
rows="3"
|
|
801
|
+
></textarea>
|
|
802
|
+
</div>
|
|
803
|
+
|
|
804
|
+
<div class="form-actions">
|
|
805
|
+
<Button type="button" @click="handleCancel" variant="secondary">
|
|
806
|
+
Cancel
|
|
807
|
+
</Button>
|
|
808
|
+
<Button type="submit">Send Message</Button>
|
|
809
|
+
</div>
|
|
810
|
+
</form>
|
|
811
|
+
</div>
|
|
812
|
+
</Popover>
|
|
813
|
+
</div>
|
|
814
|
+
</template>
|
|
815
|
+
|
|
816
|
+
<style module>
|
|
817
|
+
.form-popover {
|
|
818
|
+
padding: 2rem;
|
|
819
|
+
border: 1px solid #e0e0e0;
|
|
820
|
+
border-radius: 0.5rem;
|
|
821
|
+
max-width: 400px;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.form-content {
|
|
825
|
+
padding: 1.5rem;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.form-content h4 {
|
|
829
|
+
margin: 0 0 1.5rem 0;
|
|
830
|
+
color: #333;
|
|
831
|
+
text-align: center;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
.form-group {
|
|
835
|
+
margin-bottom: 1rem;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.form-group label {
|
|
839
|
+
display: block;
|
|
840
|
+
margin-bottom: 0.5rem;
|
|
841
|
+
font-weight: 500;
|
|
842
|
+
color: #333;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.form-group input,
|
|
846
|
+
.form-group textarea {
|
|
847
|
+
width: 100%;
|
|
848
|
+
padding: 0.75rem;
|
|
849
|
+
border: 1px solid #ddd;
|
|
850
|
+
border-radius: 0.25rem;
|
|
851
|
+
font-size: 1rem;
|
|
852
|
+
font-family: inherit;
|
|
853
|
+
box-sizing: border-box;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.form-group input:focus,
|
|
857
|
+
.form-group textarea:focus {
|
|
858
|
+
outline: none;
|
|
859
|
+
border-color: #007bff;
|
|
860
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.form-actions {
|
|
864
|
+
display: flex;
|
|
865
|
+
gap: 0.75rem;
|
|
866
|
+
justify-content: flex-end;
|
|
867
|
+
margin-top: 1.5rem;
|
|
868
|
+
}
|
|
869
|
+
</style>
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
## Technical Notes
|
|
873
|
+
|
|
874
|
+
- Popover provides a comprehensive floating content system with advanced positioning and animation
|
|
875
|
+
- Floating UI integration ensures smart positioning that adapts to viewport constraints and available space
|
|
876
|
+
- GSAP animations provide smooth, performant transitions with directional awareness
|
|
877
|
+
- Teleport usage ensures proper z-index layering and positioning outside component tree
|
|
878
|
+
- Auto-cleanup of positioning listeners and event handlers prevents memory leaks
|
|
879
|
+
- Hover triggers with configurable delays provide flexible interaction patterns
|
|
880
|
+
- Click-outside detection with configurable behavior for different use cases
|
|
881
|
+
- Arrow positioning automatically adjusts based on popover placement and available space
|
|
882
|
+
- TypeScript interfaces ensure type safety for all props and events
|
|
883
|
+
- CSS custom properties enable easy theming and customization
|
|
884
|
+
- Responsive design adapts to different screen sizes and orientations
|
|
885
|
+
- Accessibility features include keyboard navigation and proper focus management
|