@redvars/peacock 3.8.6 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/code-highlighter.js +1 -4
- package/dist/code-highlighter.js.map +1 -1
- package/dist/custom-elements-jsdocs.json +93 -213
- package/dist/custom-elements.json +488 -2149
- package/dist/elevation.js +55 -2
- package/dist/elevation.js.map +1 -1
- package/dist/flow.js +762 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/loader.js +10 -9
- package/dist/loader.js.map +1 -1
- package/dist/menu-item.js +144 -63
- package/dist/menu-item.js.map +1 -1
- package/dist/menu.js +161 -73
- package/dist/menu.js.map +1 -1
- package/dist/src/flow/flow.d.ts +102 -0
- package/dist/src/flow/index.d.ts +2 -0
- package/dist/src/index.d.ts +3 -4
- package/dist/src/menu/menu/menu.d.ts +10 -9
- package/dist/src/menu/menu-item/menu-item.d.ts +1 -3
- package/dist/src/timeline/index.d.ts +2 -0
- package/dist/src/timeline/timeline-item.d.ts +23 -0
- package/dist/src/timeline/timeline.d.ts +26 -0
- package/dist/sub-menu.js +28 -1
- package/dist/sub-menu.js.map +1 -1
- package/dist/timeline-item.js +163 -0
- package/dist/timeline-item.js.map +1 -0
- package/dist/timeline.js +52 -0
- package/dist/timeline.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/readme.md +2 -2
- package/src/code-highlighter/code-highlighter.scss +1 -7
- package/src/elevation/demo/index.html +52 -0
- package/src/elevation/elevation.scss +52 -5
- package/src/elevation/elevation.ts +8 -1
- package/src/flow/flow.scss +195 -0
- package/src/flow/flow.ts +683 -0
- package/src/flow/index.ts +2 -0
- package/src/index.ts +3 -16
- package/src/loader.ts +10 -9
- package/src/menu/menu/copy-component-files.mjs +47 -0
- package/src/menu/menu/menu.scss +55 -17
- package/src/menu/menu/menu.ts +155 -84
- package/src/menu/menu-item/menu-item-colors.scss +3 -3
- package/src/menu/menu-item/menu-item.scss +118 -24
- package/src/menu/menu-item/menu-item.ts +61 -55
- package/src/menu/sub-menu/sub-menu.scss +30 -1
- package/src/timeline/index.ts +2 -0
- package/src/timeline/timeline-item.scss +98 -0
- package/src/timeline/timeline-item.ts +63 -0
- package/src/timeline/timeline.scss +11 -0
- package/src/timeline/timeline.ts +41 -0
- package/dist/canvas.js +0 -385
- package/dist/canvas.js.map +0 -1
- package/dist/flow-designer-node-CGSm6cUH.js +0 -553
- package/dist/flow-designer-node-CGSm6cUH.js.map +0 -1
- package/dist/flow-designer-node.js +0 -4
- package/dist/flow-designer-node.js.map +0 -1
- package/dist/flow-designer.js +0 -1417
- package/dist/flow-designer.js.map +0 -1
- package/dist/src/canvas/canvas.d.ts +0 -92
- package/dist/src/canvas/index.d.ts +0 -2
- package/dist/src/flow-designer/commands.d.ts +0 -66
- package/dist/src/flow-designer/flow-designer-node.d.ts +0 -46
- package/dist/src/flow-designer/flow-designer.d.ts +0 -133
- package/dist/src/flow-designer/index.d.ts +0 -7
- package/dist/src/flow-designer/layout.d.ts +0 -30
- package/dist/src/flow-designer/types.d.ts +0 -142
- package/dist/src/flow-designer/validation.d.ts +0 -43
- package/dist/src/flow-designer/workflow-utils.d.ts +0 -40
- package/src/canvas/canvas.scss +0 -72
- package/src/canvas/canvas.ts +0 -413
- package/src/canvas/index.ts +0 -2
- package/src/flow-designer/DEMO.md +0 -239
- package/src/flow-designer/commands.ts +0 -278
- package/src/flow-designer/flow-designer-node.ts +0 -172
- package/src/flow-designer/flow-designer.scss +0 -457
- package/src/flow-designer/flow-designer.ts +0 -611
- package/src/flow-designer/index.ts +0 -41
- package/src/flow-designer/layout.ts +0 -357
- package/src/flow-designer/types.ts +0 -166
- package/src/flow-designer/validation.ts +0 -284
- package/src/flow-designer/workflow-utils.ts +0 -282
- /package/dist/test/{flow-designer.test.d.ts → elevation.test.d.ts} +0 -0
package/src/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ export { Popover, PopoverContent } from './popover/index.js';
|
|
|
42
42
|
export { Breadcrumb, BreadcrumbItem } from './breadcrumb/index.js';
|
|
43
43
|
export { Menu, MenuItem, SubMenu } from './menu/index.js';
|
|
44
44
|
export { List, ListItem } from './list/index.js';
|
|
45
|
+
export { Timeline, TimelineItem } from './timeline/index.js';
|
|
45
46
|
export { Item } from './item/index.js';
|
|
46
47
|
|
|
47
48
|
export { CodeHighlighter } from './code-highlighter/index.js';
|
|
@@ -85,22 +86,8 @@ export {
|
|
|
85
86
|
CalendarMonthView,
|
|
86
87
|
} from './calendar/index.js';
|
|
87
88
|
export type { CalendarViewType, EventType } from './calendar/index.js';
|
|
88
|
-
export {
|
|
89
|
-
export type {
|
|
90
|
-
export { FlowDesigner, FlowDesignerNode } from './flow-designer/index.js';
|
|
91
|
-
export type {
|
|
92
|
-
Workflow,
|
|
93
|
-
WorkflowNode,
|
|
94
|
-
WorkflowCommand,
|
|
95
|
-
PositionedNode,
|
|
96
|
-
ValidationError,
|
|
97
|
-
HistoryEntry,
|
|
98
|
-
EditorState,
|
|
99
|
-
NodeType,
|
|
100
|
-
WorkflowChangeEvent,
|
|
101
|
-
SwimlaneConfig,
|
|
102
|
-
NodeTemplate,
|
|
103
|
-
} from './flow-designer/index.js';
|
|
89
|
+
export { Flow } from './flow/index.js';
|
|
90
|
+
export type { FlowNode, FlowEdge, FlowStrokeVariant } from './flow/index.js';
|
|
104
91
|
export {
|
|
105
92
|
ConditionBuilder,
|
|
106
93
|
CbPredicate,
|
package/src/loader.ts
CHANGED
|
@@ -34,6 +34,8 @@ import { SubMenu } from '@/menu/sub-menu/sub-menu.js';
|
|
|
34
34
|
import { Item } from '@/item/item.js';
|
|
35
35
|
import { List } from '@/list/list.js';
|
|
36
36
|
import { ListItem } from '@/list/list-item.js';
|
|
37
|
+
import { Timeline } from '@/timeline/timeline.js';
|
|
38
|
+
import { TimelineItem } from '@/timeline/timeline-item.js';
|
|
37
39
|
|
|
38
40
|
import { Accordion } from '@/accordion/accordion.js';
|
|
39
41
|
import { Link } from '@/link/link.js';
|
|
@@ -305,6 +307,12 @@ const loaderConfig: LoaderConfig = {
|
|
|
305
307
|
'wc-list-item': {
|
|
306
308
|
CustomElementClass: ListItem,
|
|
307
309
|
},
|
|
310
|
+
'wc-timeline': {
|
|
311
|
+
CustomElementClass: Timeline,
|
|
312
|
+
},
|
|
313
|
+
'wc-timeline-item': {
|
|
314
|
+
CustomElementClass: TimelineItem,
|
|
315
|
+
},
|
|
308
316
|
'wc-item': {
|
|
309
317
|
CustomElementClass: Item,
|
|
310
318
|
},
|
|
@@ -381,15 +389,8 @@ const loaderConfig: LoaderConfig = {
|
|
|
381
389
|
'wc-calendar-month-view': {
|
|
382
390
|
importPath: `${distDirectory}/calendar-month-view.js`,
|
|
383
391
|
},
|
|
384
|
-
'wc-
|
|
385
|
-
importPath: `${distDirectory}/
|
|
386
|
-
},
|
|
387
|
-
'wc-flow-designer': {
|
|
388
|
-
importPath: `${distDirectory}/flow-designer.js`,
|
|
389
|
-
dependencies: ['wc-flow-designer-node'],
|
|
390
|
-
},
|
|
391
|
-
'wc-flow-designer-node': {
|
|
392
|
-
importPath: `${distDirectory}/flow-designer-node.js`,
|
|
392
|
+
'wc-flow': {
|
|
393
|
+
importPath: `${distDirectory}/flow.js`,
|
|
393
394
|
},
|
|
394
395
|
'wc-chart-doughnut': {
|
|
395
396
|
importPath: `${distDirectory}/chart-doughnut.js`,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const sourceDir = '../components/dist';
|
|
5
|
+
const destDir = './public/assets/peacock';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Clears the destination directory
|
|
9
|
+
*/
|
|
10
|
+
function clearDirectory(directory) {
|
|
11
|
+
if (fs.existsSync(directory)) {
|
|
12
|
+
// recursive: true deletes subdirectories
|
|
13
|
+
// force: true ignores errors if the path doesn't exist
|
|
14
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
15
|
+
console.log(`Cleared directory: ${directory}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function copyFolderRecursiveSync(source, destination) {
|
|
20
|
+
if (!fs.existsSync(destination)) {
|
|
21
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const files = fs.readdirSync(source);
|
|
25
|
+
|
|
26
|
+
files.forEach(file => {
|
|
27
|
+
const srcPath = path.join(source, file);
|
|
28
|
+
const destPath = path.join(destination, file);
|
|
29
|
+
const stat = fs.statSync(srcPath);
|
|
30
|
+
|
|
31
|
+
if (stat.isDirectory()) {
|
|
32
|
+
copyFolderRecursiveSync(srcPath, destPath);
|
|
33
|
+
} else {
|
|
34
|
+
fs.copyFileSync(srcPath, destPath);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
console.log(`Copied: ${source} -> ${destination}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// --- Execution ---
|
|
42
|
+
|
|
43
|
+
// 1. Clean the destination
|
|
44
|
+
clearDirectory(destDir);
|
|
45
|
+
|
|
46
|
+
// 2. Perform the copy
|
|
47
|
+
copyFolderRecursiveSync(sourceDir, destDir);
|
package/src/menu/menu/menu.scss
CHANGED
|
@@ -53,18 +53,66 @@
|
|
|
53
53
|
z-index: 1;
|
|
54
54
|
width: 100%;
|
|
55
55
|
|
|
56
|
-
::slotted(
|
|
57
|
-
--menu-item-container-shape-start-start: var(
|
|
58
|
-
|
|
56
|
+
::slotted([data-position-after-divider]) {
|
|
57
|
+
--menu-item-backdrop-container-shape-start-start: var(
|
|
58
|
+
--shape-corner-small
|
|
59
|
+
);
|
|
60
|
+
--menu-item-backdrop-container-shape-start-end: var(--shape-corner-small);
|
|
61
|
+
--sub-menu-item-backdrop-container-shape-start-start: var(
|
|
62
|
+
--shape-corner-small
|
|
63
|
+
);
|
|
64
|
+
--sub-menu-item-backdrop-container-shape-start-end: var(
|
|
65
|
+
--shape-corner-small
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
--menu-item-backdrop-elevation-level-block-start: 1;
|
|
59
69
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
--menu-item-container-shape-
|
|
70
|
+
|
|
71
|
+
::slotted([data-position-first]) {
|
|
72
|
+
--menu-item-backdrop-container-shape-start-start: var(
|
|
73
|
+
--shape-corner-large
|
|
74
|
+
);
|
|
75
|
+
--menu-item-backdrop-container-shape-start-end: var(--shape-corner-large);
|
|
76
|
+
--sub-menu-item-backdrop-container-shape-start-start: var(
|
|
77
|
+
--shape-corner-large
|
|
78
|
+
);
|
|
79
|
+
--sub-menu-item-backdrop-container-shape-start-end: var(
|
|
80
|
+
--shape-corner-large
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
--menu-item-backdrop-elevation-level-block-start: 1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
::slotted([data-position-before-divider]) {
|
|
87
|
+
--menu-item-backdrop-elevation-level-block-end: 1;
|
|
88
|
+
--menu-item-backdrop-container-shape-end-start: var(--shape-corner-small);
|
|
89
|
+
|
|
90
|
+
--menu-item-backdrop-container-shape-end-end: var(--shape-corner-small);
|
|
91
|
+
--sub-menu-item-backdrop-container-shape-end-start: var(
|
|
92
|
+
--shape-corner-small
|
|
93
|
+
);
|
|
94
|
+
--sub-menu-item-backdrop-container-shape-end-end: var(
|
|
95
|
+
--shape-corner-small
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
::slotted([data-position-last]) {
|
|
100
|
+
--menu-item-backdrop-elevation-level-block-end: 1;
|
|
101
|
+
--menu-item-backdrop-container-shape-end-start: var(--shape-corner-large);
|
|
102
|
+
|
|
103
|
+
--menu-item-backdrop-container-shape-end-end: var(--shape-corner-large);
|
|
104
|
+
--sub-menu-item-backdrop-container-shape-end-start: var(
|
|
105
|
+
--shape-corner-large
|
|
106
|
+
);
|
|
107
|
+
--sub-menu-item-backdrop-container-shape-end-end: var(
|
|
108
|
+
--shape-corner-large
|
|
109
|
+
);
|
|
63
110
|
}
|
|
64
111
|
|
|
65
112
|
::slotted(wc-divider) {
|
|
66
|
-
--divider-spacing:
|
|
113
|
+
--divider-spacing: 1px;
|
|
67
114
|
padding-inline: var(--spacing-050);
|
|
115
|
+
--divider-color: transparent;
|
|
68
116
|
}
|
|
69
117
|
}
|
|
70
118
|
|
|
@@ -73,8 +121,6 @@
|
|
|
73
121
|
position: absolute;
|
|
74
122
|
inset: 0;
|
|
75
123
|
|
|
76
|
-
border: 1px solid var(--color-red);
|
|
77
|
-
|
|
78
124
|
border-start-start-radius: var(--_container-shape-start-start);
|
|
79
125
|
border-start-end-radius: var(--_container-shape-start-end);
|
|
80
126
|
border-end-start-radius: var(--_container-shape-end-start);
|
|
@@ -95,12 +141,4 @@
|
|
|
95
141
|
--_container-shape-start-end: var(--shape-corner-large);
|
|
96
142
|
--_container-shape-end-start: var(--shape-corner-large);
|
|
97
143
|
--_container-shape-end-end: var(--shape-corner-large);
|
|
98
|
-
|
|
99
|
-
&.variant-standard {
|
|
100
|
-
--menu-item-container-color: var(--color-surface-container);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
&.variant-vibrant {
|
|
104
|
-
--menu-item-container-color: var(--color-tertiary-container);
|
|
105
|
-
}
|
|
106
144
|
}
|
package/src/menu/menu/menu.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { property, query, state } from
|
|
3
|
-
import { classMap } from
|
|
4
|
-
import type { Placement } from
|
|
5
|
-
import styles from
|
|
6
|
-
import { FloatingController } from
|
|
7
|
-
import { MenuItem } from
|
|
8
|
-
import IndividualComponent from
|
|
1
|
+
import { html, LitElement } from "lit";
|
|
2
|
+
import { property, query, state } from "lit/decorators.js";
|
|
3
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
4
|
+
import type { Placement } from "@floating-ui/dom";
|
|
5
|
+
import styles from "./menu.scss";
|
|
6
|
+
import { FloatingController } from "../../__internal/controllers/floating-controller.js";
|
|
7
|
+
import { MenuItem } from "../menu-item/menu-item.js";
|
|
8
|
+
import IndividualComponent from "@/IndividualComponent.js";
|
|
9
9
|
|
|
10
10
|
type CloseReason =
|
|
11
|
-
| { kind:
|
|
12
|
-
| { kind:
|
|
13
|
-
| { kind:
|
|
14
|
-
| { kind:
|
|
15
|
-
| { kind:
|
|
11
|
+
| { kind: "click-selection" }
|
|
12
|
+
| { kind: "keydown"; key: string }
|
|
13
|
+
| { kind: "outside-click" }
|
|
14
|
+
| { kind: "focusout" }
|
|
15
|
+
| { kind: "programmatic" };
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @label Menu
|
|
@@ -36,54 +36,62 @@ export class Menu extends LitElement {
|
|
|
36
36
|
static Item = MenuItem;
|
|
37
37
|
|
|
38
38
|
/** Whether the menu is currently visible. */
|
|
39
|
-
@property({ type: Boolean, reflect: true })
|
|
39
|
+
@property({ type: Boolean, reflect: true })
|
|
40
|
+
open = false;
|
|
40
41
|
|
|
41
42
|
/** Visual variant of the menu. `"vibrant"` applies stronger color emphasis. */
|
|
42
|
-
@property({ type: String, reflect: true })
|
|
43
|
-
|
|
43
|
+
@property({ type: String, reflect: true })
|
|
44
|
+
variant: "standard" | "vibrant" = "standard";
|
|
44
45
|
|
|
45
46
|
/** ID of the anchor element the menu is positioned relative to. */
|
|
46
|
-
@property({ type: String })
|
|
47
|
+
@property({ type: String })
|
|
48
|
+
anchor = "";
|
|
47
49
|
|
|
48
50
|
/** When true, renders the menu in a static preview state (always visible, no animation). */
|
|
49
|
-
@property({ type: Boolean, reflect: true })
|
|
51
|
+
@property({ type: Boolean, reflect: true })
|
|
52
|
+
preview = false;
|
|
50
53
|
|
|
51
54
|
/** When true, the menu will not close when a click occurs outside it. */
|
|
52
|
-
@property({ type: Boolean, attribute:
|
|
55
|
+
@property({ type: Boolean, attribute: "stay-open-on-outside-click" })
|
|
53
56
|
stayOpenOnOutsideClick = false;
|
|
54
57
|
|
|
55
58
|
/** When true, the menu will not close when focus leaves it. */
|
|
56
|
-
@property({ type: Boolean, attribute:
|
|
59
|
+
@property({ type: Boolean, attribute: "stay-open-on-focusout" })
|
|
57
60
|
stayOpenOnFocusout = false;
|
|
58
61
|
|
|
59
62
|
/** Set to true when this menu is being used as a submenu inside another menu. */
|
|
60
|
-
@property({ type: Boolean, attribute:
|
|
63
|
+
@property({ type: Boolean, attribute: "is-submenu" })
|
|
64
|
+
isSubmenu = false;
|
|
61
65
|
|
|
62
66
|
/** Floating UI placement of the menu relative to its anchor. */
|
|
63
|
-
@property({ type: String })
|
|
67
|
+
@property({ type: String })
|
|
68
|
+
placement: Placement = "bottom-start";
|
|
64
69
|
|
|
65
70
|
/** Distance in pixels between the menu and its anchor element. */
|
|
66
|
-
@property({ type: Number })
|
|
71
|
+
@property({ type: Number })
|
|
72
|
+
offset = 6;
|
|
67
73
|
|
|
68
74
|
/** Index of the currently focused/active item within the enabled items list. */
|
|
69
|
-
@state()
|
|
75
|
+
@state()
|
|
76
|
+
private activeIndex = -1;
|
|
70
77
|
|
|
71
|
-
@query(
|
|
78
|
+
@query(".menu")
|
|
79
|
+
private readonly menuListElement!: HTMLElement;
|
|
72
80
|
|
|
73
81
|
/** Direct reference to the anchor element; takes precedence over the `anchor` ID property. */
|
|
74
82
|
anchorElement: HTMLElement | null = null;
|
|
75
83
|
|
|
76
84
|
/** Controller managing floating-UI positioning. */
|
|
77
85
|
private readonly _floatingController = new FloatingController(this, {
|
|
78
|
-
trigger:
|
|
86
|
+
trigger: "manual",
|
|
79
87
|
closeOnClickOutside: false,
|
|
80
|
-
strategy:
|
|
81
|
-
onOpenChange: isOpen => {
|
|
88
|
+
strategy: "fixed",
|
|
89
|
+
onOpenChange: (isOpen) => {
|
|
82
90
|
if (isOpen || !this.open) {
|
|
83
91
|
return;
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
this.close({ kind:
|
|
94
|
+
this.close({ kind: "outside-click" });
|
|
87
95
|
},
|
|
88
96
|
});
|
|
89
97
|
|
|
@@ -91,27 +99,27 @@ export class Menu extends LitElement {
|
|
|
91
99
|
private _lastFocusedElement: HTMLElement | null = null;
|
|
92
100
|
|
|
93
101
|
/** Reason that triggered the most recent close, included in the `closed` event detail. */
|
|
94
|
-
private _closeReason: CloseReason = { kind:
|
|
102
|
+
private _closeReason: CloseReason = { kind: "programmatic" };
|
|
95
103
|
|
|
96
104
|
connectedCallback() {
|
|
97
105
|
// eslint-disable-next-line wc/guard-super-call
|
|
98
106
|
super.connectedCallback();
|
|
99
|
-
this.setAttribute(
|
|
107
|
+
this.setAttribute("role", "menu");
|
|
100
108
|
|
|
101
|
-
this.addEventListener(
|
|
102
|
-
this.addEventListener(
|
|
109
|
+
this.addEventListener("keydown", this._onKeyDown);
|
|
110
|
+
this.addEventListener("click", this._onClick);
|
|
103
111
|
this._syncAnchorAria();
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
disconnectedCallback() {
|
|
107
|
-
this.removeEventListener(
|
|
108
|
-
this.removeEventListener(
|
|
115
|
+
this.removeEventListener("keydown", this._onKeyDown);
|
|
116
|
+
this.removeEventListener("click", this._onClick);
|
|
109
117
|
this._floatingController.close();
|
|
110
118
|
super.disconnectedCallback();
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
get items(): MenuItem[] {
|
|
114
|
-
const slot = this.shadowRoot?.querySelector(
|
|
122
|
+
const slot = this.shadowRoot?.querySelector("slot");
|
|
115
123
|
const elements = slot?.assignedElements({ flatten: true }) ?? [];
|
|
116
124
|
const items: MenuItem[] = [];
|
|
117
125
|
|
|
@@ -134,11 +142,11 @@ export class Menu extends LitElement {
|
|
|
134
142
|
return;
|
|
135
143
|
}
|
|
136
144
|
|
|
137
|
-
this._closeReason = { kind:
|
|
145
|
+
this._closeReason = { kind: "programmatic" };
|
|
138
146
|
this.open = true;
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
close(reason: CloseReason = { kind:
|
|
149
|
+
close(reason: CloseReason = { kind: "programmatic" }) {
|
|
142
150
|
if (!this.open) {
|
|
143
151
|
return;
|
|
144
152
|
}
|
|
@@ -162,7 +170,7 @@ export class Menu extends LitElement {
|
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
const root = this.getRootNode() as Document | ShadowRoot;
|
|
165
|
-
if (
|
|
173
|
+
if ("getElementById" in root) {
|
|
166
174
|
return root.getElementById(this.anchor);
|
|
167
175
|
}
|
|
168
176
|
|
|
@@ -179,13 +187,13 @@ export class Menu extends LitElement {
|
|
|
179
187
|
this.id = `wc-menu-${Math.random().toString(36).slice(2, 9)}`;
|
|
180
188
|
}
|
|
181
189
|
|
|
182
|
-
anchorEl.setAttribute(
|
|
183
|
-
anchorEl.setAttribute(
|
|
184
|
-
anchorEl.setAttribute(
|
|
190
|
+
anchorEl.setAttribute("aria-haspopup", "menu");
|
|
191
|
+
anchorEl.setAttribute("aria-controls", this.id);
|
|
192
|
+
anchorEl.setAttribute("aria-expanded", String(this.open));
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
private _enabledItems() {
|
|
188
|
-
return this.items.filter(item => !item.disabled);
|
|
196
|
+
return this.items.filter((item) => !item.disabled);
|
|
189
197
|
}
|
|
190
198
|
|
|
191
199
|
private _syncRovingTabIndex() {
|
|
@@ -250,7 +258,7 @@ export class Menu extends LitElement {
|
|
|
250
258
|
|
|
251
259
|
private _isEventFromThisMenu(event: Event) {
|
|
252
260
|
const path = event.composedPath();
|
|
253
|
-
const sourceMenu = path.find(target => target instanceof Menu);
|
|
261
|
+
const sourceMenu = path.find((target) => target instanceof Menu);
|
|
254
262
|
|
|
255
263
|
return sourceMenu === this;
|
|
256
264
|
}
|
|
@@ -265,7 +273,7 @@ export class Menu extends LitElement {
|
|
|
265
273
|
|
|
266
274
|
for (const target of path) {
|
|
267
275
|
if (target instanceof MenuItem) {
|
|
268
|
-
const ownedItem = ownedItems.find(item => item === target);
|
|
276
|
+
const ownedItem = ownedItems.find((item) => item === target);
|
|
269
277
|
if (ownedItem) {
|
|
270
278
|
return ownedItem;
|
|
271
279
|
}
|
|
@@ -288,7 +296,7 @@ export class Menu extends LitElement {
|
|
|
288
296
|
|
|
289
297
|
private _dispatchItemActivate(item: MenuItem) {
|
|
290
298
|
this.dispatchEvent(
|
|
291
|
-
new CustomEvent(
|
|
299
|
+
new CustomEvent("menu-item-activate", {
|
|
292
300
|
bubbles: true,
|
|
293
301
|
composed: true,
|
|
294
302
|
detail: { item },
|
|
@@ -312,7 +320,7 @@ export class Menu extends LitElement {
|
|
|
312
320
|
return;
|
|
313
321
|
}
|
|
314
322
|
|
|
315
|
-
this.close({ kind:
|
|
323
|
+
this.close({ kind: "click-selection" });
|
|
316
324
|
};
|
|
317
325
|
|
|
318
326
|
private _onKeyDown = (event: KeyboardEvent) => {
|
|
@@ -330,33 +338,33 @@ export class Menu extends LitElement {
|
|
|
330
338
|
}
|
|
331
339
|
|
|
332
340
|
switch (event.key) {
|
|
333
|
-
case
|
|
341
|
+
case "ArrowDown":
|
|
334
342
|
event.preventDefault();
|
|
335
343
|
this._setActiveByOffset(1);
|
|
336
344
|
break;
|
|
337
|
-
case
|
|
345
|
+
case "ArrowUp":
|
|
338
346
|
event.preventDefault();
|
|
339
347
|
this._setActiveByOffset(-1);
|
|
340
348
|
break;
|
|
341
|
-
case
|
|
349
|
+
case "Home":
|
|
342
350
|
event.preventDefault();
|
|
343
351
|
this._setBoundaryActive(0);
|
|
344
352
|
break;
|
|
345
|
-
case
|
|
353
|
+
case "End": {
|
|
346
354
|
event.preventDefault();
|
|
347
355
|
const last = Math.max(this._enabledItems().length - 1, 0);
|
|
348
356
|
this._setBoundaryActive(last);
|
|
349
357
|
break;
|
|
350
358
|
}
|
|
351
|
-
case
|
|
359
|
+
case "Escape":
|
|
352
360
|
event.preventDefault();
|
|
353
|
-
this.close({ kind:
|
|
361
|
+
this.close({ kind: "keydown", key: "Escape" });
|
|
354
362
|
break;
|
|
355
|
-
case
|
|
356
|
-
this.close({ kind:
|
|
363
|
+
case "Tab":
|
|
364
|
+
this.close({ kind: "keydown", key: "Tab" });
|
|
357
365
|
break;
|
|
358
|
-
case
|
|
359
|
-
case
|
|
366
|
+
case "Enter":
|
|
367
|
+
case " ": {
|
|
360
368
|
event.preventDefault();
|
|
361
369
|
const activeItem = this._getActiveItem() ?? this._getFirstEnabledItem();
|
|
362
370
|
if (!activeItem) {
|
|
@@ -374,8 +382,68 @@ export class Menu extends LitElement {
|
|
|
374
382
|
|
|
375
383
|
private _onSlotChange = () => {
|
|
376
384
|
this._syncRovingTabIndex();
|
|
385
|
+
this._syncItemPositions();
|
|
377
386
|
};
|
|
378
387
|
|
|
388
|
+
private _syncItemPositions() {
|
|
389
|
+
const slot = this.shadowRoot?.querySelector("slot");
|
|
390
|
+
const elements = slot?.assignedElements({ flatten: true }) ?? [];
|
|
391
|
+
|
|
392
|
+
for (const el of elements) {
|
|
393
|
+
if (el instanceof HTMLElement) {
|
|
394
|
+
el.removeAttribute("data-position-first");
|
|
395
|
+
el.removeAttribute("data-position-last");
|
|
396
|
+
el.removeAttribute("data-position-after-divider");
|
|
397
|
+
el.removeAttribute("data-position-before-divider");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const items = elements.filter(
|
|
402
|
+
(el) => el.tagName.toLowerCase() !== "wc-divider"
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
if (items.length === 0) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const firstItem = items[0];
|
|
410
|
+
if (firstItem instanceof HTMLElement) {
|
|
411
|
+
firstItem.setAttribute("data-position-first", "");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const lastItem = items[items.length - 1];
|
|
415
|
+
if (lastItem instanceof HTMLElement) {
|
|
416
|
+
lastItem.setAttribute("data-position-last", "");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
for (let i = 0; i < elements.length; i++) {
|
|
420
|
+
const el = elements[i];
|
|
421
|
+
if (el.tagName.toLowerCase() === "wc-divider") {
|
|
422
|
+
let prevItem: Element | null = null;
|
|
423
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
424
|
+
if (elements[j].tagName.toLowerCase() !== "wc-divider") {
|
|
425
|
+
prevItem = elements[j];
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (prevItem instanceof HTMLElement) {
|
|
430
|
+
prevItem.setAttribute("data-position-before-divider", "");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let nextItem: Element | null = null;
|
|
434
|
+
for (let j = i + 1; j < elements.length; j++) {
|
|
435
|
+
if (elements[j].tagName.toLowerCase() !== "wc-divider") {
|
|
436
|
+
nextItem = elements[j];
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (nextItem instanceof HTMLElement) {
|
|
441
|
+
nextItem.setAttribute("data-position-after-divider", "");
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
379
447
|
private _applyPositioning() {
|
|
380
448
|
if (!this.open || !this.menuListElement) {
|
|
381
449
|
return;
|
|
@@ -389,7 +457,7 @@ export class Menu extends LitElement {
|
|
|
389
457
|
this._floatingController.setOptions({
|
|
390
458
|
placement: this.placement,
|
|
391
459
|
offset: this.offset,
|
|
392
|
-
strategy:
|
|
460
|
+
strategy: "fixed",
|
|
393
461
|
closeOnClickOutside: !this.stayOpenOnOutsideClick,
|
|
394
462
|
});
|
|
395
463
|
this._floatingController.setElements(anchorEl, this.menuListElement);
|
|
@@ -397,16 +465,17 @@ export class Menu extends LitElement {
|
|
|
397
465
|
}
|
|
398
466
|
|
|
399
467
|
protected override updated(changedProperties: Map<string, unknown>) {
|
|
400
|
-
if (changedProperties.has(
|
|
468
|
+
if (changedProperties.has("anchor") || changedProperties.has("open")) {
|
|
401
469
|
this._syncAnchorAria();
|
|
402
470
|
}
|
|
403
471
|
|
|
404
|
-
if (changedProperties.has(
|
|
472
|
+
if (changedProperties.has("open")) {
|
|
405
473
|
if (this.open) {
|
|
406
474
|
this._lastFocusedElement = document.activeElement as HTMLElement | null;
|
|
407
475
|
this._syncRovingTabIndex();
|
|
476
|
+
this._syncItemPositions();
|
|
408
477
|
this.dispatchEvent(
|
|
409
|
-
new CustomEvent(
|
|
478
|
+
new CustomEvent("opened", {
|
|
410
479
|
bubbles: true,
|
|
411
480
|
composed: true,
|
|
412
481
|
}),
|
|
@@ -418,7 +487,7 @@ export class Menu extends LitElement {
|
|
|
418
487
|
|
|
419
488
|
const reason = this._closeReason;
|
|
420
489
|
this.dispatchEvent(
|
|
421
|
-
new CustomEvent(
|
|
490
|
+
new CustomEvent("close-menu", {
|
|
422
491
|
bubbles: true,
|
|
423
492
|
composed: true,
|
|
424
493
|
detail: {
|
|
@@ -428,15 +497,15 @@ export class Menu extends LitElement {
|
|
|
428
497
|
}),
|
|
429
498
|
);
|
|
430
499
|
this.dispatchEvent(
|
|
431
|
-
new CustomEvent(
|
|
500
|
+
new CustomEvent("closed", {
|
|
432
501
|
bubbles: true,
|
|
433
502
|
composed: true,
|
|
434
503
|
detail: { reason },
|
|
435
504
|
}),
|
|
436
505
|
);
|
|
437
506
|
|
|
438
|
-
const shouldRestoreFocus =
|
|
439
|
-
reason.
|
|
507
|
+
const shouldRestoreFocus = reason.kind !== "keydown" ||
|
|
508
|
+
reason.key !== "Tab";
|
|
440
509
|
|
|
441
510
|
if (!this.isSubmenu && shouldRestoreFocus) {
|
|
442
511
|
this._lastFocusedElement?.focus();
|
|
@@ -445,10 +514,10 @@ export class Menu extends LitElement {
|
|
|
445
514
|
}
|
|
446
515
|
|
|
447
516
|
if (
|
|
448
|
-
(changedProperties.has(
|
|
449
|
-
changedProperties.has(
|
|
450
|
-
changedProperties.has(
|
|
451
|
-
changedProperties.has(
|
|
517
|
+
(changedProperties.has("open") ||
|
|
518
|
+
changedProperties.has("anchor") ||
|
|
519
|
+
changedProperties.has("placement") ||
|
|
520
|
+
changedProperties.has("offset")) &&
|
|
452
521
|
this.open
|
|
453
522
|
) {
|
|
454
523
|
this._applyPositioning();
|
|
@@ -456,21 +525,23 @@ export class Menu extends LitElement {
|
|
|
456
525
|
}
|
|
457
526
|
|
|
458
527
|
render() {
|
|
459
|
-
return html
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
<
|
|
528
|
+
return html`
|
|
529
|
+
<div
|
|
530
|
+
class="${classMap({
|
|
531
|
+
menu: true,
|
|
532
|
+
open: !this.preview && this.open,
|
|
533
|
+
closed: !this.preview && !this.open,
|
|
534
|
+
preview: this.preview,
|
|
535
|
+
[`variant-${this.variant}`]: true,
|
|
536
|
+
})}"
|
|
537
|
+
aria-hidden="${String(!this.open)}"
|
|
538
|
+
>
|
|
539
|
+
<div class="background"></div>
|
|
540
|
+
|
|
541
|
+
<div class="menu-content">
|
|
542
|
+
<slot @slotchange="${this._onSlotChange}"></slot>
|
|
543
|
+
</div>
|
|
473
544
|
</div>
|
|
474
|
-
|
|
545
|
+
`;
|
|
475
546
|
}
|
|
476
547
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
@use
|
|
1
|
+
@use '../../../scss/mixin';
|
|
2
2
|
|
|
3
|
-
:host-context([variant=standard]) {
|
|
3
|
+
:host-context([variant='standard']) {
|
|
4
4
|
--menu-item-label-color: var(--color-on-surface-variant);
|
|
5
5
|
--menu-item-label-selected-color: var(--color-on-tertiary-container);
|
|
6
6
|
--menu-item-container-selected-color: var(--color-tertiary-container);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
:host-context([variant=vibrant]) {
|
|
9
|
+
:host-context([variant='vibrant']) {
|
|
10
10
|
--menu-item-label-color: var(--color-on-tertiary-container);
|
|
11
11
|
--menu-item-label-selected-color: var(--color-on-tertiary);
|
|
12
12
|
--menu-item-container-selected-color: var(--color-tertiary);
|