@justeattakeaway/pie-tooltip 0.1.0 → 0.2.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/README.md CHANGED
@@ -7,16 +7,20 @@
7
7
  </a>
8
8
  </p>
9
9
 
10
- `@justeattakeaway/pie-tooltip` is a Web Component built using the Lit library. It offers a simple and accessible `tooltip` component for web applications.
10
+ `@justeattakeaway/pie-tooltip` is a Web Component built using the Lit library. It provides an accessible panel that is anchored to a trigger elsewhere on the page.
11
11
 
12
12
  ## Table of Contents
13
13
 
14
14
  - [Installation](#installation)
15
15
  - [Documentation](#documentation)
16
+ - [Controlled component](#controlled-component)
16
17
  - [Properties](#properties)
17
18
  - [Slots](#slots)
18
- - [CSS Variables](#css-variables)
19
19
  - [Events](#events)
20
+ - [CSS Variables](#css-variables)
21
+ - [Positioning](#positioning)
22
+ - [Sizing](#sizing)
23
+ - [Accessibility](#accessibility)
20
24
  - [Usage Examples](#usage-examples)
21
25
  - [Questions and Support](#questions-and-support)
22
26
  - [Contributing](#contributing)
@@ -29,25 +33,114 @@ Ideally, you should install the component using the **`@justeattakeaway/pie-webc
29
33
 
30
34
  ## Documentation
31
35
 
36
+ ### Controlled component
37
+
38
+ `pie-tooltip` is a controlled component. It never writes to its own `isOpen`.
39
+
40
+ 1. You own `isOpen`.
41
+ 2. You listen for `pie-tooltip-close`.
42
+ 3. You pass the value back.
43
+
32
44
  ### Properties
33
- | Prop | Options | Description | Default |
34
- |------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|
35
- | | | | |
45
+
46
+ | Prop | Options | Description | Default |
47
+ |---|---|---|---|
48
+ | `trigger` | Any string | The `id` of the element the panel is anchored to. The trigger lives elsewhere in the DOM and is never slotted into the tooltip. | `undefined` |
49
+ | `isOpen` | `true`, `false` | When true, the panel is visible. The component never writes to this property. | `false` |
50
+ | `position` | `top`, `top-start`, `top-end`, `bottom`, `bottom-start`, `bottom-end`, `left`, `left-start`, `left-end`, `right`, `right-start`, `right-end` | The side of the trigger the panel sits on, and its alignment along the cross axis. | `top` |
51
+ | `size` | `default`, `fit-to-content`, `fill-container` | How the panel sizes itself. `default` is a fixed 280px and wraps, `fit-to-content` is as wide as its content, and `fill-container` matches the inline size of the trigger's parent element. Not applied when `type` is `icon`. | `default` |
52
+ | `variant` | `default`, `inverse` | The colour treatment of the panel. `default` is the dark panel, `inverse` the light one. | `default` |
53
+ | `type` | `default`, `icon` | The presentation of the panel. `icon` is the compact treatment intended for icon triggers: it has no arrow and is always as wide as its content, so `size` and `--tooltip-width` have no effect on it. | `default` |
54
+ | `isDismissible` | `true`, `false` | When true, a close button is rendered inside the panel. | `false` |
55
+ | `heading` | Any string | The text to display in the panel's heading. In dialog mode this also provides the panel's accessible name. | `undefined` |
56
+ | `headingLevel` | `h2`, `h3`, `h4`, `h5`, `h6` | The HTML heading tag to use for the panel's heading. | `h2` |
57
+ | `aria` | `{ close?: string, label?: string }` | `close` names the close button. `label` names the panel in dialog mode when no `heading` is provided. | `undefined` |
36
58
 
37
59
  ### Slots
38
- | Slot | Description |
39
- |----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
40
- | | |
41
60
 
42
- ### CSS Variables
43
- | Variable | Description | Default |
44
- |----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
45
- | | | |
61
+ | Slot | Description |
62
+ |---|---|
63
+ | `content` | The descriptive content of the panel. Must not contain focusable elements. |
64
+ | `action` | Designed for using `pie-button`. Filling this slot switches the panel from a tooltip to a non-modal dialog. When using `pie-button` always set the size to `xsmall`.|
46
65
 
47
66
  ### Events
48
- | Event | Type | Description |
49
- |------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
50
- | | | |
67
+
68
+ | Event | Type | Description |
69
+ |---|---|---|
70
+ | `pie-tooltip-close` | `Event` | Emitted when the close button is clicked. Set `isOpen` to `false` in response. Bubbles and is composed. |
71
+
72
+ ### CSS Variables
73
+
74
+ | Variable | Description | Default |
75
+ |---|---|---|
76
+ | `--tooltip-offset` | The gap between the trigger and the arrow's tip, or between the trigger and the panel edge when `type` is `icon`. | `var(--dt-spacing-a)` |
77
+ | `--tooltip-width` | Sets the panel's inline size directly, overriding whatever `size` would have produced. Accepts any length. Ignored when `type` is `icon`. | Unset |
78
+
79
+ Set both on the `pie-tooltip` element itself.
80
+
81
+ ```html
82
+ <pie-tooltip style="--tooltip-offset: 16px;" trigger="delivery-info"></pie-tooltip>
83
+ ```
84
+
85
+ ## Positioning
86
+
87
+ The component projects itself over the trigger's box and places the panel against that box in CSS. The trigger is found by `id`, so `pie-tooltip` can sit anywhere in the DOM, but reading and tab order follow DOM order, so place it immediately after its trigger.
88
+
89
+ `position` names a side and, optionally, an alignment along the opposite axis:
90
+
91
+ ```
92
+ top top-start top-end
93
+ bottom bottom-start bottom-end
94
+ left left-start left-end
95
+ right right-start right-end
96
+ ```
97
+
98
+ In right-to-left languages, everything on the inline axis mirrors. The alignments follow the reading direction, so `top-start` aligns against the right-hand edge, and `left` and `right` swap: a panel asked for on the left appears on the right. The `-start` and `-end` alignments of `left` and `right` are on the block axis, which has no direction to mirror, so only the side moves. None of this needs configuration or any JavaScript awareness of direction.
99
+
100
+ ## Sizing
101
+
102
+ | `size` | Behaviour |
103
+ |---|---|
104
+ | `default` | The panel is always 280px wide. Longer content wraps. |
105
+ | `fit-to-content` | The panel is as wide as its content, up to the width of the viewport. |
106
+ | `fill-container` | The panel's inline size matches the inline size of the trigger's parent element, whatever the content. |
107
+
108
+ `--tooltip-width` overrides all three.
109
+
110
+ ## Accessibility
111
+
112
+ ### The two modes
113
+
114
+ The panel presents as one of two patterns, inferred from the `action` slot contents. They carry different obligations.
115
+
116
+ | | `action` slot empty | `action` slot filled |
117
+ |---|---|---|
118
+ | Panel role | `tooltip` | `dialog` |
119
+ | Contains focusable content | No | Yes |
120
+ | Accessible name on panel | None | Required, from `heading` or `aria.label` |
121
+ | In the accessibility tree while closed | Yes, as the trigger's description | No |
122
+
123
+ A close button does not make the panel a dialog. Only the `action` slot does.
124
+
125
+ ### What the component does
126
+
127
+ - Sets `role="tooltip"` or `role="dialog"` from the `action` slot, resolved on the client before the first paint.
128
+ - Names the dialog panel from `heading`, falling back to `aria.label`.
129
+ - Removes the dialog panel from the accessibility tree while closed. In tooltip mode the content stays in the DOM so that a description referring to it still resolves.
130
+ - Names the close button from `aria.close` and places it in the tab sequence inside the panel.
131
+ - Keeps the panel clear of the trigger at every placement, so the panel cannot obscure a focused trigger (WCAG 2.4.11).
132
+ - Wraps content.
133
+
134
+ ### What you need to do
135
+
136
+ - **Give the trigger its own accessible name.** The tooltip is a description and never supplies a name. An icon-only trigger must set its own label; `pie-icon-button` already requires `aria.label`.
137
+ - **Use a natively interactive element as the trigger**, a button or a link, so focus and click behave correctly.
138
+ - **Own `isOpen`.** Listen for `pie-tooltip-close` and set `isOpen` to `false` in response.
139
+ - **Keep focusable content out of the `content` slot.** Interactive content belongs in the `action` slot, which switches the panel to a dialog.
140
+ - **Place `<pie-tooltip>` immediately after its trigger in the DOM.** The component anchors by `id` and can sit anywhere, but reading and tab order follow DOM order.
141
+ - **In dialog mode, provide `heading` or `aria.label`** so the dialog has an accessible name.
142
+ - **Provide a translated `aria.close`** whenever `isDismissible` is set.
143
+ - **Keep tooltip-mode content short and supplementary.** Anything essential or interactive belongs in dialog mode, or inline in the page.
51
144
 
52
145
  ## Usage Examples
53
146
 
@@ -64,19 +157,72 @@ import '@justeattakeaway/pie-webc/components/tooltip.js'
64
157
  <script type="module" src="/main.js"></script>
65
158
  ```
66
159
 
160
+ ```html
161
+ <pie-button id="delivery-info">Delivery times</pie-button>
162
+
163
+ <pie-tooltip trigger="delivery-info" isOpen isDismissible>
164
+ <span slot="content">Orders placed before 6pm arrive today.</span>
165
+ </pie-tooltip>
166
+ ```
167
+
67
168
  **For Native JS Applications, Vue, Angular, Svelte etc.:**
68
169
 
69
170
  ```js
70
171
  // Vue templates (using Nuxt 3)
71
172
  import '@justeattakeaway/pie-webc/components/tooltip.js'
173
+ ```
72
174
 
175
+ ```html
176
+ <template>
177
+ <pie-button id="delivery-info">Delivery times</pie-button>
178
+
179
+ <pie-tooltip
180
+ trigger="delivery-info"
181
+ :isOpen="isOpen"
182
+ isDismissible
183
+ :aria="{ close: 'Close' }"
184
+ @pie-tooltip-close="isOpen = false">
185
+ <span slot="content">Orders placed before 6pm arrive today.</span>
186
+ </pie-tooltip>
187
+ </template>
73
188
  ```
74
189
 
75
190
  **For React Applications:**
76
191
 
77
192
  ```jsx
193
+ import { useState } from 'react';
194
+ import { PieButton } from '@justeattakeaway/pie-webc/react/button.js';
78
195
  import { PieTooltip } from '@justeattakeaway/pie-webc/react/tooltip.js';
79
196
 
197
+ export function DeliveryTimes () {
198
+ const [isOpen, setIsOpen] = useState(true);
199
+
200
+ return (
201
+ <>
202
+ <PieButton id="delivery-info">Delivery times</PieButton>
203
+
204
+ <PieTooltip
205
+ trigger="delivery-info"
206
+ isOpen={isOpen}
207
+ isDismissible
208
+ aria={{ close: 'Close' }}
209
+ onPieTooltipClose={() => setIsOpen(false)}>
210
+ <span slot="content">Orders placed before 6pm arrive today.</span>
211
+ </PieTooltip>
212
+ </>
213
+ );
214
+ }
215
+ ```
216
+
217
+ **A dialog panel:**
218
+
219
+ Filling the `action` slot switches the panel to a non-modal dialog, which then needs an accessible name.
220
+
221
+ ```html
222
+ <pie-tooltip trigger="delivery-info" isOpen heading="Delivery times">
223
+ <span slot="content">Orders placed before 6pm arrive today.</span>
224
+ <pie-button slot="action" size="xsmall">Next</pie-button>
225
+ </pie-tooltip>
80
226
  ```
81
227
 
82
228
  ## Questions and Support