Skip to content
This repository was archived by the owner on Dec 15, 2023. It is now read-only.

Commit dd9e44d

Browse files
feat: components tooltip and popover. absolute positioning (dt 40) (#194)
* DT 40 Absolute positioning for tooltips (#131) * DT 40 Absolute positioning for popovers & tooltips * updates * updates * update tooltip * update tooltip * clean up * refactoring, clean up * resolve comments * resolve comments refactor first iteration stories * update comments * DT 40 Tooltip documentation (#177) * add documentation for Tippy tooltip * update reactive "show" * resolve comments, update eslint config because of an error * update esplint json * DT 40 Tooltip tests (#178) * add documentation for Tippy tooltip * update reactive "show" * update tests * update tests * resolve comments * resolve comments * feat: DT 40 Absolute positioning for popover (#135) * DT 40 Absolute positioning for popovers & tooltips * updates * updates * update tooltip * update tooltip * clean up * refactoring, clean up * resolve comments * popover implementation, decomposition tippy, clean up * add animation, clean up * clean up popover * clean tooltip folder * add import * clean up, updates * DT-40 popover component, refactoring after tooltip implementation * resolve comments * clean up * resolve comments * fix eslint * leftover after merge * leftover after merge * Added test for tooltip tippy; Update components DtLazyShow, popover, tooltip; * chore: update package-lock.json * refactor: after merge * story doc * update story doc * add flip for popover * add implementation "modal" * remove v-click-outside * update documentation * update stories * prevent closing popup when a user blur and focus repeatedly during transition * clean up * update storybook folder for tooltip. * added comment for after-leave event * docs: update * resolve comments * fix typo * update overlay, tests * resolve comments * add comment * popover uv alignments * clean up, update data * clean up, remove prev version tooltip. * update docs * update z-index for tooltip * update border-box for content * add width content prop (anchor), update focus logic, * clean up, rename contentWidth * set empty string to content width by default * package lock * restore tooltip test * clean up tooltip test add new constant to popover update default story * add flushPromises to utils * add $nextTick before setPopoverContentAnchorWidth * update tooltip story Co-authored-by: Brad Paugh <[email protected]>
1 parent 686b2b9 commit dd9e44d

27 files changed

+1824
-32692
lines changed

.eslintrc.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module.exports = {
4949
disallowVueBuiltInComponents: true,
5050
disallowVue3BuiltInComponents: true,
5151
}],
52+
'vue/no-v-model-argument': ['warn'],
5253
'vue/padding-line-between-blocks': ['warn'],
5354
'vue/require-direct-export': ['warn'],
5455
'vue/require-name-property': ['error'],
@@ -61,8 +62,9 @@ module.exports = {
6162
'vue/v-on-event-hyphenation': ['error'],
6263
'vue/no-template-target-blank': ['error'],
6364
'vue/no-static-inline-styles': ['error'],
65+
'vuejs-accessibility/iframe-has-title': 'warn',
6466

65-
'max-lines': ['error', { max: 300, skipBlankLines: true, skipComments: true }],
67+
'max-lines': ['warn', { max: 300, skipBlankLines: true, skipComments: true }],
6668
quotes: ['error', 'single', { allowTemplateLiterals: true }],
6769
complexity: ['warn', 5],
6870

.esplint.rec.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"recordVersion": 1,
3-
"configHash": "bc9f0e28a9c7a5e937370e9f2f5ea2a8a86295b3",
3+
"configHash": "8dbf85332497122d8a139286ca9dcf3ccd3d9d58",
44
"files": {
55
"components/banner/banner.vue": {
66
"vue/no-deprecated-dollar-listeners-api": 3
@@ -26,14 +26,19 @@
2626
"components/notice/notice_action.vue": {
2727
"vue/no-deprecated-destroyed-lifecycle": 1
2828
},
29-
"components/popover/popover_default.story.vue": {
30-
"vue/no-deprecated-v-bind-sync": 1
29+
"components/popover/popover.vue": {
30+
"vue/no-deprecated-destroyed-lifecycle": 1,
31+
"max-lines": 1,
32+
"complexity": 1
3133
},
3234
"components/radio/radio.vue": {
3335
"vue/no-deprecated-dollar-listeners-api": 1
3436
},
3537
"components/toast/toast.vue": {
3638
"vue/no-deprecated-dollar-listeners-api": 3
39+
},
40+
"components/tooltip/tooltip.vue": {
41+
"vue/no-deprecated-destroyed-lifecycle": 1
3742
}
3843
}
3944
}

.esplintrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ module.exports = {
88
'vue/no-deprecated-destroyed-lifecycle',
99
'vue/no-deprecated-v-bind-sync',
1010
'complexity',
11+
'vuejs-accessibility/iframe-has-title',
12+
'max-lines'
1113
],
1214
};

components/breadcrumbs/breadcrumbs_default.story.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
:inverted="inverted"
1313
>
1414
<html-fragment
15+
v-if="defaultSlot"
1516
:html="defaultSlot"
16-
v-if="defaultSlot"></html-fragment>
17+
/>
1718
</dt-breadcrumbs>
1819
</div>
1920
</template>

components/lazy_show/lazy_show.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<template>
2+
<!-- applies the transition on initial render -->
23
<transition
34
:name="transition"
5+
:appear="appear"
46
v-on="$listeners"
57
>
68
<div
@@ -32,6 +34,11 @@ export default {
3234
type: String,
3335
default: null,
3436
},
37+
38+
appear: {
39+
type: Boolean,
40+
default: false,
41+
},
3542
},
3643
3744
/******************

components/modal/modal.vue

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<dt-lazy-show
3-
transition="d-modal"
3+
transition="d-zoom"
44
:show="show"
55
:class="[
66
'd-modal',
@@ -255,27 +255,3 @@ export default {
255255
},
256256
};
257257
</script>
258-
259-
<style lang="less">
260-
@import "../../css/dialtone.less";
261-
262-
.d-modal-enter, .d-modal-leave-to {
263-
.d-modal--animate();
264-
}
265-
266-
.d-modal__dialog-enter, .d-modal__dialog-leave-to {
267-
.d-modal__dialog--animate();
268-
}
269-
270-
.d-modal-enter-active, .d-modal__dialog-enter-active {
271-
.d-modal--animate-in();
272-
}
273-
274-
.d-modal-leave-active {
275-
.d-modal--animate-out();
276-
}
277-
278-
.d-modal__dialog-leave-active {
279-
.d-modal__dialog--animate-out();
280-
}
281-
</style>

components/modal/modal_default.story.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default {
7676
7777
data () {
7878
return {
79-
isOpen: false,
79+
isOpen: this.show,
8080
};
8181
},
8282
@@ -89,6 +89,14 @@ export default {
8989
},
9090
},
9191
92+
watch: {
93+
show: {
94+
handler () {
95+
this.isOpen = this.show;
96+
},
97+
},
98+
},
99+
92100
methods: {
93101
close (event) {
94102
this.isOpen = !this.isOpen;

components/popover/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export {
44
POPOVER_HORIZONTAL_ALIGNMENT,
55
POPOVER_VERTICAL_ALIGNMENT,
66
POPOVER_ROLES,
7+
POPOVER_CONTENT_WIDTHS,
78
} from './popover_constants';

components/popover/popover.mdx

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { Canvas, Story, Subtitle, ArgsTable, PRIMARY_STORY } from '@storybook/ad
88

99
## Basic Usage
1010

11-
Popovers may be used standalone, or to create a dropdown menu or other complex control. Popovers are not modal elements,
12-
for a modal dialog that takes over the whole screen, use a DtModal component.
11+
Popovers may be used standalone, or to create a dropdown menu or other complex control.
12+
If you want use popover as a component which takes over the whole screen, there's a prop modal for that, or you can use
13+
DtModal. Keep in mind accessibility for popover and modal components are different.
1314

1415
A popover has 2 major pieces that are provided as required named slots: the **anchor** and the **content**.
1516

@@ -18,9 +19,9 @@ content. Normally a button, the anchor can be any *interactive* element that cou
1819
content. For example, the anchor could be an input element with a conditionally displayed listbox content element to
1920
implement an auto-suggest form component.
2021

21-
The **content** slot will be rendered lazily when the popover is open. The popover content will automatically be closed
22-
when clicking outside the content (using the click-outside directive) so it is important to use `.sync` on the `show`
23-
prop (or `v-model:open` in Vue 3) so it can be updated if the popover closes itself.
22+
The **content** slot will be rendered lazily when the popover is open. By default, the popover content will
23+
automatically be closed when clicking outside the content or on escape key press, so it is important to use `.sync` on
24+
the `open` prop (or `v-model:open` in Vue 3) so it can be updated if the popover closes itself.
2425

2526
### Import
2627

@@ -33,6 +34,25 @@ import { DtPopover } from '@dialpad/dialtone-vue';
3334
```jsx
3435
<dt-popover
3536
:open.sync="open"
37+
>
38+
<template #anchor="{ attrs }">
39+
<dt-button
40+
v-bind="attrs"
41+
>
42+
Click to open
43+
</dt-button>
44+
</template>
45+
<template #content>
46+
<p>I will be displayed in the popover!</p>
47+
</template>
48+
</dt-popover>
49+
```
50+
51+
or
52+
53+
```jsx
54+
<dt-popover
55+
:open="open"
3656
>
3757
<template #anchor="{ attrs }">
3858
<dt-button
@@ -54,8 +74,16 @@ import { DtPopover } from '@dialpad/dialtone-vue';
5474

5575
## Accessibility
5676

57-
There are a few important considerations to ensure popover controls are accessible. By default, the popover content will
58-
have a generic role of "dialog".
77+
Popover, in their current implementation, are accessible when used as interactive components.
78+
Content will be read to screen reader users, and the popover markup by default get appended to the `parent`
79+
(also it could be placed to the end of `<body>` or other DOM element)
80+
81+
There are a few important considerations to ensure popover controls are accessible.
82+
The popover, by default:
83+
84+
- the popover content will have a generic role of "dialog".
85+
- focus will be transferred into the popover to the first content focusable element, and after close, triggering
86+
element will be focused (like in the modal component)
5987

6088
### Anchor
6189

@@ -78,11 +106,9 @@ By default, the dialog content will be labeled by the entire anchor element. To
78106
1. Pass `aria-label`, which is the text label that will be applied to the dialog content.
79107
2. Pass `aria-labelledby`, which is an ID of the element that should be used as the descriptive label.
80108
81-
### Focus & Keyboard
109+
### Keyboard
82110
83-
Due to the different contexts in which a popover can be used, focus management and keyboard shortcuts like `ESC` are not
84-
provided for you. You are encouraged to consult the ARIA documentation for the particular role you are implementing to
85-
see how keyboard focus & shortcuts should be implemented.
111+
The popover closes on `ESC` key press.
86112
87113
## Variants
88114
@@ -91,11 +117,14 @@ see how keyboard focus & shortcuts should be implemented.
91117
The popover content supports both fixed and dynamic horizontal and vertical alignment around the anchor element. If
92118
`fixedAlignment`/`fixedVerticalAlignment` are passed, the popover will always be positioned in that direction. If you
93119
omit either of them, the popover will dynamically adjust the corresponding position, trying not to clip the content
94-
relative to the `$root` element (**not** the viewport!). This calculation happens each time the popover is opened
95-
(not when the screen is resized).
120+
relative to the `$root` element. This calculation happens each time the popover is opened or window is resized.
121+
122+
### Flip
96123
97-
For example: with no `fixedAlignment`, a popover anchor positioned such that the content, when open, would overflow the
98-
`$root` element's right bounds will open to the left.
124+
The popover uses [headless-tippy](https://atomiks.github.io/tippyjs/v6/headless-tippy/) and
125+
[popper](https://popper.js.org/docs/v2/modifiers/flip/), which has flip modifier (which can change the placement of a
126+
popper when it's scheduled to overflow a given boundary). By default, boundary is `clippingParents`
127+
(corresponding popover prop is `flipBoundary`).
99128

100129
<Canvas>
101130
<Story id="components-popovers--fixed-right" />

components/popover/popover.stories.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import {
44
POPOVER_HORIZONTAL_ALIGNMENT,
55
POPOVER_VERTICAL_ALIGNMENT,
66
POPOVER_ROLES,
7+
POPOVER_CONTENT_WIDTHS,
78
} from './';
89
import PopoverDefault from './popover_default.story.vue';
910
import { createTemplateFromVueFile } from '../storybook_utils';
1011
import PopoverMdx from './popover.mdx';
1112
import { action } from '@storybook/addon-actions';
13+
import { TOOLTIP_HIDE_ON_CLICK_VARIANTS } from '../tooltip';
1214

1315
const argTypesData = {
1416
// Slots
@@ -39,7 +41,7 @@ const argTypesData = {
3941
padding: {
4042
control: {
4143
type: 'select',
42-
options: POPOVER_PADDING_CLASSES,
44+
options: Object.keys(POPOVER_PADDING_CLASSES),
4345
},
4446
},
4547
role: {
@@ -60,6 +62,12 @@ const argTypesData = {
6062
options: POPOVER_VERTICAL_ALIGNMENT,
6163
},
6264
},
65+
contentWidth: {
66+
control: {
67+
type: 'select',
68+
options: POPOVER_CONTENT_WIDTHS,
69+
},
70+
},
6371

6472
// Events
6573
onClose: {
@@ -70,13 +78,18 @@ const argTypesData = {
7078

7179
'update:open': {
7280
description: `The popover will emit a "false" boolean value for this event when the \
73-
user performs a popover-closing action.`,
81+
user performs a popover-closing action. Parent components can sync on this value to create \
82+
a 2-way binding to control popover visibility.`,
7483
table: {
7584
type: {
7685
summary: 'boolean',
7786
},
7887
},
7988
},
89+
hideOnClick: {
90+
type: 'select',
91+
options: TOOLTIP_HIDE_ON_CLICK_VARIANTS,
92+
},
8093
};
8194

8295
// Default Props for all variations
@@ -161,3 +174,18 @@ NoPadding.parameters = {
161174
},
162175
},
163176
};
177+
178+
export const overlayModal = Template.bind({});
179+
overlayModal.args = { ...Default.args, open: true, modal: true };
180+
overlayModal.parameters = {
181+
docs: {
182+
source: {
183+
code: `
184+
<dt-popover padding="none">
185+
<template #anchor="{ attrs }"></template>
186+
<template #content></template>
187+
</dt-popover>
188+
`,
189+
},
190+
},
191+
};

0 commit comments

Comments
 (0)