@vaadin/context-menu 25.1.2 → 25.2.0-alpha10
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/custom-elements.json +79 -4
- package/package.json +13 -13
- package/src/vaadin-context-menu-item.js +5 -0
- package/src/vaadin-context-menu-mixin.js +10 -6
- package/src/vaadin-context-menu-tooltip-controller.js +76 -0
- package/src/vaadin-context-menu.d.ts +28 -0
- package/src/vaadin-context-menu.js +31 -9
- package/src/vaadin-contextmenu-event.js +1 -1
- package/src/vaadin-contextmenu-items-mixin.d.ts +25 -0
- package/src/vaadin-contextmenu-items-mixin.js +61 -4
- package/src/vaadin-menu-overlay-mixin.js +1 -1
- package/web-types.json +20 -28
- package/web-types.lit.json +17 -3
package/custom-elements.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"type": {
|
|
49
49
|
"text": "!Array<!ContextMenuItem> | undefined"
|
|
50
50
|
},
|
|
51
|
-
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```",
|
|
51
|
+
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```",
|
|
52
52
|
"attribute": "items",
|
|
53
53
|
"inheritedFrom": {
|
|
54
54
|
"name": "ItemsMixin",
|
|
@@ -230,13 +230,88 @@
|
|
|
230
230
|
}
|
|
231
231
|
]
|
|
232
232
|
},
|
|
233
|
+
{
|
|
234
|
+
"kind": "javascript-module",
|
|
235
|
+
"path": "src/vaadin-context-menu-tooltip-controller.js",
|
|
236
|
+
"declarations": [
|
|
237
|
+
{
|
|
238
|
+
"kind": "class",
|
|
239
|
+
"description": "Controller for the tooltip slotted into `<vaadin-context-menu>`. Configures\nthe tooltip in manual mode and drives its target, context, and position\nbased on the currently hovered or focused item.",
|
|
240
|
+
"name": "ContextMenuTooltipController",
|
|
241
|
+
"members": [
|
|
242
|
+
{
|
|
243
|
+
"kind": "method",
|
|
244
|
+
"name": "close",
|
|
245
|
+
"parameters": [
|
|
246
|
+
{
|
|
247
|
+
"name": "immediate",
|
|
248
|
+
"type": {
|
|
249
|
+
"text": "boolean"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"kind": "method",
|
|
256
|
+
"name": "initCustomNode",
|
|
257
|
+
"parameters": [
|
|
258
|
+
{
|
|
259
|
+
"name": "tooltipNode"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"kind": "method",
|
|
265
|
+
"name": "open",
|
|
266
|
+
"parameters": [
|
|
267
|
+
{
|
|
268
|
+
"name": "{ trigger }"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"name": "options",
|
|
272
|
+
"type": {
|
|
273
|
+
"text": "{ trigger: 'hover' | 'focus' }"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"kind": "method",
|
|
280
|
+
"name": "setTarget",
|
|
281
|
+
"parameters": [
|
|
282
|
+
{
|
|
283
|
+
"name": "target",
|
|
284
|
+
"type": {
|
|
285
|
+
"text": "HTMLElement | null"
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
"superclass": {
|
|
292
|
+
"name": "SlotController",
|
|
293
|
+
"package": "@vaadin/component-base/src/slot-controller.js"
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
],
|
|
297
|
+
"exports": [
|
|
298
|
+
{
|
|
299
|
+
"kind": "js",
|
|
300
|
+
"name": "ContextMenuTooltipController",
|
|
301
|
+
"declaration": {
|
|
302
|
+
"name": "ContextMenuTooltipController",
|
|
303
|
+
"module": "src/vaadin-context-menu-tooltip-controller.js"
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
]
|
|
307
|
+
},
|
|
233
308
|
{
|
|
234
309
|
"kind": "javascript-module",
|
|
235
310
|
"path": "src/vaadin-context-menu.js",
|
|
236
311
|
"declarations": [
|
|
237
312
|
{
|
|
238
313
|
"kind": "class",
|
|
239
|
-
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](#/elements/vaadin-item).\n- `<vaadin-context-menu-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).\n\nThe `<vaadin-context-menu-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
314
|
+
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n#### Disabled menu items\n\nWhen disabled, menu items are rendered as \"dimmed\".\n\nBy default, disabled items are not focusable and don't react to hover.\nAs a result, they are hidden from assistive technologies, and it's not\npossible to show a tooltip to explain why they are disabled. This can\nbe addressed by enabling the feature flag `accessibleDisabledMenuItems`,\nwhich makes disabled items focusable and hoverable, while still\npreventing them from being activated:\n\n```js\n// Set before any context menu is attached to the DOM.\nwindow.Vaadin.featureFlags.accessibleDisabledMenuItems = true;\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](#/elements/vaadin-item).\n- `<vaadin-context-menu-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).\n\nThe `<vaadin-context-menu-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
240
315
|
"name": "ContextMenu",
|
|
241
316
|
"members": [
|
|
242
317
|
{
|
|
@@ -269,7 +344,7 @@
|
|
|
269
344
|
"type": {
|
|
270
345
|
"text": "!Array<!ContextMenuItem> | undefined"
|
|
271
346
|
},
|
|
272
|
-
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```",
|
|
347
|
+
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```",
|
|
273
348
|
"attribute": "items",
|
|
274
349
|
"inheritedFrom": {
|
|
275
350
|
"name": "ItemsMixin",
|
|
@@ -571,7 +646,7 @@
|
|
|
571
646
|
"type": {
|
|
572
647
|
"text": "!Array<!ContextMenuItem> | undefined"
|
|
573
648
|
},
|
|
574
|
-
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```",
|
|
649
|
+
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```",
|
|
575
650
|
"attribute": "items"
|
|
576
651
|
}
|
|
577
652
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/context-menu",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.2.0-alpha10",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -37,21 +37,21 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
40
|
-
"@vaadin/a11y-base": "
|
|
41
|
-
"@vaadin/component-base": "
|
|
42
|
-
"@vaadin/item": "
|
|
43
|
-
"@vaadin/list-box": "
|
|
44
|
-
"@vaadin/lit-renderer": "
|
|
45
|
-
"@vaadin/overlay": "
|
|
46
|
-
"@vaadin/vaadin-themable-mixin": "
|
|
40
|
+
"@vaadin/a11y-base": "25.2.0-alpha10",
|
|
41
|
+
"@vaadin/component-base": "25.2.0-alpha10",
|
|
42
|
+
"@vaadin/item": "25.2.0-alpha10",
|
|
43
|
+
"@vaadin/list-box": "25.2.0-alpha10",
|
|
44
|
+
"@vaadin/lit-renderer": "25.2.0-alpha10",
|
|
45
|
+
"@vaadin/overlay": "25.2.0-alpha10",
|
|
46
|
+
"@vaadin/vaadin-themable-mixin": "25.2.0-alpha10",
|
|
47
47
|
"lit": "^3.0.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@vaadin/aura": "
|
|
51
|
-
"@vaadin/chai-plugins": "
|
|
52
|
-
"@vaadin/test-runner-commands": "
|
|
50
|
+
"@vaadin/aura": "25.2.0-alpha10",
|
|
51
|
+
"@vaadin/chai-plugins": "25.2.0-alpha10",
|
|
52
|
+
"@vaadin/test-runner-commands": "25.2.0-alpha10",
|
|
53
53
|
"@vaadin/testing-helpers": "^2.0.0",
|
|
54
|
-
"@vaadin/vaadin-lumo-styles": "
|
|
54
|
+
"@vaadin/vaadin-lumo-styles": "25.2.0-alpha10",
|
|
55
55
|
"sinon": "^21.0.2"
|
|
56
56
|
},
|
|
57
57
|
"customElements": "custom-elements.json",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"web-types.json",
|
|
60
60
|
"web-types.lit.json"
|
|
61
61
|
],
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "1303b6a3eeecb44a9d26f2b53cb56d9e906febdf"
|
|
63
63
|
}
|
|
@@ -47,6 +47,11 @@ class ContextMenuItem extends ItemMixin(ThemableMixin(DirMixin(PolylitMixin(Lumo
|
|
|
47
47
|
|
|
48
48
|
this.setAttribute('role', 'menuitem');
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
/** @override */
|
|
52
|
+
__shouldAllowFocusWhenDisabled() {
|
|
53
|
+
return window.Vaadin.featureFlags.accessibleDisabledMenuItems;
|
|
54
|
+
}
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
defineCustomElement(ContextMenuItem);
|
|
@@ -7,6 +7,7 @@ import { isElementFocusable, isKeyboardActive } from '@vaadin/a11y-base/src/focu
|
|
|
7
7
|
import { isAndroid, isIOS } from '@vaadin/component-base/src/browser-utils.js';
|
|
8
8
|
import { addListener, deepTargetFind, gestures, removeListener } from '@vaadin/component-base/src/gestures.js';
|
|
9
9
|
import { MediaQueryController } from '@vaadin/component-base/src/media-query-controller.js';
|
|
10
|
+
import { ContextMenuTooltipController } from './vaadin-context-menu-tooltip-controller.js';
|
|
10
11
|
import { ItemsMixin } from './vaadin-contextmenu-items-mixin.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -172,6 +173,15 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
172
173
|
this._fullscreen = matches;
|
|
173
174
|
}),
|
|
174
175
|
);
|
|
176
|
+
|
|
177
|
+
// Sub-menus inherit the tooltip controller from their parent menu
|
|
178
|
+
// (assigned before `firstUpdated` runs) to reuse the same slotted
|
|
179
|
+
// `<vaadin-tooltip>` across nesting levels. Only create a new one
|
|
180
|
+
// when none was inherited, i.e. on the outer host.
|
|
181
|
+
if (!this._tooltipController) {
|
|
182
|
+
this._tooltipController = new ContextMenuTooltipController(this);
|
|
183
|
+
this.addController(this._tooltipController);
|
|
184
|
+
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
/**
|
|
@@ -645,10 +655,4 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
645
655
|
this.close();
|
|
646
656
|
}
|
|
647
657
|
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* Fired when the context menu is closed.
|
|
651
|
-
*
|
|
652
|
-
* @event closed
|
|
653
|
-
*/
|
|
654
658
|
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2016 - 2026 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Controller for the tooltip slotted into `<vaadin-context-menu>`. Configures
|
|
10
|
+
* the tooltip in manual mode and drives its target, context, and position
|
|
11
|
+
* based on the currently hovered or focused item.
|
|
12
|
+
*/
|
|
13
|
+
export class ContextMenuTooltipController extends SlotController {
|
|
14
|
+
constructor(host) {
|
|
15
|
+
super(host, 'tooltip');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** @override */
|
|
19
|
+
initCustomNode(tooltipNode) {
|
|
20
|
+
tooltipNode.manual = true;
|
|
21
|
+
tooltipNode.generator ||= ({ item }) => item?.tooltip;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** @protected */
|
|
25
|
+
_getItem(target) {
|
|
26
|
+
return target._item;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @protected */
|
|
30
|
+
_getDefaultPosition(target) {
|
|
31
|
+
const item = this._getItem(target);
|
|
32
|
+
return item.children?.length > 0 && !item.disabled ? 'start' : 'end';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {HTMLElement | null} target
|
|
37
|
+
*/
|
|
38
|
+
setTarget(target) {
|
|
39
|
+
const tooltipNode = this.node;
|
|
40
|
+
if (!tooltipNode) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const item = target ? this._getItem(target) : null;
|
|
45
|
+
if (item?.tooltip) {
|
|
46
|
+
tooltipNode.target = target;
|
|
47
|
+
tooltipNode.context = { item };
|
|
48
|
+
tooltipNode._position = item.tooltipPosition || this._getDefaultPosition(target);
|
|
49
|
+
} else {
|
|
50
|
+
tooltipNode.target = null;
|
|
51
|
+
tooltipNode.context = { item: null };
|
|
52
|
+
this.close(true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {{ trigger: 'hover' | 'focus' }} options
|
|
58
|
+
*/
|
|
59
|
+
open({ trigger }) {
|
|
60
|
+
const tooltipNode = this.node;
|
|
61
|
+
if (tooltipNode?.isConnected && tooltipNode.target) {
|
|
62
|
+
tooltipNode._stateController.open({
|
|
63
|
+
hover: trigger === 'hover',
|
|
64
|
+
focus: trigger === 'focus',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {boolean} immediate
|
|
71
|
+
*/
|
|
72
|
+
close(immediate) {
|
|
73
|
+
const tooltipNode = this.node;
|
|
74
|
+
tooltipNode?._stateController.close(immediate);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -106,6 +106,34 @@ export interface ContextMenuEventMap<TItem extends ContextMenuItem = ContextMenu
|
|
|
106
106
|
*
|
|
107
107
|
* **NOTE:** when the `items` array is defined, the renderer cannot be used.
|
|
108
108
|
*
|
|
109
|
+
* #### Disabled menu items
|
|
110
|
+
*
|
|
111
|
+
* When disabled, menu items are rendered as "dimmed".
|
|
112
|
+
*
|
|
113
|
+
* By default, disabled items are not focusable and don't react to hover.
|
|
114
|
+
* As a result, they are hidden from assistive technologies, and it's not
|
|
115
|
+
* possible to show a tooltip to explain why they are disabled. This can
|
|
116
|
+
* be addressed by enabling the feature flag `accessibleDisabledMenuItems`,
|
|
117
|
+
* which makes disabled items focusable and hoverable, while still
|
|
118
|
+
* preventing them from being activated:
|
|
119
|
+
*
|
|
120
|
+
* ```js
|
|
121
|
+
* // Set before any context menu is attached to the DOM.
|
|
122
|
+
* window.Vaadin.featureFlags.accessibleDisabledMenuItems = true;
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* #### Item tooltips
|
|
126
|
+
*
|
|
127
|
+
* Menu items can have tooltips that are shown on hover and keyboard
|
|
128
|
+
* focus. To enable them, add a slotted `<vaadin-tooltip>` element
|
|
129
|
+
* and set the `tooltip` property on each item that should have one:
|
|
130
|
+
*
|
|
131
|
+
* ```html
|
|
132
|
+
* <vaadin-context-menu>
|
|
133
|
+
* <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
|
|
134
|
+
* </vaadin-context-menu>
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
109
137
|
* ### Rendering
|
|
110
138
|
*
|
|
111
139
|
* The content of the menu can be populated by using the renderer callback function.
|
|
@@ -54,6 +54,34 @@ import { ContextMenuMixin } from './vaadin-context-menu-mixin.js';
|
|
|
54
54
|
*
|
|
55
55
|
* **NOTE:** when the `items` array is defined, the renderer cannot be used.
|
|
56
56
|
*
|
|
57
|
+
* #### Disabled menu items
|
|
58
|
+
*
|
|
59
|
+
* When disabled, menu items are rendered as "dimmed".
|
|
60
|
+
*
|
|
61
|
+
* By default, disabled items are not focusable and don't react to hover.
|
|
62
|
+
* As a result, they are hidden from assistive technologies, and it's not
|
|
63
|
+
* possible to show a tooltip to explain why they are disabled. This can
|
|
64
|
+
* be addressed by enabling the feature flag `accessibleDisabledMenuItems`,
|
|
65
|
+
* which makes disabled items focusable and hoverable, while still
|
|
66
|
+
* preventing them from being activated:
|
|
67
|
+
*
|
|
68
|
+
* ```js
|
|
69
|
+
* // Set before any context menu is attached to the DOM.
|
|
70
|
+
* window.Vaadin.featureFlags.accessibleDisabledMenuItems = true;
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* #### Item tooltips
|
|
74
|
+
*
|
|
75
|
+
* Menu items can have tooltips that are shown on hover and keyboard
|
|
76
|
+
* focus. To enable them, add a slotted `<vaadin-tooltip>` element
|
|
77
|
+
* and set the `tooltip` property on each item that should have one:
|
|
78
|
+
*
|
|
79
|
+
* ```html
|
|
80
|
+
* <vaadin-context-menu>
|
|
81
|
+
* <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
|
|
82
|
+
* </vaadin-context-menu>
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
57
85
|
* ### Rendering
|
|
58
86
|
*
|
|
59
87
|
* The content of the menu can be populated by using the renderer callback function.
|
|
@@ -267,7 +295,7 @@ class ContextMenu extends ContextMenuMixin(ElementMixin(ThemePropertyMixin(Polyl
|
|
|
267
295
|
.modeless="${this._modeless}"
|
|
268
296
|
.renderer="${this.items ? this.__itemsRenderer : this.renderer}"
|
|
269
297
|
.position="${position}"
|
|
270
|
-
.positionTarget="${position ? context
|
|
298
|
+
.positionTarget="${position ? context?.target : this._positionTarget}"
|
|
271
299
|
.horizontalAlign="${this.__computeHorizontalAlign(position)}"
|
|
272
300
|
.verticalAlign="${this.__computeVerticalAlign(position)}"
|
|
273
301
|
?no-horizontal-overlap="${this.__computeNoHorizontalOverlap(position)}"
|
|
@@ -283,6 +311,8 @@ class ContextMenu extends ContextMenuMixin(ElementMixin(ThemePropertyMixin(Polyl
|
|
|
283
311
|
<slot name="overlay"></slot>
|
|
284
312
|
<slot name="submenu" slot="submenu"></slot>
|
|
285
313
|
</vaadin-context-menu-overlay>
|
|
314
|
+
|
|
315
|
+
<slot name="tooltip"></slot>
|
|
286
316
|
`;
|
|
287
317
|
}
|
|
288
318
|
|
|
@@ -321,14 +351,6 @@ class ContextMenu extends ContextMenuMixin(ElementMixin(ThemePropertyMixin(Polyl
|
|
|
321
351
|
|
|
322
352
|
return ['top-start', 'top-end', 'top', 'start-bottom', 'end-bottom'].includes(position) ? 'bottom' : 'top';
|
|
323
353
|
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Fired when an item is selected when the context menu is populated using the `items` API.
|
|
327
|
-
*
|
|
328
|
-
* @event item-selected
|
|
329
|
-
* @param {Object} detail
|
|
330
|
-
* @param {Object} detail.value the selected menu item
|
|
331
|
-
*/
|
|
332
354
|
}
|
|
333
355
|
|
|
334
356
|
defineCustomElement(ContextMenu);
|
|
@@ -120,7 +120,7 @@ register({
|
|
|
120
120
|
ev.detail = { x, y, sourceEvent };
|
|
121
121
|
target.dispatchEvent(ev);
|
|
122
122
|
// Forward `preventDefault` in a clean way
|
|
123
|
-
if (ev.defaultPrevented && sourceEvent
|
|
123
|
+
if (ev.defaultPrevented && sourceEvent?.preventDefault) {
|
|
124
124
|
sourceEvent.preventDefault();
|
|
125
125
|
}
|
|
126
126
|
},
|
|
@@ -9,6 +9,19 @@ import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
|
9
9
|
|
|
10
10
|
export type ContextMenuItem<TItemData extends object = object> = {
|
|
11
11
|
text?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Text to be set as the menu item's tooltip.
|
|
14
|
+
* Requires a `<vaadin-tooltip slot="tooltip">` element to be added inside the `<vaadin-context-menu>`.
|
|
15
|
+
*/
|
|
16
|
+
tooltip?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Position of the item's tooltip relative to the item
|
|
19
|
+
* (e.g. `end`, `top`, `bottom-start`). Items with a sub-menu default to `start` to
|
|
20
|
+
* avoid overlap with the opening sub-menu; all other items, including disabled ones
|
|
21
|
+
* (whose sub-menus cannot be opened), default to `end`. If the slotted
|
|
22
|
+
* `<vaadin-tooltip>` has its `position` property set, that value is used instead.
|
|
23
|
+
*/
|
|
24
|
+
tooltipPosition?: string;
|
|
12
25
|
component?: HTMLElement | string;
|
|
13
26
|
disabled?: boolean;
|
|
14
27
|
checked?: boolean;
|
|
@@ -48,6 +61,18 @@ export declare class ItemsMixinClass<TItem extends ContextMenuItem = ContextMenu
|
|
|
48
61
|
* { text: 'Menu Item 3', disabled: true, className: 'last' }
|
|
49
62
|
* ];
|
|
50
63
|
* ```
|
|
64
|
+
*
|
|
65
|
+
* #### Item tooltips
|
|
66
|
+
*
|
|
67
|
+
* Menu items can have tooltips that are shown on hover and keyboard
|
|
68
|
+
* focus. To enable them, add a slotted `<vaadin-tooltip>` element
|
|
69
|
+
* and set the `tooltip` property on each item that should have one:
|
|
70
|
+
*
|
|
71
|
+
* ```html
|
|
72
|
+
* <vaadin-context-menu>
|
|
73
|
+
* <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
|
|
74
|
+
* </vaadin-context-menu>
|
|
75
|
+
* ```
|
|
51
76
|
*/
|
|
52
77
|
items: TItem[] | undefined;
|
|
53
78
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2016 - 2026 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
|
|
6
7
|
import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -16,6 +17,13 @@ export const ItemsMixin = (superClass) =>
|
|
|
16
17
|
* @typedef ContextMenuItem
|
|
17
18
|
* @type {object}
|
|
18
19
|
* @property {string} text - Text to be set as the menu item component's textContent
|
|
20
|
+
* @property {string} tooltip - Text to be set as the menu item's tooltip.
|
|
21
|
+
* Requires a `<vaadin-tooltip slot="tooltip">` element to be added inside the `<vaadin-context-menu>`.
|
|
22
|
+
* @property {string} tooltipPosition - Position of the item's tooltip relative to the
|
|
23
|
+
* item (e.g. `end`, `top`, `bottom-start`). Items with a sub-menu default to `start`
|
|
24
|
+
* to avoid overlap with the opening sub-menu; all other items, including disabled
|
|
25
|
+
* ones (whose sub-menus cannot be opened), default to `end`. If the slotted
|
|
26
|
+
* `<vaadin-tooltip>` has its `position` property set, that value is used instead.
|
|
19
27
|
* @property {string | HTMLElement} component - The component to represent the item.
|
|
20
28
|
* Either a tagName or an element instance. Defaults to "vaadin-context-menu-item".
|
|
21
29
|
* @property {boolean} disabled - If true, the item is disabled and cannot be selected
|
|
@@ -54,6 +62,18 @@ export const ItemsMixin = (superClass) =>
|
|
|
54
62
|
* ];
|
|
55
63
|
* ```
|
|
56
64
|
*
|
|
65
|
+
* #### Item tooltips
|
|
66
|
+
*
|
|
67
|
+
* Menu items can have tooltips that are shown on hover and keyboard
|
|
68
|
+
* focus. To enable them, add a slotted `<vaadin-tooltip>` element
|
|
69
|
+
* and set the `tooltip` property on each item that should have one:
|
|
70
|
+
*
|
|
71
|
+
* ```html
|
|
72
|
+
* <vaadin-context-menu>
|
|
73
|
+
* <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
|
|
74
|
+
* </vaadin-context-menu>
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
57
77
|
* @type {!Array<!ContextMenuItem> | undefined}
|
|
58
78
|
*/
|
|
59
79
|
items: {
|
|
@@ -105,6 +125,7 @@ export const ItemsMixin = (superClass) =>
|
|
|
105
125
|
disconnectedCallback() {
|
|
106
126
|
super.disconnectedCallback();
|
|
107
127
|
document.documentElement.removeEventListener('click', this.__itemsOutsideClickListener);
|
|
128
|
+
this._tooltipController.setTarget(null);
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
/**
|
|
@@ -126,7 +147,7 @@ export const ItemsMixin = (superClass) =>
|
|
|
126
147
|
// If parent item is not focused, do not focus submenu
|
|
127
148
|
if (overlay.parentOverlay) {
|
|
128
149
|
const parent = overlay.parentOverlay._contentRoot.querySelector('[expanded]');
|
|
129
|
-
if (parent
|
|
150
|
+
if (parent?.hasAttribute('focused') && child) {
|
|
130
151
|
child.focus();
|
|
131
152
|
} else {
|
|
132
153
|
overlay.$.overlay.focus();
|
|
@@ -264,6 +285,31 @@ export const ItemsMixin = (superClass) =>
|
|
|
264
285
|
}
|
|
265
286
|
|
|
266
287
|
this.__showSubMenu(event);
|
|
288
|
+
|
|
289
|
+
const itemElement = event.target.closest(`${this._tagNamePrefix}-item`);
|
|
290
|
+
this._tooltipController.setTarget(itemElement);
|
|
291
|
+
this._tooltipController.open({ trigger: 'hover' });
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
overlay.addEventListener('mouseleave', (event) => {
|
|
295
|
+
// Ignore events from the submenus
|
|
296
|
+
if (event.composedPath().includes(this._subMenu)) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
this._tooltipController.close();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
overlay.addEventListener('focusin', (event) => {
|
|
304
|
+
// Ignore events from the submenus
|
|
305
|
+
// Ignore non-keyboard focus changes (e.g. clicks).
|
|
306
|
+
if (event.composedPath().includes(this._subMenu) || !isKeyboardActive()) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const itemElement = event.target.closest(`${this._tagNamePrefix}-item`);
|
|
311
|
+
this._tooltipController.setTarget(itemElement);
|
|
312
|
+
this._tooltipController.open({ trigger: 'focus' });
|
|
267
313
|
});
|
|
268
314
|
|
|
269
315
|
overlay.addEventListener('keydown', (event) => {
|
|
@@ -300,6 +346,11 @@ export const ItemsMixin = (superClass) =>
|
|
|
300
346
|
__initSubMenu() {
|
|
301
347
|
const subMenu = document.createElement(this.constructor.is);
|
|
302
348
|
|
|
349
|
+
// The slotted `<vaadin-tooltip>` lives on the outer `<vaadin-context-menu>`
|
|
350
|
+
// host. Its tooltip controller instance is shared across sub-menus to
|
|
351
|
+
// reuse the same tooltip element for items at every nesting level.
|
|
352
|
+
subMenu._tooltipController = this._tooltipController;
|
|
353
|
+
|
|
303
354
|
subMenu._modeless = true;
|
|
304
355
|
subMenu.openOn = 'opensubmenu';
|
|
305
356
|
|
|
@@ -374,12 +425,12 @@ export const ItemsMixin = (superClass) =>
|
|
|
374
425
|
const subMenu = this._subMenu;
|
|
375
426
|
const expandedItem = this._listBox.querySelector('[expanded]');
|
|
376
427
|
|
|
377
|
-
if (item && item !== expandedItem) {
|
|
428
|
+
if (item && item !== expandedItem && !item.disabled) {
|
|
378
429
|
const { children } = item._item;
|
|
379
430
|
|
|
380
431
|
// Check if the sub-menu was focused before closing it.
|
|
381
432
|
const child = subMenu._overlayElement._contentRoot.firstElementChild;
|
|
382
|
-
const isSubmenuFocused = child
|
|
433
|
+
const isSubmenuFocused = child?.focused;
|
|
383
434
|
|
|
384
435
|
// Mark previously expanded item as collapsed
|
|
385
436
|
if (expandedItem) {
|
|
@@ -395,7 +446,7 @@ export const ItemsMixin = (superClass) =>
|
|
|
395
446
|
return;
|
|
396
447
|
}
|
|
397
448
|
|
|
398
|
-
if (children
|
|
449
|
+
if (children?.length) {
|
|
399
450
|
// Open or update the submenu if the new item has children
|
|
400
451
|
this.__updateExpanded(item, true);
|
|
401
452
|
this.__openSubMenu(subMenu, item);
|
|
@@ -407,6 +458,12 @@ export const ItemsMixin = (superClass) =>
|
|
|
407
458
|
this._overlayElement.$.overlay.focus();
|
|
408
459
|
}
|
|
409
460
|
}
|
|
461
|
+
|
|
462
|
+
// Only reachable with `accessibleDisabledMenuItems` enabled (disabled
|
|
463
|
+
// items otherwise have `pointer-events: none` and never receive mouseover).
|
|
464
|
+
if (item?.disabled) {
|
|
465
|
+
subMenu.close();
|
|
466
|
+
}
|
|
410
467
|
}
|
|
411
468
|
|
|
412
469
|
/** @protected */
|
|
@@ -103,7 +103,7 @@ export const MenuOverlayMixin = (superClass) =>
|
|
|
103
103
|
|
|
104
104
|
// Adjust constraints to ensure bottom-aligned applies to sub-menu.
|
|
105
105
|
const parent = this.parentOverlay;
|
|
106
|
-
if (parent
|
|
106
|
+
if (parent?.hasAttribute('bottom-aligned')) {
|
|
107
107
|
const parentStyle = getComputedStyle(parent);
|
|
108
108
|
yMax = yMax - parseFloat(parentStyle.bottom) - parseFloat(parentStyle.height);
|
|
109
109
|
}
|
package/web-types.json
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/context-menu",
|
|
4
|
-
"version": "25.
|
|
4
|
+
"version": "25.2.0-alpha10",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
8
8
|
"elements": [
|
|
9
9
|
{
|
|
10
10
|
"name": "vaadin-context-menu",
|
|
11
|
-
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.
|
|
11
|
+
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n#### Disabled menu items\n\nWhen disabled, menu items are rendered as \"dimmed\".\n\nBy default, disabled items are not focusable and don't react to hover.\nAs a result, they are hidden from assistive technologies, and it's not\npossible to show a tooltip to explain why they are disabled. This can\nbe addressed by enabling the feature flag `accessibleDisabledMenuItems`,\nwhich makes disabled items focusable and hoverable, while still\npreventing them from being activated:\n\n```js\n// Set before any context menu is attached to the DOM.\nwindow.Vaadin.featureFlags.accessibleDisabledMenuItems = true;\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.2.0-alpha10/#/elements/vaadin-item).\n- `<vaadin-context-menu-list-box>` - has the same API as [`<vaadin-list-box>`](https://cdn.vaadin.com/vaadin-web-components/25.2.0-alpha10/#/elements/vaadin-list-box).\n\nThe `<vaadin-context-menu-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
12
12
|
"attributes": [
|
|
13
13
|
{
|
|
14
14
|
"name": "close-on",
|
|
15
15
|
"description": "Event name to listen for closing the context menu.",
|
|
16
16
|
"value": {
|
|
17
17
|
"type": [
|
|
18
|
-
"string"
|
|
19
|
-
"null",
|
|
20
|
-
"undefined"
|
|
18
|
+
"string"
|
|
21
19
|
]
|
|
22
20
|
}
|
|
23
21
|
},
|
|
@@ -26,9 +24,7 @@
|
|
|
26
24
|
"description": "Event name to listen for opening the context menu.",
|
|
27
25
|
"value": {
|
|
28
26
|
"type": [
|
|
29
|
-
"string"
|
|
30
|
-
"null",
|
|
31
|
-
"undefined"
|
|
27
|
+
"string"
|
|
32
28
|
]
|
|
33
29
|
}
|
|
34
30
|
},
|
|
@@ -37,9 +33,7 @@
|
|
|
37
33
|
"description": "Position of the overlay with respect to the target.\nSupported values: null, `top-start`, `top`, `top-end`,\n`bottom-start`, `bottom`, `bottom-end`, `start-top`,\n`start`, `start-bottom`, `end-top`, `end`, `end-bottom`.",
|
|
38
34
|
"value": {
|
|
39
35
|
"type": [
|
|
40
|
-
"string"
|
|
41
|
-
"null",
|
|
42
|
-
"undefined"
|
|
36
|
+
"string"
|
|
43
37
|
]
|
|
44
38
|
}
|
|
45
39
|
},
|
|
@@ -48,9 +42,7 @@
|
|
|
48
42
|
"description": "CSS selector that can be used to target any child element\nof the context menu to listen for `openOn` events.",
|
|
49
43
|
"value": {
|
|
50
44
|
"type": [
|
|
51
|
-
"string"
|
|
52
|
-
"null",
|
|
53
|
-
"undefined"
|
|
45
|
+
"string"
|
|
54
46
|
]
|
|
55
47
|
}
|
|
56
48
|
},
|
|
@@ -73,18 +65,16 @@
|
|
|
73
65
|
"description": "Event name to listen for closing the context menu.",
|
|
74
66
|
"value": {
|
|
75
67
|
"type": [
|
|
76
|
-
"string"
|
|
77
|
-
"null",
|
|
78
|
-
"undefined"
|
|
68
|
+
"string"
|
|
79
69
|
]
|
|
80
70
|
}
|
|
81
71
|
},
|
|
82
72
|
{
|
|
83
73
|
"name": "items",
|
|
84
|
-
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```",
|
|
74
|
+
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```",
|
|
85
75
|
"value": {
|
|
86
76
|
"type": [
|
|
87
|
-
"Array
|
|
77
|
+
"Array<ContextMenuItem>",
|
|
88
78
|
"undefined"
|
|
89
79
|
]
|
|
90
80
|
}
|
|
@@ -103,9 +93,7 @@
|
|
|
103
93
|
"description": "Event name to listen for opening the context menu.",
|
|
104
94
|
"value": {
|
|
105
95
|
"type": [
|
|
106
|
-
"string"
|
|
107
|
-
"null",
|
|
108
|
-
"undefined"
|
|
96
|
+
"string"
|
|
109
97
|
]
|
|
110
98
|
}
|
|
111
99
|
},
|
|
@@ -114,9 +102,7 @@
|
|
|
114
102
|
"description": "Position of the overlay with respect to the target.\nSupported values: null, `top-start`, `top`, `top-end`,\n`bottom-start`, `bottom`, `bottom-end`, `start-top`,\n`start`, `start-bottom`, `end-top`, `end`, `end-bottom`.",
|
|
115
103
|
"value": {
|
|
116
104
|
"type": [
|
|
117
|
-
"string"
|
|
118
|
-
"null",
|
|
119
|
-
"undefined"
|
|
105
|
+
"string"
|
|
120
106
|
]
|
|
121
107
|
}
|
|
122
108
|
},
|
|
@@ -135,14 +121,16 @@
|
|
|
135
121
|
"description": "CSS selector that can be used to target any child element\nof the context menu to listen for `openOn` events.",
|
|
136
122
|
"value": {
|
|
137
123
|
"type": [
|
|
138
|
-
"string"
|
|
139
|
-
"null",
|
|
140
|
-
"undefined"
|
|
124
|
+
"string"
|
|
141
125
|
]
|
|
142
126
|
}
|
|
143
127
|
}
|
|
144
128
|
],
|
|
145
129
|
"events": [
|
|
130
|
+
{
|
|
131
|
+
"name": "close-all-menus",
|
|
132
|
+
"description": "Fired when all menus should close, e.g., after pressing Tab or on submenu close."
|
|
133
|
+
},
|
|
146
134
|
{
|
|
147
135
|
"name": "closed",
|
|
148
136
|
"description": "Fired when the context menu is closed."
|
|
@@ -151,6 +139,10 @@
|
|
|
151
139
|
"name": "item-selected",
|
|
152
140
|
"description": "Fired when an item is selected when the context menu is populated using the `items` API."
|
|
153
141
|
},
|
|
142
|
+
{
|
|
143
|
+
"name": "items-outside-click",
|
|
144
|
+
"description": "Fired when a click happens outside any open sub-menus."
|
|
145
|
+
},
|
|
154
146
|
{
|
|
155
147
|
"name": "opened-changed",
|
|
156
148
|
"description": "Fired when the `opened` property changes."
|
package/web-types.lit.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@vaadin/context-menu",
|
|
4
|
-
"version": "25.
|
|
4
|
+
"version": "25.2.0-alpha10",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"framework": "lit",
|
|
7
7
|
"framework-config": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"elements": [
|
|
17
17
|
{
|
|
18
18
|
"name": "vaadin-context-menu",
|
|
19
|
-
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.
|
|
19
|
+
"description": "`<vaadin-context-menu>` is a Web Component for creating context menus.\n\n### Items\n\nItems is a higher level convenience API for defining a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nWhen an item is selected, `<vaadin-context-menu>` dispatches an \"item-selected\" event\nwith the selected item as `event.detail.value` property.\nIf item does not have `keepOpen` property the menu will be closed.\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n\ncontextMenu.addEventListener('item-selected', e => {\n const item = e.detail.value;\n console.log(`${item.text} selected`);\n});\n```\n\n**NOTE:** when the `items` array is defined, the renderer cannot be used.\n\n#### Disabled menu items\n\nWhen disabled, menu items are rendered as \"dimmed\".\n\nBy default, disabled items are not focusable and don't react to hover.\nAs a result, they are hidden from assistive technologies, and it's not\npossible to show a tooltip to explain why they are disabled. This can\nbe addressed by enabling the feature flag `accessibleDisabledMenuItems`,\nwhich makes disabled items focusable and hoverable, while still\npreventing them from being activated:\n\n```js\n// Set before any context menu is attached to the DOM.\nwindow.Vaadin.featureFlags.accessibleDisabledMenuItems = true;\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```\n\n### Rendering\n\nThe content of the menu can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `contextMenu`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `contextMenu`. Before generating\nnew content, the renderer function should check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-context-menu id=\"contextMenu\">\n <p>This paragraph has a context menu.</p>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'Content of the selector: ' + context.target.textContent;\n};\n```\n\nYou can access the menu context inside the renderer using\n`context.target` and `context.detail`.\n\nRenderer is called on the opening of the context-menu and each time the related context is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### `vaadin-contextmenu` Gesture Event\n\n`vaadin-contextmenu` is a gesture event (a custom event),\nwhich is dispatched after either `contextmenu` or long touch events.\nThis enables support for both mouse and touch environments in a uniform way.\n\n`<vaadin-context-menu>` opens the menu overlay on the `vaadin-contextmenu`\nevent by default.\n\n### Menu Listener\n\nBy default, the `<vaadin-context-menu>` element listens for the menu opening\nevent on itself. In case if you do not want to wrap the target, you can listen for\nevents on an element outside the `<vaadin-context-menu>` by setting the\n`listenOn` property:\n\n```html\n<vaadin-context-menu id=\"contextMenu\"></vaadin-context-menu>\n\n<div id=\"menuListener\">The element that listens for the contextmenu event.</div>\n```\n```javascript\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.listenOn = document.querySelector('#menuListener');\n```\n\n### Filtering Menu Targets\n\nBy default, the listener element and all its descendants open the context\nmenu. You can filter the menu targets to a smaller set of elements inside\nthe listener element by setting the `selector` property.\n\nIn the following example, only the elements matching `.has-menu` will open the context menu:\n\n```html\n<vaadin-context-menu selector=\".has-menu\">\n <p class=\"has-menu\">This paragraph opens the context menu</p>\n <p>This paragraph does not open the context menu</p>\n</vaadin-context-menu>\n```\n\n### Menu Context\n\nThe following properties are available in the `context` argument:\n\n- `target` is the menu opening event target, which is the element that\nthe user has called the context menu for\n- `detail` is the menu opening event detail\n\nIn the following example, the menu item text is composed with the contents\nof the element that opened the menu:\n\n```html\n<vaadin-context-menu selector=\"li\" id=\"contextMenu\">\n <ul>\n <li>Foo</li>\n <li>Bar</li>\n <li>Baz</li>\n </ul>\n</vaadin-context-menu>\n```\n```js\nconst contextMenu = document.querySelector('#contextMenu');\ncontextMenu.renderer = (root, contextMenu, context) => {\n let listBox = root.firstElementChild;\n if (!listBox) {\n listBox = document.createElement('vaadin-list-box');\n root.appendChild(listBox);\n }\n\n let item = listBox.querySelector('vaadin-item');\n if (!item) {\n item = document.createElement('vaadin-item');\n listBox.appendChild(item);\n }\n item.textContent = 'The menu target: ' + context.target.textContent;\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description\n--------------------------------------|-------------\n`--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target\n`--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target\n`--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target\n`--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Internal components\n\nWhen using `items` API the following internal components are themable:\n\n- `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.2.0-alpha10/#/elements/vaadin-item).\n- `<vaadin-context-menu-list-box>` - has the same API as [`<vaadin-list-box>`](https://cdn.vaadin.com/vaadin-web-components/25.2.0-alpha10/#/elements/vaadin-list-box).\n\nThe `<vaadin-context-menu-item>` sub-menu elements have the following additional state attributes\non top of the built-in `<vaadin-item>` state attributes:\n\nAttribute | Description\n---------- |-------------\n`expanded` | Expanded parent item.",
|
|
20
20
|
"extension": true,
|
|
21
21
|
"attributes": [
|
|
22
22
|
{
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"name": ".items",
|
|
31
|
-
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```",
|
|
31
|
+
"description": "Defines a (hierarchical) menu structure for the component.\nIf a menu item has a non-empty `children` set, a sub-menu with the child items is opened\nnext to the parent menu on mouseover, tap or a right arrow keypress.\n\nThe items API can't be used together with a renderer!\n\n#### Example\n\n```javascript\ncontextMenu.items = [\n { text: 'Menu Item 1', theme: 'primary', className: 'first', children:\n [\n { text: 'Menu Item 1-1', checked: true, keepOpen: true },\n { text: 'Menu Item 1-2' }\n ]\n },\n { component: 'hr' },\n { text: 'Menu Item 2', children:\n [\n { text: 'Menu Item 2-1' },\n { text: 'Menu Item 2-2', disabled: true }\n ]\n },\n { text: 'Menu Item 3', disabled: true, className: 'last' }\n];\n```\n\n#### Item tooltips\n\nMenu items can have tooltips that are shown on hover and keyboard\nfocus. To enable them, add a slotted `<vaadin-tooltip>` element\nand set the `tooltip` property on each item that should have one:\n\n```html\n<vaadin-context-menu>\n <vaadin-tooltip slot=\"tooltip\"></vaadin-tooltip>\n</vaadin-context-menu>\n```",
|
|
32
32
|
"value": {
|
|
33
33
|
"kind": "expression"
|
|
34
34
|
}
|
|
@@ -68,6 +68,13 @@
|
|
|
68
68
|
"kind": "expression"
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
"name": "@close-all-menus",
|
|
73
|
+
"description": "Fired when all menus should close, e.g., after pressing Tab or on submenu close.",
|
|
74
|
+
"value": {
|
|
75
|
+
"kind": "expression"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
71
78
|
{
|
|
72
79
|
"name": "@closed",
|
|
73
80
|
"description": "Fired when the context menu is closed.",
|
|
@@ -82,6 +89,13 @@
|
|
|
82
89
|
"kind": "expression"
|
|
83
90
|
}
|
|
84
91
|
},
|
|
92
|
+
{
|
|
93
|
+
"name": "@items-outside-click",
|
|
94
|
+
"description": "Fired when a click happens outside any open sub-menus.",
|
|
95
|
+
"value": {
|
|
96
|
+
"kind": "expression"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
85
99
|
{
|
|
86
100
|
"name": "@opened-changed",
|
|
87
101
|
"description": "Fired when the `opened` property changes.",
|