├── .browserslistrc
├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── .prettierrc.json
├── LICENSE
├── README.md
├── babel.config.js
├── build
└── rollup.config.js
├── dev
├── serve.js
└── serve.vue
├── docs
├── .vitepress
│ ├── config.js
│ └── theme
│ │ └── index.js
├── components
│ ├── Button.vue
│ ├── CodeBlock.vue
│ ├── CodeGroup.ts
│ ├── PopperDeep.vue
│ ├── PopperDemo.vue
│ ├── PopperDynamicTheme.vue
│ ├── PopperEvents.vue
│ ├── PopperManual.vue
│ ├── PopperScopedSlots.vue
│ ├── PopperStyled.vue
│ └── code-group.css
├── guide
│ ├── api.md
│ ├── getting-started.md
│ └── what-is-vue-3-popper.md
├── index.md
└── public
│ └── popper.svg
├── index.d.ts
├── package-lock.json
├── package.json
└── src
├── component
├── Arrow.vue
└── Popper.vue
├── composables
├── index.js
├── useClickAway.js
├── useContent.js
├── useEventListener.js
└── usePopper.js
├── entry.esm.js
└── entry.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | current node
2 | last 2 versions and > 2%
3 | ie > 10
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Description of the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Reproduction link**
14 | If you can, create a reproduction on [CodeSandbox](https://codesandbox.io/)
15 |
16 | **To Reproduce**
17 | Steps to reproduce the behavior:
18 | 1. Go to '...'
19 | 2. Click on '....'
20 | 3. Scroll down to '....'
21 | 4. See error
22 |
23 | **Expected behavior**
24 | A clear and concise description of what you expected to happen.
25 |
26 | **Screenshots**
27 | If applicable, add screenshots to help explain your problem.
28 |
29 | **Additional context**
30 | Add any other context about the problem here.
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | dist
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "vueIndentScriptAndStyle": true
4 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Valgeir Björnsson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
20 |
21 |
42 |
--------------------------------------------------------------------------------
/docs/components/code-group.css:
--------------------------------------------------------------------------------
1 | /** * code-group */
2 | .code-group__nav {
3 | margin-top: 0.85rem;
4 | margin-bottom: calc(-1.7rem - 6px);
5 | padding-bottom: calc(1.7rem - 6px);
6 | padding-left: 10px;
7 | padding-top: 10px;
8 | border-top-left-radius: 6px;
9 | border-top-right-radius: 6px;
10 | background-color: black;
11 | }
12 | .code-group__ul {
13 | margin: auto 0;
14 | padding-left: 0;
15 | display: inline-flex;
16 | list-style: none;
17 | }
18 | .code-group__nav-tab {
19 | border: 0;
20 | padding: 5px;
21 | cursor: pointer;
22 | background-color: transparent;
23 | font-size: 0.85em;
24 | line-height: 1.4;
25 | color: rgba(255, 255, 255, 0.9);
26 | font-weight: 600;
27 | }
28 | .code-group__nav-tab:focus {
29 | outline: none;
30 | }
31 | .code-group__nav-tab:focus-visible {
32 | outline: 1px solid rgba(255, 255, 255, 0.9);
33 | }
34 | .code-group__nav-tab-active {
35 | border-bottom: var(--c-brand) 1px solid;
36 | }
37 | @media (max-width: 419px) {
38 | .code-group__nav {
39 | margin-left: -1.5rem;
40 | margin-right: -1.5rem;
41 | border-radius: 0;
42 | }
43 | }
44 | /** * code-group-item */
45 | .code-group-item {
46 | display: none;
47 | }
48 | .code-group-item__active {
49 | display: block;
50 | }
51 | .code-group-item > pre {
52 | background-color: orange;
53 | }
54 |
--------------------------------------------------------------------------------
/docs/guide/api.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | ## Props
4 |
5 | | Name | Default | Description |
6 | | ------------------ | -------- | ----------------------------------------------------------------------------------------------------------- |
7 | | `placement` | `bottom` | Preferred placement of the Popper |
8 | | `disableClickAway` | `false` | Disables automatically closing the Popper when the user clicks away from it |
9 | | `offsetSkid` | `0` | Offset in pixels along the trigger element |
10 | | `offsetDistance` | `12` | Offset in pixels away from the trigger element |
11 | | `hover` | `false` | Trigger the Popper on hover |
12 | | `arrow` | `false` | Display an arrow on the Popper |
13 | | `arrowPadding` | `0` | Stop arrow from reaching the edge of the Popper (in pixels) |
14 | | `disabled` | `false` | Disables the Popper. If it was already open, it will be closed. |
15 | | `openDelay` | `0` | Open the Popper after a delay (ms) |
16 | | `closeDelay` | `0` | Close the Popper after a delay (ms) |
17 | | `interactive` | `true` | If the Popper should be interactive, it will close when clicked/hovered if false |
18 | | `content` | `null` | If your content is just a simple string, you can pass it as a prop |
19 | | `show` | `null` | Control the Popper **manually**, other events (click, hover) are ignored if this is set to `true/false` |
20 | | `zIndex` | `9999` | The z-index of the Popper |
21 | | `locked` | `false` | Lock the Popper into place, it will not flip dynamically when it runs out of space if this is set to `true` |
22 |
23 | ## Events
24 |
25 | | Name | Description |
26 | | -------------- | ------------------------- |
27 | | `open:popper` | When the Popper is opened |
28 | | `close:popper` | When the Popper is hidden |
29 |
30 | ## Slots
31 |
32 | | Name | Description |
33 | | --------- | ---------------------- |
34 | | `content` | For the Popper content |
35 |
36 | ## Slot props
37 |
38 | The `content` slot gives you access to useful variables and functions.
39 |
40 | | Name | Type | Description |
41 | | -------- | -------- | ------------------------------ |
42 | | `close` | function | A function to close the Popper |
43 | | `isOpen` | boolean | The `open` state of the Popper |
44 |
45 | ## CSS variables
46 |
47 | `Popper` only comes with some barebones styling by default, but it also uses a list of predefined CSS variables. You can overwrite these variables to suit your needs.
48 |
49 | | CSS variable | Example value |
50 | | --------------------------------------- | ----------------------------------- |
51 | | `--popper-theme-background-color` | #ffffff |
52 | | `--popper-theme-background-color-hover` | #ffffff |
53 | | `--popper-theme-text-color` | inherit |
54 | | `--popper-theme-border-width` | 1px |
55 | | `--popper-theme-border-style` | solid |
56 | | `--popper-theme-border-color` | #eeeeee |
57 | | `--popper-theme-border-radius` | 6px |
58 | | `--popper-theme-padding` | 16px |
59 | | `--popper-theme-box-shadow` | 0 6px 30px -6px rgba(0, 0, 0, 0.25) |
60 |
--------------------------------------------------------------------------------
/docs/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | ::: tip
4 | Like the name suggests, `vue3-popper` is written for Vue 3. There are no plans to support both Vue 2.x and Vue 3.x at the moment.
5 | :::
6 |
7 | You can install `Vue 3 Popper` by opening your terminal in your project and running the following command:
8 |
9 | With yarn:
10 |
11 | ```bash
12 | $ yarn add vue3-popper
13 | ```
14 |
15 | With NPM:
16 |
17 | ```bash
18 | $ npm i vue3-popper
19 | ```
20 |
21 | ### Global
22 |
23 | You can import and register the component globally:
24 |
25 | ```javascript
26 | import { createApp } from "vue";
27 | import Popper from "vue3-popper";
28 |
29 | const app = Vue.createApp({});
30 | app.component("Popper", Popper);
31 | ```
32 |
33 | ### Component
34 |
35 | Or use it on a case by case basis:
36 |
37 | ```html
38 |
39 |
40 |
41 |
42 |
43 |
44 |
54 | ```
55 |
56 |
61 |
62 | ## Usage
63 |
64 | You can add Popper to any of your elements or components. Just wrap them with `Popper` and use the `content` prop or slot for your popover.
65 |
66 | ### Using the content `prop`
67 |
68 | If your content is only a simple string, you can use the `content` prop:
69 |
70 | ```vue
71 |
72 |
73 |
74 |
75 |
76 | ```
77 |
78 | ### Using the content `slot`
79 |
80 | If your content is more complex, you can use the `#content` slot:
81 |
82 | ```vue
83 |
84 |
85 |
86 |
87 |
This is the Popper content
88 |
89 |
90 |
91 | ```
92 |
93 | ## What about styles?
94 |
95 | `Popper` only comes with some barebones styling by default, but it also uses a list of predefined CSS variables. You can overwrite these variables to suit your needs.
96 |
97 | ### CSS variables
98 |
99 | | CSS variable | Example value |
100 | | --------------------------------------- | ----------------------------------- |
101 | | `--popper-theme-background-color` | #ffffff |
102 | | `--popper-theme-background-color-hover` | #ffffff |
103 | | `--popper-theme-text-color` | inherit |
104 | | `--popper-theme-border-width` | 1px |
105 | | `--popper-theme-border-style` | solid |
106 | | `--popper-theme-border-color` | #eeeeee |
107 | | `--popper-theme-border-radius` | 6px |
108 | | `--popper-theme-padding` | 16px |
109 | | `--popper-theme-box-shadow` | 0 6px 30px -6px rgba(0, 0, 0, 0.25) |
110 |
111 | You can overwrite them any way you like, for example in a Vue component:
112 |
113 | ```vue
114 |
115 |
116 |
117 |
118 |
119 |
120 |
132 | ```
133 |
134 | You could also create a `theme.css` file:
135 |
136 | ```css
137 | :root {
138 | --popper-theme-background-color: #333333;
139 | --popper-theme-background-color-hover: #333333;
140 | --popper-theme-text-color: #ffffff;
141 | --popper-theme-border-width: 0px;
142 | --popper-theme-border-style: solid;
143 | --popper-theme-border-radius: 6px;
144 | --popper-theme-padding: 32px;
145 | --popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25);
146 | }
147 | ```
148 |
149 | Import it:
150 |
151 | ```javascript
152 | import { createApp } from "vue";
153 | import App from "./App.vue";
154 | import "./theme.css"; // Magic happens here
155 |
156 | createApp(App).mount("#app");
157 | ```
158 |
159 | And your Popper is styled!
160 |
161 |
162 |
163 | ### Dynamic theming
164 |
165 | Using the CSS variables you could even add multiple themes to your popover.
166 |
167 | ```css
168 | .dark {
169 | --popper-theme-background-color: #333333;
170 | --popper-theme-background-color-hover: #333333;
171 | --popper-theme-text-color: white;
172 | --popper-theme-border-width: 0px;
173 | --popper-theme-border-radius: 6px;
174 | --popper-theme-padding: 32px;
175 | --popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25);
176 | }
177 |
178 | .light {
179 | --popper-theme-background-color: #ffffff;
180 | --popper-theme-background-color-hover: #ffffff;
181 | --popper-theme-text-color: #333333;
182 | --popper-theme-border-width: 1px;
183 | --popper-theme-border-style: solid;
184 | --popper-theme-border-color: #eeeeee;
185 | --popper-theme-border-radius: 6px;
186 | --popper-theme-padding: 32px;
187 | --popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25);
188 | }
189 | ```
190 |
191 | ```vue
192 |
193 |
199 |
200 |
201 |
202 | ```
203 |
204 |
205 |
206 | ### I don't want to use CSS variables
207 |
208 | That's fine, you can always just apply your own styles, just make sure it's `scoped` and you use the `:deep` selector:
209 |
210 | ```vue
211 |
212 |
213 |
214 |
215 |
216 |
217 |
236 | ```
237 |
238 |
239 |
240 | ## How can I wrap `Popper` with my own component?
241 |
242 | It is generally a good idea to wrap 3rd party components like `vue3-popper` with your own local component. It gives you things like:
243 |
244 | - Modularity
245 | - Scalability
246 | - Ability to add custom styles or extensions
247 | - **If you need to change something (even swap out vue3-popper for something else) you only need to do that once in your wrapper component.**
248 |
249 | Here's an example of how you can wrap `vue3-popper` with your own component:
250 |
251 | ::: tip
252 | Notice that in this example, `hover`, `openDelay` and `closeDelay` are all hardcoded. This is just to show how you can create an **opinionated** wrapper.
253 | :::
254 |
255 | ```vue
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
277 | ```
278 |
279 | You could then go on to define your styles etc. and use your component just like you would `Popper`:
280 |
281 | ```vue
282 |
283 |
284 |
285 |
286 |
This is the Popper content 🍿
287 |
288 |
289 |
290 | ```
291 |
292 | ## Reacting to `Popper` events
293 |
294 | Sometimes you need to add some side-effects when closing/opening Poppers. You can use the built-in events for that:
295 |
296 | ```vue
297 |
298 |
304 |
305 |
306 |
307 |
308 |
322 | ```
323 |
324 |
325 |
326 | ## Using scoped slot properties
327 |
328 | You can gain access to the `close` function for those edge cases. In this example we use the `close` function to dismiss the Popper when a button is clicked inside of it.
329 |
330 | ```vue
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 | ```
340 |
341 |
342 |
343 | ## Manually controlling the Popper
344 |
345 | You can use the `show` prop to manually control the Popper. Other events (click, hover) are ignored when in manual mode.
346 |
347 | ```vue
348 |
349 |