@m3e/drawer-container 1.0.0-rc.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.
Files changed (39) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +139 -0
  3. package/cem.config.mjs +16 -0
  4. package/demo/index.html +88 -0
  5. package/dist/css-custom-data.json +57 -0
  6. package/dist/custom-elements.json +569 -0
  7. package/dist/html-custom-data.json +49 -0
  8. package/dist/index.js +620 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/index.min.js +209 -0
  11. package/dist/index.min.js.map +1 -0
  12. package/dist/src/DrawerContainerElement.d.ts +105 -0
  13. package/dist/src/DrawerContainerElement.d.ts.map +1 -0
  14. package/dist/src/DrawerMode.d.ts +3 -0
  15. package/dist/src/DrawerMode.d.ts.map +1 -0
  16. package/dist/src/DrawerPosition.d.ts +3 -0
  17. package/dist/src/DrawerPosition.d.ts.map +1 -0
  18. package/dist/src/DrawerToggleElement.d.ts +48 -0
  19. package/dist/src/DrawerToggleElement.d.ts.map +1 -0
  20. package/dist/src/index.d.ts +5 -0
  21. package/dist/src/index.d.ts.map +1 -0
  22. package/dist/src/styles/DrawerContainerStyle.d.ts +7 -0
  23. package/dist/src/styles/DrawerContainerStyle.d.ts.map +1 -0
  24. package/dist/src/styles/DrawerContainerToken.d.ts +16 -0
  25. package/dist/src/styles/DrawerContainerToken.d.ts.map +1 -0
  26. package/dist/src/styles/index.d.ts +2 -0
  27. package/dist/src/styles/index.d.ts.map +1 -0
  28. package/eslint.config.mjs +13 -0
  29. package/package.json +49 -0
  30. package/rollup.config.js +32 -0
  31. package/src/DrawerContainerElement.ts +244 -0
  32. package/src/DrawerMode.ts +2 -0
  33. package/src/DrawerPosition.ts +2 -0
  34. package/src/DrawerToggleElement.ts +123 -0
  35. package/src/index.ts +4 -0
  36. package/src/styles/DrawerContainerStyle.ts +178 -0
  37. package/src/styles/DrawerContainerToken.ts +19 -0
  38. package/src/styles/index.ts +1 -0
  39. package/tsconfig.json +9 -0
@@ -0,0 +1,123 @@
1
+ import { css, CSSResultGroup, html, LitElement } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+
4
+ import { HtmlFor, Role } from "@m3e/core";
5
+
6
+ import { M3eDrawerContainerElement } from "./DrawerContainerElement";
7
+
8
+ /**
9
+ * An element, nested within a clickable element, used to toggle the opened state of a drawer.
10
+ *
11
+ * @example
12
+ * The following example illustrates the use of a `m3e-drawer-toggle`, nested inside a `m3e-icon-button` component,
13
+ * which toggles the open state of the start drawer.
14
+ *
15
+ * ```html
16
+ * <m3e-icon-button slot="leading-icon" aria-label="Menu" toggle selected>
17
+ * <m3e-drawer-toggle for="startDrawer"></m3e-drawer-toggle>
18
+ * <m3e-icon name="menu"></m3e-icon>
19
+ * <m3e-icon slot="selected" name="menu_open"></m3e-icon>
20
+ * </m3e-icon-button>
21
+ *
22
+ * <m3e-drawer-container start>
23
+ * <nav slot="start" id="startDrawer" aria-label="Navigation">
24
+ * <!-- Start drawer content -->
25
+ * </nav>
26
+ * <!-- Container content -->
27
+ * </m3e-drawer-container>
28
+ * ```
29
+ *
30
+ * @tag m3e-drawer-toggle
31
+ */
32
+ @customElement("m3e-drawer-toggle")
33
+ export class M3eDrawerToggleElement 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 = (e: Event) => this.#handleClick(e);
45
+ /** @private */ readonly #drawerContainerChangeHandler = () => this.#handleDrawerContainerChange();
46
+
47
+ /** @inheritdoc */
48
+ override connectedCallback(): void {
49
+ super.connectedCallback();
50
+ this.parentElement?.addEventListener("click", this.#clickHandler);
51
+ }
52
+
53
+ /** @inheritdoc */
54
+ override disconnectedCallback(): void {
55
+ super.disconnectedCallback();
56
+ this.parentElement?.removeEventListener("click", this.#clickHandler);
57
+ }
58
+
59
+ /** @inheritdoc */
60
+ override attach(control: HTMLElement): void {
61
+ const container = control.closest("m3e-drawer-container");
62
+ if (container) {
63
+ container.addEventListener("change", this.#drawerContainerChangeHandler);
64
+ this.#updateToggle(container, control);
65
+ }
66
+
67
+ super.attach(control);
68
+ }
69
+
70
+ /** @inheritdoc */
71
+ override detach(): void {
72
+ this.control?.closest("m3e-drawer-container")?.removeEventListener("change", this.#drawerContainerChangeHandler);
73
+ super.detach();
74
+ }
75
+
76
+ /** @inheritdoc */
77
+ protected override render(): unknown {
78
+ return html`<slot></slot>`;
79
+ }
80
+
81
+ /** @private */
82
+ #handleClick(e: Event): void {
83
+ if (!e.defaultPrevented && this.control && this.parentElement) {
84
+ const container = this.control.closest("m3e-drawer-container");
85
+ if (container) {
86
+ if (this.control.slot === "start") {
87
+ container.start = !container.start;
88
+ } else if (this.control.slot === "end") {
89
+ container.end = !container.end;
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ /** @private */
96
+ #handleDrawerContainerChange(): void {
97
+ if (this.control) {
98
+ const container = this.control.closest("m3e-drawer-container");
99
+ if (container) {
100
+ this.#updateToggle(container, this.control);
101
+ }
102
+ }
103
+ }
104
+
105
+ /** @private */
106
+ #updateToggle(container: M3eDrawerContainerElement, control: HTMLElement) {
107
+ if (control.slot === "start") {
108
+ if (this.parentElement?.hasAttribute("toggle")) {
109
+ this.parentElement.toggleAttribute("selected", container.start);
110
+ }
111
+ } else if (control.slot === "end") {
112
+ if (this.parentElement?.hasAttribute("toggle")) {
113
+ this.parentElement.toggleAttribute("selected", container.end);
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ declare global {
120
+ interface HTMLElementTagNameMap {
121
+ "m3e-drawer-toggle": M3eDrawerToggleElement;
122
+ }
123
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./DrawerContainerElement";
2
+ export * from "./DrawerMode";
3
+ export * from "./DrawerPosition";
4
+ export * from "./DrawerToggleElement";
@@ -0,0 +1,178 @@
1
+ import { css, CSSResultGroup, unsafeCSS } from "lit";
2
+
3
+ import { DesignToken } from "@m3e/core";
4
+
5
+ import { DrawerContainerToken } from "./DrawerContainerToken";
6
+
7
+ /**
8
+ * Styles for `M3eDrawerContainerElement`.
9
+ * @internal
10
+ */
11
+ export const DrawerContainerStyle: CSSResultGroup = css`
12
+ :host {
13
+ display: flex;
14
+ flex-direction: row;
15
+ position: relative;
16
+ overflow: hidden;
17
+ flex: 1 1 auto;
18
+ }
19
+ .content {
20
+ height: 100%;
21
+ }
22
+ ::slotted([slot="start"]),
23
+ ::slotted([slot="end"]) {
24
+ display: block;
25
+ height: 100%;
26
+ z-index: 3;
27
+ outline: none;
28
+ box-sizing: border-box;
29
+ flex: none;
30
+ width: ${DrawerContainerToken.containerWidth};
31
+ background-color: ${DrawerContainerToken.containerColor};
32
+ box-shadow: ${DrawerContainerToken.containerElevation};
33
+ transition: ${unsafeCSS(
34
+ `margin ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard},
35
+ visibility ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard} allow-discrete,
36
+ background-color ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard},
37
+ box-shadow ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard}`
38
+ )};
39
+ }
40
+ :host(.-start-over) ::slotted([slot="start"]) {
41
+ position: absolute;
42
+ top: 0;
43
+ left: 0;
44
+ }
45
+ :host(.-end-over) ::slotted([slot="end"]) {
46
+ position: absolute;
47
+ top: 0;
48
+ right: 0;
49
+ }
50
+ :host(:not([start])) ::slotted([slot="start"]) {
51
+ visibility: hidden;
52
+ margin-inline-start: calc(0px - ${DrawerContainerToken.containerWidth});
53
+ }
54
+ :host([start]) ::slotted([slot="start"]) {
55
+ visibility: visible;
56
+ margin-inline-start: 0;
57
+ }
58
+ :host(:not([end])) ::slotted([slot="end"]) {
59
+ visibility: hidden;
60
+ margin-inline-end: calc(0px - ${DrawerContainerToken.containerWidth});
61
+ }
62
+ :host([end]) ::slotted([slot="end"]) {
63
+ margin-inline-end: 0;
64
+ visibility: visible;
65
+ }
66
+ .content {
67
+ flex: 1 1 auto;
68
+ position: relative;
69
+ height: 100%;
70
+ }
71
+ .scrim {
72
+ display: block;
73
+ position: absolute;
74
+ left: 0;
75
+ right: 0;
76
+ top: 0;
77
+ bottom: 0;
78
+ z-index: 1;
79
+ background-color: ${DesignToken.color.scrim};
80
+ opacity: 0;
81
+ visibility: hidden;
82
+ transition: ${unsafeCSS(
83
+ `opacity ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard},
84
+ visibility ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard} allow-discrete`
85
+ )};
86
+ }
87
+ @starting-style {
88
+ .scrim {
89
+ opacity: 0;
90
+ }
91
+ }
92
+ :host(.-start-push[start]) .scrim,
93
+ :host(.-end-push[end]) .scrim,
94
+ :host(.-start-over[start]) .scrim,
95
+ :host(.-end-over[end]) .scrim {
96
+ visibility: visible;
97
+ opacity: ${DrawerContainerToken.scrimOpacity};
98
+ }
99
+ :host(.-start-push) ::slotted([slot="start"]),
100
+ :host(.-start-over) ::slotted([slot="start"]) {
101
+ border-start-end-radius: ${DrawerContainerToken.cornerShape};
102
+ border-end-end-radius: ${DrawerContainerToken.cornerShape};
103
+ }
104
+ :host(.-end-push) ::slotted([slot="end"]),
105
+ :host(.-end-over) ::slotted([slot="end"]) {
106
+ border-start-start-radius: ${DrawerContainerToken.cornerShape};
107
+ border-end-start-radius: ${DrawerContainerToken.cornerShape};
108
+ }
109
+ :host(.-start-push) ::slotted([slot="start"]),
110
+ :host(.-end-push) ::slotted([slot="end"]),
111
+ :host(.-start-over) ::slotted([slot="start"]),
112
+ :host(.-end-over) ::slotted([slot="end"]) {
113
+ background-color: ${DrawerContainerToken.modalContainerColor};
114
+ box-shadow: ${DrawerContainerToken.modalContainerElevation};
115
+ }
116
+ :host([start-divider]) ::slotted([slot="start"]) {
117
+ border-inline-end-color: transparent;
118
+ border-inline-end-width: ${DrawerContainerToken.dividerThickness};
119
+ border-inline-end-style: solid;
120
+ box-sizing: border-box;
121
+ }
122
+ :host([start-divider].-start-side[start]:not(.-end-push[end]):not(.-end-over[end])) ::slotted([slot="start"]) {
123
+ border-inline-end-color: ${DrawerContainerToken.dividerColor};
124
+ }
125
+ :host([end-divider]) ::slotted([slot="end"]) {
126
+ border-inline-start-color: transparent;
127
+ border-inline-start-width: ${DrawerContainerToken.dividerThickness};
128
+ border-inline-start-style: solid;
129
+ box-sizing: border-box;
130
+ }
131
+ :host([end-divider].-end-side[end]:not(.-start-push[start]):not(.-start-over[start])) ::slotted([slot="end"]) {
132
+ border-inline-start-color: ${DrawerContainerToken.dividerColor};
133
+ }
134
+ @media (forced-colors: active) {
135
+ ::slotted([slot="start"]),
136
+ ::slotted([slot="end"]) {
137
+ background-color: Canvas;
138
+ box-shadow: unset;
139
+ transition: ${unsafeCSS(
140
+ `margin ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard},
141
+ visibility ${DesignToken.motion.duration.medium4} ${DesignToken.motion.easing.standard} allow-discrete`
142
+ )};
143
+ }
144
+ :host(.-start-push) ::slotted([slot="start"]),
145
+ :host(.-end-push) ::slotted([slot="end"]),
146
+ :host(.-start-over) ::slotted([slot="start"]),
147
+ :host(.-end-over) ::slotted([slot="end"]) {
148
+ background-color: Canvas;
149
+ box-shadow: unset;
150
+ border-color: CanvasText;
151
+ }
152
+ ::slotted([slot="start"]),
153
+ ::slotted([slot="end"]) {
154
+ border-style: solid;
155
+ border-color: Canvas;
156
+ border-width: 1px;
157
+ }
158
+ ::slotted([slot="start"]) {
159
+ border-inline-start-style: none;
160
+ }
161
+ ::slotted([slot="end"]) {
162
+ border-inline-end-style: none;
163
+ }
164
+ :host([start-divider].-start-side[start]:not(.-end-push[end]):not(.-end-over[end])) ::slotted([slot="start"]) {
165
+ border-inline-end-color: GrayText;
166
+ }
167
+ :host([end-divider].-end-side[end]:not(.-start-push[start]):not(.-start-over[start])) ::slotted([slot="end"]) {
168
+ border-inline-start-color: GrayText;
169
+ }
170
+ }
171
+ @media (prefers-reduced-motion) {
172
+ ::slotted([slot="start"]),
173
+ ::slotted([slot="end"]),
174
+ .scrim {
175
+ transition: none;
176
+ }
177
+ }
178
+ `;
@@ -0,0 +1,19 @@
1
+ import { unsafeCSS } from "lit";
2
+
3
+ import { DesignToken } from "@m3e/core";
4
+
5
+ /**
6
+ * Component design tokens that control `M3eDrawerContainerElement`.
7
+ * @internal
8
+ */
9
+ export const DrawerContainerToken = {
10
+ containerColor: unsafeCSS(`var(--m3e-drawer-container-color, ${DesignToken.color.surface})`),
11
+ containerElevation: unsafeCSS(`var(--m3e-drawer-container-elevation, ${DesignToken.elevation.level0})`),
12
+ containerWidth: unsafeCSS(`var(--m3e-drawer-container-width, 22.5rem)`),
13
+ scrimOpacity: unsafeCSS("var(--m3e-drawer-container-scrim-opacity, 32%)"),
14
+ cornerShape: unsafeCSS(`var(--m3e-modal-drawer-corner-shape, ${DesignToken.shape.corner.large})`),
15
+ modalContainerColor: unsafeCSS(`var(--m3e-modal-drawer-container-color, ${DesignToken.color.surfaceContainerLow})`),
16
+ modalContainerElevation: unsafeCSS(`var(--m3e-modal-drawer-elevation, ${DesignToken.elevation.level1})`),
17
+ dividerColor: unsafeCSS(`var(--m3e-drawer-divider-color, ${DesignToken.color.outline})`),
18
+ dividerThickness: unsafeCSS("var(--m3e-drawer-divider-thickness, 1px)"),
19
+ } as const;
@@ -0,0 +1 @@
1
+ export * from "./DrawerContainerStyle";
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "./dist/src"
6
+ },
7
+ "include": ["src/**/*.ts", "**/*.mjs", "**/*.js"],
8
+ "exclude": []
9
+ }