@m3e/fab-menu 1.0.0-rc.1 → 1.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/custom-elements.json +2882 -14
- package/dist/html-custom-data.json +10 -4
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +13 -11
- package/dist/index.min.js.map +1 -1
- package/dist/src/FabMenuElement.d.ts +3 -2
- package/dist/src/FabMenuElement.d.ts.map +1 -1
- package/dist/src/FabMenuItemElement.d.ts +2 -0
- package/dist/src/FabMenuItemElement.d.ts.map +1 -1
- package/dist/src/FabMenuTriggerElement.d.ts +1 -1
- package/dist/src/FabMenuTriggerElement.d.ts.map +1 -1
- package/package.json +4 -4
- package/cem.config.mjs +0 -16
- package/demo/index.html +0 -60
- package/eslint.config.mjs +0 -13
- package/rollup.config.js +0 -32
- package/src/FabMenuElement.ts +0 -391
- package/src/FabMenuItemElement.ts +0 -253
- package/src/FabMenuTriggerElement.ts +0 -108
- package/src/FabMenuVariant.ts +0 -2
- package/src/index.ts +0 -4
- package/tsconfig.json +0 -9
|
@@ -33,6 +33,8 @@ declare const M3eFabMenuItemElement_base: import("node_modules/@m3e/core/dist/sr
|
|
|
33
33
|
* @attr rel - The relationship between the `target` of the link button and the document.
|
|
34
34
|
* @attr target - The target of the link button.
|
|
35
35
|
*
|
|
36
|
+
* @fires click - Emitted when the element is clicked.
|
|
37
|
+
*
|
|
36
38
|
* @cssprop --m3e-fab-menu-item-height - Height of the menu item.
|
|
37
39
|
* @cssprop --m3e-fab-menu-item-font-size - Font size of the menu item label.
|
|
38
40
|
* @cssprop --m3e-fab-menu-item-font-weight - Font weight of the menu item label.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FabMenuItemElement.d.ts","sourceRoot":"","sources":["../../src/FabMenuItemElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAQ,UAAU,EAAE,cAAc,EAAa,MAAM,KAAK,CAAC;AAiBvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;;AAE1D
|
|
1
|
+
{"version":3,"file":"FabMenuItemElement.d.ts","sourceRoot":"","sources":["../../src/FabMenuItemElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAQ,UAAU,EAAE,cAAc,EAAa,MAAM,KAAK,CAAC;AAiBvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qBACa,qBAAsB,SAAQ,0BAE1C;;IACC,iCAAiC;IACjC,OAAgB,MAAM,EAAE,cAAc,CA6HpC;IAEF,eAAe,CAAsB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAsB;IACvF,eAAe,CAAuB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAsB;IACxF,eAAe,CAAwB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAuB;IAC3F,eAAe,CAAmB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAmB;IAI9E,wEAAwE;IACxE,IAAI,IAAI,IAAI,iBAAiB,GAAG,IAAI,CAEnC;IAED,kBAAkB;IACT,iBAAiB,IAAI,IAAI;IAKlC,kBAAkB;IACT,oBAAoB,IAAI,IAAI;IAKrC,kBAAkB;cACC,YAAY,CAAC,kBAAkB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAK/E,kBAAkB;IACT,MAAM,IAAI,OAAO;CAqB3B;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,qBAAqB,CAAC;KAC5C;CACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CSSResultGroup, LitElement } from "lit";
|
|
2
2
|
import { M3eFabMenuElement } from "./FabMenuElement";
|
|
3
|
-
declare const M3eFabMenuTriggerElement_base: import("node_modules/@m3e/core/dist/src/shared/mixins/Constructor").Constructor<import("@m3e/core").HtmlForMixin> &
|
|
3
|
+
declare const M3eFabMenuTriggerElement_base: import("node_modules/@m3e/core/dist/src/shared/mixins/Constructor").Constructor<import("@m3e/core").HtmlForMixin> & typeof LitElement;
|
|
4
4
|
/**
|
|
5
5
|
* An element, nested within a clickable element, used to open a floating action button (FAB) menu.
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FabMenuTriggerElement.d.ts","sourceRoot":"","sources":["../../src/FabMenuTriggerElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAQ,UAAU,EAAE,MAAM,KAAK,CAAC;AAM5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,wBAAyB,SAAQ,
|
|
1
|
+
{"version":3,"file":"FabMenuTriggerElement.d.ts","sourceRoot":"","sources":["../../src/FabMenuTriggerElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAQ,UAAU,EAAE,MAAM,KAAK,CAAC;AAM5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,wBAAyB,SAAQ,6BAAmB;;IAC/D,iCAAiC;IACjC,OAAgB,MAAM,EAAE,cAAc,CAOpC;IAIF,yCAAyC;IACzC,IAAI,IAAI,IAAI,iBAAiB,GAAG,IAAI,CAEnC;IAED,kBAAkB;IACT,iBAAiB,IAAI,IAAI;IAKlC,kBAAkB;IACT,oBAAoB,IAAI,IAAI;IAKrC,kBAAkB;IACT,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAc3C,kBAAkB;IACT,MAAM,IAAI,IAAI;IAYvB,kBAAkB;cACC,MAAM,IAAI,OAAO;CAUrC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,sBAAsB,EAAE,wBAAwB,CAAC;KAClD;CACF"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m3e/fab-menu",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
4
|
"description": "FAB Menu for M3E",
|
|
5
5
|
"author": "matraic <matraic@yahoo.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"homepage": "https://matraic.github.io/m3e/",
|
|
7
|
+
"homepage": "https://matraic.github.io/m3e/#/components/fab-menu.html",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/matraic/m3e.git"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"clean": "rimraf dist"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@m3e/core": "1.0.0-rc.
|
|
31
|
-
"@m3e/fab": "1.0.0-rc.
|
|
30
|
+
"@m3e/core": "1.0.0-rc.3",
|
|
31
|
+
"@m3e/fab": "1.0.0-rc.3",
|
|
32
32
|
"lit": "^3.3.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
package/cem.config.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { customElementVsCodePlugin } from "custom-element-vs-code-integration";
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
globs: ["src/**/*.ts"],
|
|
5
|
-
exclude: ["src/**/*.spec.ts"],
|
|
6
|
-
packagejson: true,
|
|
7
|
-
outdir: "dist",
|
|
8
|
-
litelement: true,
|
|
9
|
-
plugins: [
|
|
10
|
-
customElementVsCodePlugin({
|
|
11
|
-
outdir: "dist",
|
|
12
|
-
htmlFileName: "html-custom-data.json",
|
|
13
|
-
cssFileName: "css-custom-data.json",
|
|
14
|
-
}),
|
|
15
|
-
],
|
|
16
|
-
};
|
package/demo/index.html
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en" style="overflow-y: auto">
|
|
3
|
-
<head>
|
|
4
|
-
<title>Floating Action Button Menu for M3E</title>
|
|
5
|
-
<meta charset="utf-8" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
-
<meta name="description" content="Floating Action Button Menu for M3E" />
|
|
8
|
-
<base href="./" />
|
|
9
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
10
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
|
-
<link
|
|
12
|
-
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap"
|
|
13
|
-
rel="stylesheet"
|
|
14
|
-
/>
|
|
15
|
-
<link
|
|
16
|
-
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0"
|
|
17
|
-
rel="stylesheet"
|
|
18
|
-
/>
|
|
19
|
-
<script type="importmap">
|
|
20
|
-
{
|
|
21
|
-
"imports": {
|
|
22
|
-
"lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
|
|
23
|
-
"@m3e/core": "../../core/dist/index.min.js",
|
|
24
|
-
"@m3e/core/a11y": "../../core/dist/a11y.min.js",
|
|
25
|
-
"@m3e/core/bidi": "../../core/dist/bidi.min.js",
|
|
26
|
-
"@m3e/core/anchoring": "../../core/dist/anchoring.min.js"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
</script>
|
|
30
|
-
<script type="module" src="../../icon/dist/index.min.js"></script>
|
|
31
|
-
<script type="module" src="../../fab/dist/index.min.js"></script>
|
|
32
|
-
<script type="module" src="../../theme/dist/index.min.js"></script>
|
|
33
|
-
<script type="module" src="../dist/index.min.js"></script>
|
|
34
|
-
<style>
|
|
35
|
-
body {
|
|
36
|
-
font-family: "Roboto";
|
|
37
|
-
}
|
|
38
|
-
*:not(:defined) {
|
|
39
|
-
display: none;
|
|
40
|
-
}
|
|
41
|
-
</style>
|
|
42
|
-
</head>
|
|
43
|
-
<body>
|
|
44
|
-
<m3e-theme strong-focus>
|
|
45
|
-
<m3e-fab variant="primary" size="large" style="position: absolute; right: 1rem; bottom: 1rem">
|
|
46
|
-
<m3e-fab-menu-trigger for="fabmenu">
|
|
47
|
-
<m3e-icon name="edit"></m3e-icon>
|
|
48
|
-
</m3e-fab-menu-trigger>
|
|
49
|
-
</m3e-fab>
|
|
50
|
-
<m3e-fab-menu id="fabmenu" variant="secondary">
|
|
51
|
-
<m3e-fab-menu-item>First</m3e-fab-menu-item>
|
|
52
|
-
<m3e-fab-menu-item disabled>Second</m3e-fab-menu-item>
|
|
53
|
-
<m3e-fab-menu-item>Third</m3e-fab-menu-item>
|
|
54
|
-
<m3e-fab-menu-item>Forth</m3e-fab-menu-item>
|
|
55
|
-
<m3e-fab-menu-item>Fifth</m3e-fab-menu-item>
|
|
56
|
-
<m3e-fab-menu-item>Sixth</m3e-fab-menu-item>
|
|
57
|
-
</m3e-fab-menu>
|
|
58
|
-
</m3e-theme>
|
|
59
|
-
</body>
|
|
60
|
-
</html>
|
package/eslint.config.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import eslint from "@eslint/js";
|
|
2
|
-
import tseslint from "typescript-eslint";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import { dirname } from "path";
|
|
5
|
-
|
|
6
|
-
export default tseslint.config(eslint.configs.recommended, tseslint.configs.recommended, {
|
|
7
|
-
languageOptions: {
|
|
8
|
-
parserOptions: {
|
|
9
|
-
project: true,
|
|
10
|
-
tsconfigRootDir: dirname(fileURLToPath(import.meta.url)),
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
});
|
package/rollup.config.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import resolve from "@rollup/plugin-node-resolve";
|
|
2
|
-
import terser from "@rollup/plugin-terser";
|
|
3
|
-
import typescript from "@rollup/plugin-typescript";
|
|
4
|
-
|
|
5
|
-
const banner = `/**
|
|
6
|
-
* @license MIT
|
|
7
|
-
* Copyright (c) 2025 matraic
|
|
8
|
-
* See LICENSE file in the project root for full license text.
|
|
9
|
-
*/`;
|
|
10
|
-
|
|
11
|
-
export default [
|
|
12
|
-
{
|
|
13
|
-
input: "src/index.ts",
|
|
14
|
-
output: [
|
|
15
|
-
{
|
|
16
|
-
file: "dist/index.js",
|
|
17
|
-
format: "esm",
|
|
18
|
-
sourcemap: true,
|
|
19
|
-
banner: banner,
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
file: "dist/index.min.js",
|
|
23
|
-
format: "esm",
|
|
24
|
-
sourcemap: true,
|
|
25
|
-
banner: banner,
|
|
26
|
-
plugins: [terser({ mangle: true })],
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
external: ["@m3e/core", "@m3e/core/a11y", "@m3e/core/bidi", "@m3e/core/anchoring", "@m3e/fab", "lit"],
|
|
30
|
-
plugins: [resolve(), typescript()],
|
|
31
|
-
},
|
|
32
|
-
];
|
package/src/FabMenuElement.ts
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
|
|
2
|
-
import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit";
|
|
3
|
-
import { customElement, property } from "lit/decorators.js";
|
|
4
|
-
|
|
5
|
-
import { DesignToken, DisabledMixin, Role, ScrollController } from "@m3e/core";
|
|
6
|
-
import { RovingTabIndexManager } from "@m3e/core/a11y";
|
|
7
|
-
import { M3eDirectionality } from "@m3e/core/bidi";
|
|
8
|
-
import { positionAnchor } from "@m3e/core/anchoring";
|
|
9
|
-
|
|
10
|
-
import { M3eFabElement } from "@m3e/fab";
|
|
11
|
-
|
|
12
|
-
import { FabMenuVariant } from "./FabMenuVariant";
|
|
13
|
-
import { M3eFabMenuItemElement } from "./FabMenuItemElement";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @summary
|
|
17
|
-
* A menu, opened from a floating action button (FAB), used to display multiple related actions.
|
|
18
|
-
*
|
|
19
|
-
* @description
|
|
20
|
-
* The `m3e-fab-menu` component presents a dynamic menu of related actions, elegantly revealed from a
|
|
21
|
-
* floating action button (FAB). Designed using expressive, adaptive surfaces, it enables seamless access
|
|
22
|
-
* to contextual actions in modern, visually rich interfaces.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* The following example illustrates triggering a `m3e-fab-menu` from an `m3e-fab` using a `m3e-fab-menu-trigger`.
|
|
26
|
-
* ```html
|
|
27
|
-
* <m3e-fab variant="primary" size="large">
|
|
28
|
-
* <m3e-fab-menu-trigger for="fabmenu">
|
|
29
|
-
* <m3e-icon name="edit"></m3e-icon>
|
|
30
|
-
* </m3e-fab-menu-trigger>
|
|
31
|
-
* </m3e-fab>
|
|
32
|
-
* <m3e-fab-menu id="fabmenu" variant="secondary">
|
|
33
|
-
* <m3e-fab-menu-item>First</m3e-fab-menu-item>
|
|
34
|
-
* <m3e-fab-menu-item>Second</m3e-fab-menu-item>
|
|
35
|
-
* <m3e-fab-menu-item>Third</m3e-fab-menu-item>
|
|
36
|
-
* <m3e-fab-menu-item>Forth</m3e-fab-menu-item>
|
|
37
|
-
* <m3e-fab-menu-item>Fifth</m3e-fab-menu-item>
|
|
38
|
-
* <m3e-fab-menu-item>Sixth</m3e-fab-menu-item>
|
|
39
|
-
* </m3e-fab-menu>
|
|
40
|
-
* ```
|
|
41
|
-
*
|
|
42
|
-
* @tag m3e-fab-menu
|
|
43
|
-
*
|
|
44
|
-
* @slot - Renders the contents of the menu.
|
|
45
|
-
*
|
|
46
|
-
* @attr variant - The appearance variant of the menu.
|
|
47
|
-
*
|
|
48
|
-
* @cssprop --m3e-fab-menu-spacing - Vertical gap between menu items.
|
|
49
|
-
* @cssprop --m3e-fab-menu-max-width - Maximum width of the menu.
|
|
50
|
-
* @cssprop --m3e-primary-fab-color - Foreground color for primary variant items.
|
|
51
|
-
* @cssprop --m3e-primary-fab-container-color - Container color for primary variant items.
|
|
52
|
-
* @cssprop --m3e-primary-fab-hover-color - Hover background color for primary variant items.
|
|
53
|
-
* @cssprop --m3e-primary-fab-focus-color - Focus background color for primary variant items.
|
|
54
|
-
* @cssprop --m3e-primary-fab-ripple-color - Ripple color for primary variant items.
|
|
55
|
-
* @cssprop --m3e-secondary-fab-color - Foreground color for secondary variant items.
|
|
56
|
-
* @cssprop --m3e-secondary-fab-container-color - Container color for secondary variant items.
|
|
57
|
-
* @cssprop --m3e-secondary-fab-hover-color - Hover background color for secondary variant items.
|
|
58
|
-
* @cssprop --m3e-secondary-fab-focus-color - Focus background color for secondary variant items.
|
|
59
|
-
* @cssprop --m3e-secondary-fab-ripple-color - Ripple color for secondary variant items.
|
|
60
|
-
* @cssprop --m3e-tertiary-fab-color - Foreground color for tertiary variant items.
|
|
61
|
-
* @cssprop --m3e-tertiary-fab-container-color - Container color for tertiary variant items.
|
|
62
|
-
* @cssprop --m3e-tertiary-fab-hover-color - Hover background color for tertiary variant items.
|
|
63
|
-
* @cssprop --m3e-tertiary-fab-focus-color - Focus background color for tertiary variant items.
|
|
64
|
-
* @cssprop --m3e-tertiary-fab-ripple-color - Ripple color for tertiary variant items.
|
|
65
|
-
*/
|
|
66
|
-
@customElement("m3e-fab-menu")
|
|
67
|
-
export class M3eFabMenuElement extends Role(LitElement, "menu") {
|
|
68
|
-
/** The styles of the element. */
|
|
69
|
-
static override styles: CSSResultGroup = css`
|
|
70
|
-
:host {
|
|
71
|
-
position: absolute;
|
|
72
|
-
flex-direction: column;
|
|
73
|
-
row-gap: var(--m3e-fab-menu-spacing, 0.25rem);
|
|
74
|
-
padding: unset;
|
|
75
|
-
margin: unset;
|
|
76
|
-
border: unset;
|
|
77
|
-
overflow: visible;
|
|
78
|
-
max-width: var(--m3e-fab-menu-max-width, 17.5rem);
|
|
79
|
-
opacity: 0;
|
|
80
|
-
background-color: transparent;
|
|
81
|
-
display: none;
|
|
82
|
-
transition: ${unsafeCSS(
|
|
83
|
-
`opacity ${DesignToken.motion.spring.fastEffects},
|
|
84
|
-
transform ${DesignToken.motion.spring.fastSpatial},
|
|
85
|
-
overlay ${DesignToken.motion.spring.fastEffects} allow-discrete,
|
|
86
|
-
display ${DesignToken.motion.spring.fastEffects} allow-discrete`
|
|
87
|
-
)};
|
|
88
|
-
}
|
|
89
|
-
.base {
|
|
90
|
-
display: contents;
|
|
91
|
-
}
|
|
92
|
-
:host([variant="primary"]) .base {
|
|
93
|
-
--_fab-menu-item-color: var(--m3e-primary-fab-color, ${DesignToken.color.onPrimaryContainer});
|
|
94
|
-
--_fab-menu-item-container-color: var(--m3e-primary-fab-container-color, ${DesignToken.color.primaryContainer});
|
|
95
|
-
--_fab-menu-background-hover-color: var(--m3e-primary-fab-hover-color, ${DesignToken.color.onPrimaryContainer});
|
|
96
|
-
--_fab-menu-background-focus-color: var(--m3e-primary-fab-focus-color, ${DesignToken.color.onPrimaryContainer});
|
|
97
|
-
--_fab-menu-ripple-color: var(--m3e-primary-fab-ripple-color, ${DesignToken.color.onPrimaryContainer});
|
|
98
|
-
}
|
|
99
|
-
:host([variant="secondary"]) .base {
|
|
100
|
-
--_fab-menu-item-color: var(--m3e-secondary-fab-color, ${DesignToken.color.onSecondaryContainer});
|
|
101
|
-
--_fab-menu-item-container-color: var(
|
|
102
|
-
--m3e-secondary-fab-container-color,
|
|
103
|
-
${DesignToken.color.secondaryContainer}
|
|
104
|
-
);
|
|
105
|
-
--_fab-menu-background-hover-color: var(
|
|
106
|
-
--m3e-secondary-fab-hover-color,
|
|
107
|
-
${DesignToken.color.onSecondaryContainer}
|
|
108
|
-
);
|
|
109
|
-
--_fab-menu-background-focus-color: var(
|
|
110
|
-
--m3e-secondary-fab-focus-color,
|
|
111
|
-
${DesignToken.color.onSecondaryContainer}
|
|
112
|
-
);
|
|
113
|
-
--_fab-menu-ripple-color: var(--m3e-secondary-fab-ripple-color, ${DesignToken.color.onSecondaryContainer});
|
|
114
|
-
}
|
|
115
|
-
:host([variant="tertiary"]) .base {
|
|
116
|
-
--_fab-menu-item-color: var(--m3e-tertiary-fab-color, ${DesignToken.color.onTertiaryContainer});
|
|
117
|
-
--_fab-menu-item-container-color: var(--m3e-tertiary-fab-container-color, ${DesignToken.color.tertiaryContainer});
|
|
118
|
-
--_fab-menu-background-hover-color: var(--m3e-tertiary-fab-hover-color, ${DesignToken.color.onTertiaryContainer});
|
|
119
|
-
--_fab-menu-background-focus-color: var(--m3e-tertiary-fab-focus-color, ${DesignToken.color.onTertiaryContainer});
|
|
120
|
-
--_fab-menu-ripple-color: var(--m3e-tertiary-fab-ripple-color, ${DesignToken.color.onTertiaryContainer});
|
|
121
|
-
}
|
|
122
|
-
:host {
|
|
123
|
-
transform: scaleX(0.8);
|
|
124
|
-
}
|
|
125
|
-
:host(.-left) {
|
|
126
|
-
align-items: flex-start;
|
|
127
|
-
transform-origin: left;
|
|
128
|
-
}
|
|
129
|
-
:host(.-right) {
|
|
130
|
-
align-items: flex-end;
|
|
131
|
-
transform-origin: right;
|
|
132
|
-
}
|
|
133
|
-
:host(:popover-open) {
|
|
134
|
-
transform: scaleX(1);
|
|
135
|
-
display: inline-flex;
|
|
136
|
-
opacity: 1;
|
|
137
|
-
}
|
|
138
|
-
:host::backdrop {
|
|
139
|
-
background-color: transparent;
|
|
140
|
-
}
|
|
141
|
-
@starting-style {
|
|
142
|
-
:host(:popover-open) {
|
|
143
|
-
opacity: 0;
|
|
144
|
-
}
|
|
145
|
-
:host(:popover-open) {
|
|
146
|
-
transform: scaleX(0.8);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
@media (prefers-reduced-motion) {
|
|
150
|
-
:host {
|
|
151
|
-
transition: none;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
@media (forced-colors: active) {
|
|
155
|
-
:host {
|
|
156
|
-
border-radius: ${DesignToken.shape.corner.medium};
|
|
157
|
-
border: 1px solid MenuText;
|
|
158
|
-
background-color: Menu;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
`;
|
|
162
|
-
|
|
163
|
-
/** @private */ #fabTabIndex?: number;
|
|
164
|
-
/** @private */ #trigger?: HTMLElement;
|
|
165
|
-
/** @private */ #anchoringCleanup?: () => void;
|
|
166
|
-
|
|
167
|
-
/** @private */
|
|
168
|
-
readonly #listManager = new RovingTabIndexManager<LitElement & DisabledMixin>()
|
|
169
|
-
.withWrap()
|
|
170
|
-
.withHomeAndEnd()
|
|
171
|
-
.withVerticalOrientation();
|
|
172
|
-
|
|
173
|
-
/** @private */ readonly #keyDownHandler = (e: KeyboardEvent) => this.#handleKeyDown(e);
|
|
174
|
-
/** @private */ readonly #documentClickHandler = (e: MouseEvent) => this.#handleDocumentClick(e);
|
|
175
|
-
|
|
176
|
-
/** @private */
|
|
177
|
-
readonly #scrollController = new ScrollController(this, { target: null, callback: () => this.hide() });
|
|
178
|
-
|
|
179
|
-
/** @private */
|
|
180
|
-
readonly #toggleHandler = (e: ToggleEvent) => {
|
|
181
|
-
if (e.newState === "closed") {
|
|
182
|
-
this.#anchoringCleanup?.();
|
|
183
|
-
this.#anchoringCleanup = undefined;
|
|
184
|
-
} else {
|
|
185
|
-
setTimeout(() => {
|
|
186
|
-
this.#listManager.setActiveItem(this.#listManager.items.find((x) => !x.disabled));
|
|
187
|
-
}, 40);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* The appearance variant of the menu.
|
|
193
|
-
* @default "primary"
|
|
194
|
-
*/
|
|
195
|
-
@property({ reflect: true }) variant: FabMenuVariant = "primary";
|
|
196
|
-
|
|
197
|
-
/** Whether the menu is open. */
|
|
198
|
-
get isOpen() {
|
|
199
|
-
return this.#trigger !== undefined;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Opens the menu.
|
|
204
|
-
* @param {HTMLElement} trigger The element that triggered the menu.
|
|
205
|
-
* @returns {Promise<void>} A `Promise` that resolves when the menu is opened.
|
|
206
|
-
*/
|
|
207
|
-
async show(trigger: HTMLElement): Promise<void> {
|
|
208
|
-
if (this.#trigger && this.#trigger !== trigger) {
|
|
209
|
-
this.hide();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
this.#anchoringCleanup?.();
|
|
213
|
-
this.#anchoringCleanup = await positionAnchor(
|
|
214
|
-
this,
|
|
215
|
-
trigger,
|
|
216
|
-
{
|
|
217
|
-
position: M3eDirectionality.current === "ltr" ? "top-end" : "top-start",
|
|
218
|
-
inline: true,
|
|
219
|
-
shift: true,
|
|
220
|
-
flip: true,
|
|
221
|
-
offset: 8,
|
|
222
|
-
},
|
|
223
|
-
(x, y, position) => {
|
|
224
|
-
this.classList.toggle("-right", position.includes("end"));
|
|
225
|
-
this.classList.toggle("-left", position.includes("start"));
|
|
226
|
-
this.style.left = `${x}px`;
|
|
227
|
-
this.style.top = `${y}px`;
|
|
228
|
-
}
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
this.showPopover();
|
|
232
|
-
|
|
233
|
-
this.#trigger = trigger;
|
|
234
|
-
this.#trigger.ariaExpanded = "true";
|
|
235
|
-
this.#scrollController.observe(this.#trigger);
|
|
236
|
-
|
|
237
|
-
this.#attachFab();
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Hides the menu.
|
|
242
|
-
* @param {boolean} [restoreFocus=false] A value indicating whether to restore focus to the menu's trigger.
|
|
243
|
-
*/
|
|
244
|
-
hide(restoreFocus: boolean = false): void {
|
|
245
|
-
this.hidePopover();
|
|
246
|
-
|
|
247
|
-
if (this.#trigger) {
|
|
248
|
-
this.#trigger.ariaExpanded = "false";
|
|
249
|
-
if (restoreFocus) {
|
|
250
|
-
this.#trigger.focus();
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
this.#detachFab();
|
|
254
|
-
|
|
255
|
-
this.#scrollController.unobserve(this.#trigger);
|
|
256
|
-
this.#trigger = undefined;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Toggles the menu.
|
|
262
|
-
* @param {HTMLElement} trigger The element that triggered the menu.
|
|
263
|
-
* @returns {Promise<void>} A `Promise` that resolves when the menu is opened or closed.
|
|
264
|
-
*/
|
|
265
|
-
async toggle(trigger: HTMLElement): Promise<void> {
|
|
266
|
-
if (this.#trigger) {
|
|
267
|
-
this.hide();
|
|
268
|
-
} else {
|
|
269
|
-
await this.show(trigger);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/** @inheritdoc */
|
|
274
|
-
override connectedCallback(): void {
|
|
275
|
-
super.connectedCallback();
|
|
276
|
-
|
|
277
|
-
this.tabIndex = -1;
|
|
278
|
-
this.setAttribute("popover", "manual");
|
|
279
|
-
|
|
280
|
-
this.addEventListener("keydown", this.#keyDownHandler);
|
|
281
|
-
this.addEventListener("toggle", this.#toggleHandler);
|
|
282
|
-
document.addEventListener("click", this.#documentClickHandler);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/** @inheritdoc */
|
|
286
|
-
override disconnectedCallback(): void {
|
|
287
|
-
super.disconnectedCallback();
|
|
288
|
-
|
|
289
|
-
this.removeEventListener("keydown", this.#keyDownHandler);
|
|
290
|
-
this.removeEventListener("toggle", this.#toggleHandler);
|
|
291
|
-
document.removeEventListener("click", this.#documentClickHandler);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/** @inheritdoc */
|
|
295
|
-
protected override render(): unknown {
|
|
296
|
-
return html`<div class="base"><slot @slotchange="${this.#handleSlotChange}"></slot></div>`;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/** @private */
|
|
300
|
-
#handleSlotChange(): void {
|
|
301
|
-
const { added } = this.#listManager.setItems([...this.querySelectorAll("m3e-fab-menu-item")]);
|
|
302
|
-
if (!this.#listManager.activeItem) {
|
|
303
|
-
this.#listManager.updateActiveItem(added.find((x) => !x.disabled));
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/** @private */
|
|
308
|
-
#handleKeyDown(e: KeyboardEvent): void {
|
|
309
|
-
switch (e.key) {
|
|
310
|
-
case "Tab":
|
|
311
|
-
this.hide();
|
|
312
|
-
break;
|
|
313
|
-
|
|
314
|
-
case "Escape":
|
|
315
|
-
if (!e.shiftKey && !e.ctrlKey) {
|
|
316
|
-
this.hide(true);
|
|
317
|
-
}
|
|
318
|
-
break;
|
|
319
|
-
|
|
320
|
-
default:
|
|
321
|
-
this.#listManager.onKeyDown(e);
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/** @private */
|
|
327
|
-
#handleDocumentClick(e: MouseEvent): void {
|
|
328
|
-
if (!e.composedPath().some((x) => x instanceof M3eFabMenuItemElement || x === this.#trigger)) {
|
|
329
|
-
this.hide();
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/** @private */
|
|
334
|
-
#attachFab(): void {
|
|
335
|
-
const fab = this.#trigger?.closest<M3eFabElement>("m3e-fab");
|
|
336
|
-
if (fab) {
|
|
337
|
-
this.#fabTabIndex = fab.tabIndex;
|
|
338
|
-
fab.addEventListener("keydown", this.#keyDownHandler);
|
|
339
|
-
this.#listManager.setItems([...this.#listManager.items, fab]);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/** @private */
|
|
344
|
-
#detachFab(): void {
|
|
345
|
-
const fab = this.#trigger?.closest<M3eFabElement>("m3e-fab");
|
|
346
|
-
if (fab) {
|
|
347
|
-
if (this.#fabTabIndex !== undefined) {
|
|
348
|
-
fab.tabIndex = this.#fabTabIndex;
|
|
349
|
-
}
|
|
350
|
-
fab.removeEventListener("keydown", this.#keyDownHandler);
|
|
351
|
-
this.#listManager.setItems([...this.#listManager.items.filter((x) => x !== fab)]);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
interface M3eFabMenuElementEventMap extends HTMLElementEventMap {
|
|
357
|
-
beforetoggle: ToggleEvent;
|
|
358
|
-
toggle: ToggleEvent;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export interface M3eFabMenuElement {
|
|
362
|
-
addEventListener<K extends keyof M3eFabMenuElementEventMap>(
|
|
363
|
-
type: K,
|
|
364
|
-
listener: (this: M3eFabMenuElement, ev: M3eFabMenuElementEventMap[K]) => void,
|
|
365
|
-
options?: boolean | AddEventListenerOptions
|
|
366
|
-
): void;
|
|
367
|
-
|
|
368
|
-
addEventListener(
|
|
369
|
-
type: string,
|
|
370
|
-
listener: EventListenerOrEventListenerObject,
|
|
371
|
-
options?: boolean | AddEventListenerOptions
|
|
372
|
-
): void;
|
|
373
|
-
|
|
374
|
-
removeEventListener<K extends keyof M3eFabMenuElementEventMap>(
|
|
375
|
-
type: K,
|
|
376
|
-
listener: (this: M3eFabMenuElement, ev: M3eFabMenuElementEventMap[K]) => void,
|
|
377
|
-
options?: boolean | EventListenerOptions
|
|
378
|
-
): void;
|
|
379
|
-
|
|
380
|
-
removeEventListener(
|
|
381
|
-
type: string,
|
|
382
|
-
listener: EventListenerOrEventListenerObject,
|
|
383
|
-
options?: boolean | EventListenerOptions
|
|
384
|
-
): void;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
declare global {
|
|
388
|
-
interface HTMLElementTagNameMap {
|
|
389
|
-
"m3e-fab-menu": M3eFabMenuElement;
|
|
390
|
-
}
|
|
391
|
-
}
|