@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.
@@ -1,253 +0,0 @@
1
- import { css, CSSResultGroup, html, LitElement, PropertyValues, unsafeCSS } from "lit";
2
- import { customElement, query } from "lit/decorators.js";
3
-
4
- import {
5
- AttachInternals,
6
- DesignToken,
7
- Disabled,
8
- KeyboardClick,
9
- LinkButton,
10
- M3eElevationElement,
11
- M3eFocusRingElement,
12
- M3eRippleElement,
13
- M3eStateLayerElement,
14
- renderPseudoLink,
15
- Role,
16
- } from "@m3e/core";
17
-
18
- import type { M3eFabMenuElement } from "./FabMenuElement";
19
-
20
- /**
21
- * An item of a floating action button (FAB) menu.
22
- *
23
- * @example
24
- * The following example illustrates triggering a `m3e-fab-menu` from an `m3e-fab` using a `m3e-fab-menu-trigger`.
25
- * ```html
26
- * <m3e-fab variant="primary" size="large">
27
- * <m3e-fab-menu-trigger for="fabmenu">
28
- * <m3e-icon name="edit"></m3e-icon>
29
- * </m3e-fab-menu-trigger>
30
- * </m3e-fab>
31
- * <m3e-fab-menu id="fabmenu" variant="secondary">
32
- * <m3e-fab-menu-item>First</m3e-fab-menu-item>
33
- * <m3e-fab-menu-item>Second</m3e-fab-menu-item>
34
- * <m3e-fab-menu-item>Third</m3e-fab-menu-item>
35
- * <m3e-fab-menu-item>Forth</m3e-fab-menu-item>
36
- * <m3e-fab-menu-item>Fifth</m3e-fab-menu-item>
37
- * <m3e-fab-menu-item>Sixth</m3e-fab-menu-item>
38
- * </m3e-fab-menu>
39
- * ```
40
- *
41
- * @tag m3e-menu-item
42
- *
43
- * @slot - Renders the label of the item.
44
- * @slot icon - Renders an icon before the items's label.
45
- *
46
- * @attr disabled - Whether the element is disabled.
47
- * @attr download - A value indicating whether the `target` of the link button will be downloaded, optionally specifying the new name of the file.
48
- * @attr href - The URL to which the link button points.
49
- * @attr rel - The relationship between the `target` of the link button and the document.
50
- * @attr target - The target of the link button.
51
- *
52
- * @cssprop --m3e-fab-menu-item-height - Height of the menu item.
53
- * @cssprop --m3e-fab-menu-item-font-size - Font size of the menu item label.
54
- * @cssprop --m3e-fab-menu-item-font-weight - Font weight of the menu item label.
55
- * @cssprop --m3e-fab-menu-item-line-height - Line height of the menu item label.
56
- * @cssprop --m3e-fab-menu-item-tracking - Letter spacing of the menu item label.
57
- * @cssprop --m3e-fab-menu-item-shape - Border radius of the menu item.
58
- * @cssprop --m3e-fab-menu-item-leading-space - Padding at the start of the menu item.
59
- * @cssprop --m3e-fab-menu-item-trailing-space - Padding at the end of the menu item.
60
- * @cssprop --m3e-fab-menu-item-spacing - Gap between icon and label.
61
- * @cssprop --m3e-fab-menu-item-icon-size - Size of the icon in the menu item.
62
- */
63
- @customElement("m3e-fab-menu-item")
64
- export class M3eFabMenuItemElement extends KeyboardClick(
65
- LinkButton(Disabled(AttachInternals(Role(LitElement, "menuitem"), true)))
66
- ) {
67
- /** The styles of the element. */
68
- static override styles: CSSResultGroup = css`
69
- :host {
70
- display: inline-block;
71
- outline: none;
72
- user-select: none;
73
- }
74
- .base {
75
- box-sizing: border-box;
76
- vertical-align: middle;
77
- display: inline-flex;
78
- align-items: center;
79
- justify-content: center;
80
- position: relative;
81
- width: 100%;
82
- transition: ${unsafeCSS(
83
- `background-color ${DesignToken.motion.duration.short4} ${DesignToken.motion.easing.standard}`
84
- )};
85
- height: var(--m3e-fab-menu-item-height, 3.5rem);
86
- font-size: var(--m3e-fab-menu-item-font-size, ${DesignToken.typescale.standard.label.large.fontSize});
87
- font-weight: var(--m3e-fab-menu-item-font-weight, ${DesignToken.typescale.standard.label.large.fontWeight});
88
- line-height: var(--m3e-fab-menu-item-line-height, ${DesignToken.typescale.standard.label.large.lineHeight});
89
- letter-spacing: var(--m3e-fab-menu-item-tracking, ${DesignToken.typescale.standard.label.large.tracking});
90
- border-radius: var(--m3e-fab-menu-item-shape, ${DesignToken.shape.corner.full});
91
- }
92
- :host(:not(:disabled)) .label,
93
- :host(:not(:disabled)) .icon {
94
- color: var(--_fab-menu-item-color);
95
- }
96
- :host(:not(:disabled)) .base {
97
- background-color: var(--_fab-menu-item-container-color);
98
- --m3e-state-layer-hover-color: var(--_fab-menu-background-hover-color);
99
- --m3e-state-layer-focus-color: var(--_fab-menu-background-focus-color);
100
- --m3e-ripple-color: var(--_fab-menu-ripple-color);
101
- }
102
- :host(:disabled) .base {
103
- background-color: color-mix(
104
- in srgb,
105
- var(--m3e-fab-menu-item-disabled-container-color, ${DesignToken.color.onSurface})
106
- var(--m3e-fab-menu-item-disabled-container-opacity, 10%),
107
- transparent
108
- );
109
- }
110
- :host(:disabled) .label,
111
- :host(:disabled) .icon {
112
- color: color-mix(
113
- in srgb,
114
- var(--m3e-fab-menu-item-disabled-color, ${DesignToken.color.onSurface})
115
- var(--m3e-fab-menu-item-disabled-opacity, 38%),
116
- transparent
117
- );
118
- }
119
- .touch {
120
- position: absolute;
121
- height: 3rem;
122
- left: 0;
123
- right: 0;
124
- }
125
- .wrapper {
126
- width: 100%;
127
- overflow: hidden;
128
- display: inline-flex;
129
- align-items: center;
130
- padding-inline-start: var(--m3e-fab-menu-item-leading-space, 1.5rem);
131
- padding-inline-end: var(--m3e-fab-menu-item-trailing-space, 1.5rem);
132
- column-gap: var(--m3e-fab-menu-item-spacing, 0.5rem);
133
- }
134
- .label {
135
- justify-self: center;
136
- flex: 1 1 auto;
137
- text-align: center;
138
- white-space: nowrap;
139
- overflow: hidden;
140
- text-overflow: ellipsis;
141
- transition: ${unsafeCSS(`color ${DesignToken.motion.duration.short4} ${DesignToken.motion.easing.standard}`)};
142
- }
143
- .icon {
144
- font-size: var(--m3e-fab-menu-item-icon-size, 1.5rem);
145
- transition: ${unsafeCSS(`color ${DesignToken.motion.duration.short4} ${DesignToken.motion.easing.standard}`)};
146
- }
147
- :host(:not(:disabled)) {
148
- cursor: pointer;
149
- }
150
- ::slotted([slot="icon"]) {
151
- font-size: inherit !important;
152
- flex: none;
153
- }
154
- ::slotted(svg[slot="icon"]) {
155
- width: 1em;
156
- height: 1em;
157
- }
158
- a {
159
- all: unset;
160
- display: block;
161
- position: absolute;
162
- top: 0px;
163
- left: 0px;
164
- right: 0px;
165
- bottom: 0px;
166
- z-index: 1;
167
- }
168
- @media (prefers-reduced-motion) {
169
- .base,
170
- .label,
171
- .icon {
172
- transition: none;
173
- }
174
- }
175
- @media (forced-colors: active) {
176
- .base,
177
- .label,
178
- .icon {
179
- transition: none;
180
- }
181
- :host(:not(:disabled)) .base {
182
- background-color: Menu;
183
- }
184
- :host(:not(:disabled)) .label,
185
- :host(:not(:disabled)) .icon {
186
- color: MenuText;
187
- }
188
- :host(:disabled) .label,
189
- :host(:disabled) .icon {
190
- color: GrayText;
191
- }
192
- }
193
- `;
194
-
195
- /** @private */ @query(".elevation") private readonly _elevation?: M3eElevationElement;
196
- /** @private */ @query(".focus-ring") private readonly _focusRing?: M3eFocusRingElement;
197
- /** @private */ @query(".state-layer") private readonly _stateLayer?: M3eStateLayerElement;
198
- /** @private */ @query(".ripple") private readonly _ripple?: M3eRippleElement;
199
-
200
- /** @private */ readonly #clickHandler = (e: Event) => this.#handleClick(e);
201
-
202
- /** The floating action button (FAB) menu to which this item belongs. */
203
- get menu(): M3eFabMenuElement | null {
204
- return this.closest("m3e-fab-menu");
205
- }
206
-
207
- /** @inheritdoc */
208
- override connectedCallback(): void {
209
- super.connectedCallback();
210
- this.addEventListener("click", this.#clickHandler);
211
- }
212
-
213
- /** @inheritdoc */
214
- override disconnectedCallback(): void {
215
- super.disconnectedCallback();
216
- this.removeEventListener("click", this.#clickHandler);
217
- }
218
-
219
- /** @inheritdoc */
220
- protected override firstUpdated(_changedProperties: PropertyValues<this>): void {
221
- super.firstUpdated(_changedProperties);
222
- [this._elevation, this._focusRing, this._stateLayer, this._ripple].forEach((x) => x?.attach(this));
223
- }
224
-
225
- /** @inheritdoc */
226
- override render(): unknown {
227
- return html`<div class="base">
228
- <m3e-elevation class="elevation" ?disabled="${this.disabled}"></m3e-elevation>
229
- <m3e-state-layer class="state-layer" ?disabled="${this.disabled}"></m3e-state-layer>
230
- <m3e-focus-ring class="focus-ring" ?disabled="${this.disabled}"></m3e-focus-ring>
231
- <m3e-ripple class="ripple" ?disabled="${this.disabled}"></m3e-ripple>
232
- <div class="touch" aria-hidden="true"></div>
233
- ${this[renderPseudoLink]()}
234
- <div class="wrapper">
235
- <slot class="icon" name="icon" aria-hidden="true"></slot>
236
- <div class="label"><slot></slot></div>
237
- </div>
238
- </div>`;
239
- }
240
-
241
- /** @private */
242
- #handleClick(e: Event): void {
243
- if (!e.defaultPrevented) {
244
- this.menu?.hide(true);
245
- }
246
- }
247
- }
248
-
249
- declare global {
250
- interface HTMLElementTagNameMap {
251
- "m3e-fab-menu-item": M3eFabMenuItemElement;
252
- }
253
- }
@@ -1,108 +0,0 @@
1
- import { css, CSSResultGroup, html, LitElement } from "lit";
2
- import { customElement } from "lit/decorators.js";
3
-
4
- import { HtmlFor, Role } from "@m3e/core";
5
- import { addAriaReferencedId, removeAriaReferencedId } from "@m3e/core/a11y";
6
-
7
- import { M3eFabMenuElement } from "./FabMenuElement";
8
-
9
- /**
10
- * An element, nested within a clickable element, used to open a floating action button (FAB) menu.
11
- *
12
- * @example
13
- * The following example illustrates triggering a `m3e-fab-menu` from an `m3e-fab` using a `m3e-fab-menu-trigger`.
14
- * ```html
15
- * <m3e-fab variant="primary" size="large">
16
- * <m3e-fab-menu-trigger for="fabmenu">
17
- * <m3e-icon name="edit"></m3e-icon>
18
- * </m3e-fab-menu-trigger>
19
- * </m3e-fab>
20
- * <m3e-fab-menu id="fabmenu" variant="secondary">
21
- * <m3e-fab-menu-item>First</m3e-fab-menu-item>
22
- * <m3e-fab-menu-item>Second</m3e-fab-menu-item>
23
- * <m3e-fab-menu-item>Third</m3e-fab-menu-item>
24
- * <m3e-fab-menu-item>Forth</m3e-fab-menu-item>
25
- * <m3e-fab-menu-item>Fifth</m3e-fab-menu-item>
26
- * <m3e-fab-menu-item>Sixth</m3e-fab-menu-item>
27
- * </m3e-fab-menu>
28
- * ```
29
- *
30
- * @tag m3e-fab-menu-trigger
31
- */
32
- @customElement("m3e-fab-menu-trigger")
33
- export class M3eFabMenuTriggerElement extends HtmlFor(Role(LitElement, "none")) {
34
- /** The styles of the element. */
35
- static override styles: CSSResultGroup = css`
36
- :host {
37
- display: contents;
38
- }
39
- ::slotted(.material-icons) {
40
- font-size: inherit !important;
41
- }
42
- `;
43
-
44
- /** @private */ readonly #clickHandler = async (e: Event) => this.#handleClick(e);
45
-
46
- /** The menu triggered by the element. */
47
- get menu(): M3eFabMenuElement | null {
48
- return this.control instanceof M3eFabMenuElement ? this.control : null;
49
- }
50
-
51
- /** @inheritdoc */
52
- override connectedCallback(): void {
53
- super.connectedCallback();
54
- this.parentElement?.addEventListener("click", this.#clickHandler);
55
- }
56
-
57
- /** @inheritdoc */
58
- override disconnectedCallback(): void {
59
- super.disconnectedCallback();
60
- this.parentElement?.removeEventListener("click", this.#clickHandler);
61
- }
62
-
63
- /** @inheritdoc */
64
- override attach(control: HTMLElement): void {
65
- super.attach(control);
66
-
67
- if (control instanceof M3eFabMenuElement) {
68
- if (this.parentElement) {
69
- this.parentElement.ariaHasPopup = "menu";
70
- this.parentElement.ariaExpanded = "false";
71
- if (control.id) {
72
- addAriaReferencedId(this.parentElement, "aria-controls", control.id);
73
- }
74
- }
75
- }
76
- }
77
-
78
- /** @inheritdoc */
79
- override detach(): void {
80
- if (this.parentElement) {
81
- this.parentElement.ariaHasPopup = null;
82
- this.parentElement.ariaExpanded = null;
83
- if (this.control?.id) {
84
- removeAriaReferencedId(this.parentElement, "aria-controls", this.control.id);
85
- }
86
- }
87
-
88
- super.detach();
89
- }
90
-
91
- /** @inheritdoc */
92
- protected override render(): unknown {
93
- return html`<slot></slot>`;
94
- }
95
-
96
- /** @private */
97
- #handleClick(e: Event): void {
98
- if (!e.defaultPrevented && this.parentElement) {
99
- this.menu?.toggle(this.parentElement);
100
- }
101
- }
102
- }
103
-
104
- declare global {
105
- interface HTMLElementTagNameMap {
106
- "m3e-fab-menu-trigger": M3eFabMenuTriggerElement;
107
- }
108
- }
@@ -1,2 +0,0 @@
1
- /** Specifies the possible appearance variants of a floating-action button menu. */
2
- export type FabMenuVariant = "primary" | "secondary" | "tertiary";
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./FabMenuElement";
2
- export * from "./FabMenuItemElement";
3
- export * from "./FabMenuTriggerElement";
4
- export * from "./FabMenuVariant";
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist/src"
6
- },
7
- "include": ["src/**/*.ts", "**/*.mjs", "**/*.js"],
8
- "exclude": []
9
- }