@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,105 @@
1
+ import { CSSResultGroup, LitElement, PropertyValues } from "lit";
2
+ import { DrawerMode } from "./DrawerMode";
3
+ declare const M3eDrawerContainerElement_base: import("node_modules/@m3e/core/dist/src/shared/mixins/Constructor").Constructor & typeof LitElement;
4
+ /**
5
+ * @summary
6
+ * A container for one or two sliding drawers.
7
+ *
8
+ * @description
9
+ * A responsive layout container that manages left and right drawers alongside main content.
10
+ * Supports `over`, `push`, `side`, and `auto` modes, adapting drawer behavior based on breakpoint size.
11
+ * Encodes spatial hierarchy, motion transitions, and accessibility semantics for modal, dismissible,
12
+ * and permanent navigation.
13
+ *
14
+ * @example
15
+ * The following example illustrates a typical drawer layout.
16
+ * ```html
17
+ * <m3e-drawer-container>
18
+ * <nav slot="start">
19
+ * <!-- Start drawer content -->
20
+ * </nav>
21
+ * <main>
22
+ * <!-- Main content -->
23
+ * </main>
24
+ * <aside slot="end">
25
+ * <!-- End drawer content -->
26
+ * </aside>
27
+ * <m3e-drawer-container>
28
+ * ```
29
+ *
30
+ * @tag m3e-drawer-container
31
+ *
32
+ * @slot - Renders the main content.
33
+ * @slot start - Renders the start drawer.
34
+ * @slot end - Renders the end drawer.
35
+ *
36
+ * @attr end - Whether the end drawer is open.
37
+ * @attr end-mode - The behavior mode of the end drawer.
38
+ * @attr end-divider - Whether to show a divider between the end drawer and content for `side` mode.
39
+ * @attr start - Whether the start drawer is open.
40
+ * @attr start-mode - The behavior mode of the start drawer.
41
+ * @attr start-divider - Whether to show a divider between the start drawer and content for `side` mode.
42
+ *
43
+ * @fires change - Emitted when the state of the start or end drawers change.
44
+ *
45
+ * @cssprop --m3e-drawer-container-color - The background color of the drawer container.
46
+ * @cssprop --m3e-drawer-container-elevation - The elevation level of the drawer container.
47
+ * @cssprop --m3e-drawer-container-width - The width of the drawer container.
48
+ * @cssprop --m3e-drawer-container-scrim-opacity - The opacity of the scrim behind the drawer.
49
+ * @cssprop --m3e-modal-drawer-start-shape - The shape of the drawer’s start edge (typically left in LTR).
50
+ * @cssprop --m3e-modal-drawer-end-shape - The shape of the drawer’s end edge (typically right in LTR).
51
+ * @cssprop --m3e-modal-drawer-container-color - The background color of the modal drawer container.
52
+ * @cssprop --m3e-modal-drawer-elevation - The elevation level of the modal drawer container.
53
+ * @cssprop --m3e-drawer-divider-color - The color of the divider between drawer sections.
54
+ * @cssprop --m3e-drawer-divider-thickness - The thickness of the divider line.
55
+ */
56
+ export declare class M3eDrawerContainerElement extends M3eDrawerContainerElement_base {
57
+ #private;
58
+ /** The styles of the element. */
59
+ static styles: CSSResultGroup;
60
+ /** @private */ private _startMode;
61
+ /** @private */ private _endMode;
62
+ /**
63
+ * Whether the start drawer is open.
64
+ * @default false
65
+ */
66
+ start: boolean;
67
+ /**
68
+ * The behavior mode of the start drawer.
69
+ * @default "side"
70
+ */
71
+ startMode: DrawerMode;
72
+ /**
73
+ * Whether to show a divider between the start drawer and content for `side` mode.
74
+ * @default "side"
75
+ */
76
+ startDivider: boolean;
77
+ /**
78
+ * Whether the end drawer is open.
79
+ * @default false
80
+ */
81
+ end: boolean;
82
+ /**
83
+ * The behavior mode of the end drawer.
84
+ * @default "side"
85
+ */
86
+ endMode: DrawerMode;
87
+ /**
88
+ * Whether to show a divider between the end drawer and content for `side` mode.
89
+ * @default "side"
90
+ */
91
+ endDivider: boolean;
92
+ /** @inheritdoc */
93
+ disconnectedCallback(): void;
94
+ /** @inheritdoc */
95
+ protected update(changedProperties: PropertyValues<this>): void;
96
+ /** @inheritdoc */
97
+ protected render(): unknown;
98
+ }
99
+ declare global {
100
+ interface HTMLElementTagNameMap {
101
+ "m3e-drawer-container": M3eDrawerContainerElement;
102
+ }
103
+ }
104
+ export {};
105
+ //# sourceMappingURL=DrawerContainerElement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerContainerElement.d.ts","sourceRoot":"","sources":["../../src/DrawerContainerElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAQ,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAMvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;;AAI1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,qBACa,yBAA0B,SAAQ,8BAAwB;;IACrE,iCAAiC;IACjC,OAAgB,MAAM,EAAE,cAAc,CAAwB;IAE9D,eAAe,CAAU,OAAO,CAAC,UAAU,CAAuC;IAClF,eAAe,CAAU,OAAO,CAAC,QAAQ,CAAuC;IAMhF;;;OAGG;IACyC,KAAK,UAAS;IAE1D;;;OAGG;IACmD,SAAS,EAAE,UAAU,CAAU;IAErF;;;OAGG;IACqE,YAAY,UAAS;IAE7F;;;OAGG;IACyC,GAAG,UAAS;IAExD;;;OAGG;IACiD,OAAO,EAAE,UAAU,CAAU;IAEjF;;;OAGG;IACmE,UAAU,UAAS;IAEzF,kBAAkB;IACT,oBAAoB,IAAI,IAAI;IAOrC,kBAAkB;cACC,MAAM,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAkBxE,kBAAkB;cACC,MAAM,IAAI,OAAO;CAmGrC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,sBAAsB,EAAE,yBAAyB,CAAC;KACnD;CACF"}
@@ -0,0 +1,3 @@
1
+ /** Specifies the possible display modes for a drawer. */
2
+ export type DrawerMode = "over" | "push" | "side" | "auto";
3
+ //# sourceMappingURL=DrawerMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerMode.d.ts","sourceRoot":"","sources":["../../src/DrawerMode.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Specifies the possible positions of a drawer. */
2
+ export type DrawerPosition = "start" | "end";
3
+ //# sourceMappingURL=DrawerPosition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerPosition.d.ts","sourceRoot":"","sources":["../../src/DrawerPosition.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { CSSResultGroup, LitElement } from "lit";
2
+ declare const M3eDrawerToggleElement_base: import("node_modules/@m3e/core/dist/src/shared/mixins/Constructor").Constructor<import("@m3e/core").HtmlForMixin> & import("node_modules/@m3e/core/dist/src/shared/mixins/Constructor").Constructor & typeof LitElement;
3
+ /**
4
+ * An element, nested within a clickable element, used to toggle the opened state of a drawer.
5
+ *
6
+ * @example
7
+ * The following example illustrates the use of a `m3e-drawer-toggle`, nested inside a `m3e-icon-button` component,
8
+ * which toggles the open state of the start drawer.
9
+ *
10
+ * ```html
11
+ * <m3e-icon-button slot="leading-icon" aria-label="Menu" toggle selected>
12
+ * <m3e-drawer-toggle for="startDrawer"></m3e-drawer-toggle>
13
+ * <m3e-icon name="menu"></m3e-icon>
14
+ * <m3e-icon slot="selected" name="menu_open"></m3e-icon>
15
+ * </m3e-icon-button>
16
+ *
17
+ * <m3e-drawer-container start>
18
+ * <nav slot="start" id="startDrawer" aria-label="Navigation">
19
+ * <!-- Start drawer content -->
20
+ * </nav>
21
+ * <!-- Container content -->
22
+ * </m3e-drawer-container>
23
+ * ```
24
+ *
25
+ * @tag m3e-drawer-toggle
26
+ */
27
+ export declare class M3eDrawerToggleElement extends M3eDrawerToggleElement_base {
28
+ #private;
29
+ /** The styles of the element. */
30
+ static styles: CSSResultGroup;
31
+ /** @inheritdoc */
32
+ connectedCallback(): void;
33
+ /** @inheritdoc */
34
+ disconnectedCallback(): void;
35
+ /** @inheritdoc */
36
+ attach(control: HTMLElement): void;
37
+ /** @inheritdoc */
38
+ detach(): void;
39
+ /** @inheritdoc */
40
+ protected render(): unknown;
41
+ }
42
+ declare global {
43
+ interface HTMLElementTagNameMap {
44
+ "m3e-drawer-toggle": M3eDrawerToggleElement;
45
+ }
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=DrawerToggleElement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerToggleElement.d.ts","sourceRoot":"","sources":["../../src/DrawerToggleElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAQ,UAAU,EAAE,MAAM,KAAK,CAAC;;AAO5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBACa,sBAAuB,SAAQ,2BAAiC;;IAC3E,iCAAiC;IACjC,OAAgB,MAAM,EAAE,cAAc,CAOpC;IAKF,kBAAkB;IACT,iBAAiB,IAAI,IAAI;IAKlC,kBAAkB;IACT,oBAAoB,IAAI,IAAI;IAKrC,kBAAkB;IACT,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAU3C,kBAAkB;IACT,MAAM,IAAI,IAAI;IAKvB,kBAAkB;cACC,MAAM,IAAI,OAAO;CAwCrC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,sBAAsB,CAAC;KAC7C;CACF"}
@@ -0,0 +1,5 @@
1
+ export * from "./DrawerContainerElement";
2
+ export * from "./DrawerMode";
3
+ export * from "./DrawerPosition";
4
+ export * from "./DrawerToggleElement";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { CSSResultGroup } from "lit";
2
+ /**
3
+ * Styles for `M3eDrawerContainerElement`.
4
+ * @internal
5
+ */
6
+ export declare const DrawerContainerStyle: CSSResultGroup;
7
+ //# sourceMappingURL=DrawerContainerStyle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerContainerStyle.d.ts","sourceRoot":"","sources":["../../../src/styles/DrawerContainerStyle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,cAAc,EAAa,MAAM,KAAK,CAAC;AAMrD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAuKlC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Component design tokens that control `M3eDrawerContainerElement`.
3
+ * @internal
4
+ */
5
+ export declare const DrawerContainerToken: {
6
+ readonly containerColor: import("lit").CSSResult;
7
+ readonly containerElevation: import("lit").CSSResult;
8
+ readonly containerWidth: import("lit").CSSResult;
9
+ readonly scrimOpacity: import("lit").CSSResult;
10
+ readonly cornerShape: import("lit").CSSResult;
11
+ readonly modalContainerColor: import("lit").CSSResult;
12
+ readonly modalContainerElevation: import("lit").CSSResult;
13
+ readonly dividerColor: import("lit").CSSResult;
14
+ readonly dividerThickness: import("lit").CSSResult;
15
+ };
16
+ //# sourceMappingURL=DrawerContainerToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerContainerToken.d.ts","sourceRoot":"","sources":["../../../src/styles/DrawerContainerToken.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;CAUvB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./DrawerContainerStyle";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,13 @@
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/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@m3e/drawer-container",
3
+ "version": "1.0.0-rc.1",
4
+ "description": "Drawer Container for M3E",
5
+ "author": "matraic <matraic@yahoo.com>",
6
+ "license": "MIT",
7
+ "homepage": "https://matraic.github.io/m3e/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/matraic/m3e.git"
11
+ },
12
+ "keywords": [
13
+ "material design",
14
+ "web components",
15
+ "drawer container",
16
+ "navigation drawer"
17
+ ],
18
+ "main": "dist/index.js",
19
+ "module": "dist/index.js",
20
+ "browser": "dist/index.min.js",
21
+ "unpkg": "dist/index.min.js",
22
+ "types": "dist/src/index.d.ts",
23
+ "type": "module",
24
+ "scripts": {
25
+ "build": "rollup -c",
26
+ "cem": "cem analyze --config cem.config.mjs",
27
+ "lint": "npx eslint ./src",
28
+ "clean": "rimraf dist"
29
+ },
30
+ "peerDependencies": {
31
+ "@m3e/core": "1.0.0-rc.1",
32
+ "lit": "^3.3.0"
33
+ },
34
+ "devDependencies": {
35
+ "@custom-elements-manifest/analyzer": "^0.10.4",
36
+ "@eslint/js": "^9.30.1",
37
+ "@rollup/plugin-node-resolve": "^16.0.0",
38
+ "@rollup/plugin-terser": "^0.4.4",
39
+ "@rollup/plugin-typescript": "12.1.0",
40
+ "custom-element-vs-code-integration": "^1.5.0",
41
+ "eslint": "^9.32.0",
42
+ "rimraf": "^6.0.1",
43
+ "rollup": "^4.44.2",
44
+ "tslib": "^2.8.1",
45
+ "typescript": "~5.8.2",
46
+ "typescript-eslint": "^8.38.0"
47
+ },
48
+ "customElements": "dist/custom-elements.json"
49
+ }
@@ -0,0 +1,32 @@
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/layout", "lit"],
30
+ plugins: [resolve(), typescript()],
31
+ },
32
+ ];
@@ -0,0 +1,244 @@
1
+ import { CSSResultGroup, html, LitElement, PropertyValues } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+
4
+ import { hasAssignedNodes, Role } from "@m3e/core";
5
+ import { Breakpoint, M3eBreakpointObserver } from "@m3e/core/layout";
6
+
7
+ import { DrawerMode } from "./DrawerMode";
8
+
9
+ import { DrawerContainerStyle } from "./styles";
10
+
11
+ /**
12
+ * @summary
13
+ * A container for one or two sliding drawers.
14
+ *
15
+ * @description
16
+ * A responsive layout container that manages left and right drawers alongside main content.
17
+ * Supports `over`, `push`, `side`, and `auto` modes, adapting drawer behavior based on breakpoint size.
18
+ * Encodes spatial hierarchy, motion transitions, and accessibility semantics for modal, dismissible,
19
+ * and permanent navigation.
20
+ *
21
+ * @example
22
+ * The following example illustrates a typical drawer layout.
23
+ * ```html
24
+ * <m3e-drawer-container>
25
+ * <nav slot="start">
26
+ * <!-- Start drawer content -->
27
+ * </nav>
28
+ * <main>
29
+ * <!-- Main content -->
30
+ * </main>
31
+ * <aside slot="end">
32
+ * <!-- End drawer content -->
33
+ * </aside>
34
+ * <m3e-drawer-container>
35
+ * ```
36
+ *
37
+ * @tag m3e-drawer-container
38
+ *
39
+ * @slot - Renders the main content.
40
+ * @slot start - Renders the start drawer.
41
+ * @slot end - Renders the end drawer.
42
+ *
43
+ * @attr end - Whether the end drawer is open.
44
+ * @attr end-mode - The behavior mode of the end drawer.
45
+ * @attr end-divider - Whether to show a divider between the end drawer and content for `side` mode.
46
+ * @attr start - Whether the start drawer is open.
47
+ * @attr start-mode - The behavior mode of the start drawer.
48
+ * @attr start-divider - Whether to show a divider between the start drawer and content for `side` mode.
49
+ *
50
+ * @fires change - Emitted when the state of the start or end drawers change.
51
+ *
52
+ * @cssprop --m3e-drawer-container-color - The background color of the drawer container.
53
+ * @cssprop --m3e-drawer-container-elevation - The elevation level of the drawer container.
54
+ * @cssprop --m3e-drawer-container-width - The width of the drawer container.
55
+ * @cssprop --m3e-drawer-container-scrim-opacity - The opacity of the scrim behind the drawer.
56
+ * @cssprop --m3e-modal-drawer-start-shape - The shape of the drawer’s start edge (typically left in LTR).
57
+ * @cssprop --m3e-modal-drawer-end-shape - The shape of the drawer’s end edge (typically right in LTR).
58
+ * @cssprop --m3e-modal-drawer-container-color - The background color of the modal drawer container.
59
+ * @cssprop --m3e-modal-drawer-elevation - The elevation level of the modal drawer container.
60
+ * @cssprop --m3e-drawer-divider-color - The color of the divider between drawer sections.
61
+ * @cssprop --m3e-drawer-divider-thickness - The thickness of the divider line.
62
+ */
63
+ @customElement("m3e-drawer-container")
64
+ export class M3eDrawerContainerElement extends Role(LitElement, "none") {
65
+ /** The styles of the element. */
66
+ static override styles: CSSResultGroup = DrawerContainerStyle;
67
+
68
+ /** @private */ @state() private _startMode: Exclude<DrawerMode, "auto"> = "side";
69
+ /** @private */ @state() private _endMode: Exclude<DrawerMode, "auto"> = "side";
70
+ /** @private */ #breakpointUnobserve?: () => void;
71
+ /** @private */ #disableStartFocusTrap = false;
72
+ /** @private */ #disableEndFocusTrap = false;
73
+ /** @private */ #initialized = false;
74
+
75
+ /**
76
+ * Whether the start drawer is open.
77
+ * @default false
78
+ */
79
+ @property({ type: Boolean, reflect: true }) start = false;
80
+
81
+ /**
82
+ * The behavior mode of the start drawer.
83
+ * @default "side"
84
+ */
85
+ @property({ attribute: "start-mode", reflect: true }) startMode: DrawerMode = "side";
86
+
87
+ /**
88
+ * Whether to show a divider between the start drawer and content for `side` mode.
89
+ * @default "side"
90
+ */
91
+ @property({ attribute: "start-divider", type: Boolean, reflect: true }) startDivider = false;
92
+
93
+ /**
94
+ * Whether the end drawer is open.
95
+ * @default false
96
+ */
97
+ @property({ type: Boolean, reflect: true }) end = false;
98
+
99
+ /**
100
+ * The behavior mode of the end drawer.
101
+ * @default "side"
102
+ */
103
+ @property({ attribute: "end-mode", reflect: true }) endMode: DrawerMode = "side";
104
+
105
+ /**
106
+ * Whether to show a divider between the end drawer and content for `side` mode.
107
+ * @default "side"
108
+ */
109
+ @property({ attribute: "end-divider", type: Boolean, reflect: true }) endDivider = false;
110
+
111
+ /** @inheritdoc */
112
+ override disconnectedCallback(): void {
113
+ super.disconnectedCallback();
114
+
115
+ this.#breakpointUnobserve?.();
116
+ this.#clearMode();
117
+ }
118
+
119
+ /** @inheritdoc */
120
+ protected override update(changedProperties: PropertyValues<this>): void {
121
+ super.update(changedProperties);
122
+
123
+ if (changedProperties.has("startMode") || changedProperties.has("endMode")) {
124
+ this.#breakpointUnobserve?.();
125
+
126
+ if (this.startMode === "auto" || this.endMode === "auto") {
127
+ this.#breakpointUnobserve = M3eBreakpointObserver.observe([Breakpoint.XSmall, Breakpoint.Small], (matches) =>
128
+ this.#updateMode(matches, this.#initialized)
129
+ );
130
+ } else {
131
+ this.#updateMode();
132
+ }
133
+ }
134
+
135
+ this.#initialized = true;
136
+ }
137
+
138
+ /** @inheritdoc */
139
+ protected override render(): unknown {
140
+ return html`<m3e-focus-trap ?disabled="${!this.start || this._startMode === "side" || this.#disableStartFocusTrap}">
141
+ <slot name="start" @slotchange="${this.#handleStartSlotChange}"></slot>
142
+ </m3e-focus-trap>
143
+ <div
144
+ class="content"
145
+ .inert="${(this._startMode !== "side" || this._endMode !== "side") && (this.start || this.end)}"
146
+ >
147
+ <slot></slot>
148
+ </div>
149
+ <div class="scrim" @click="${this.#handleScrimClick}"></div>
150
+ <m3e-focus-trap ?disabled="${!this.end || this._endMode === "side" || this.#disableEndFocusTrap}">
151
+ <slot name="end" @slotchange="${this.#handleEndSlotChange}"></slot>
152
+ </m3e-focus-trap>`;
153
+ }
154
+
155
+ /** @private */
156
+ #handleScrimClick() {
157
+ if (this._startMode !== "side") {
158
+ this.start = false;
159
+ }
160
+ if (this._endMode !== "side") {
161
+ this.end = false;
162
+ }
163
+ this.dispatchEvent(new Event("change", { bubbles: true }));
164
+ }
165
+
166
+ /** @private */
167
+ #handleStartSlotChange(e: Event): void {
168
+ this.#disableStartFocusTrap = !hasAssignedNodes(<HTMLSlotElement>e.target);
169
+ }
170
+
171
+ /** @private */
172
+ #handleEndSlotChange(e: Event): void {
173
+ this.#disableEndFocusTrap = !hasAssignedNodes(<HTMLSlotElement>e.target);
174
+ }
175
+
176
+ /** @inheritdoc */
177
+ #clearMode(): void {
178
+ this.classList.remove("-start-over");
179
+ this.classList.remove("-start-push");
180
+ this.classList.remove("-start-side");
181
+ this.classList.remove("-end-over");
182
+ this.classList.remove("-end-push");
183
+ this.classList.remove("-end-side");
184
+ }
185
+
186
+ /** @inheritdoc */
187
+ #updateMode(breakpoints?: Map<string, boolean>, autoClose = false) {
188
+ let autoCloseStart = false,
189
+ autoCloseEnd = false;
190
+ if (this.startMode === "auto") {
191
+ if (breakpoints?.get(Breakpoint.Medium)) {
192
+ this._startMode = "side";
193
+ } else if (breakpoints?.get(Breakpoint.Small)) {
194
+ autoCloseStart = this._startMode === "side" && this.start;
195
+ this._startMode = "push";
196
+ } else if (breakpoints?.get(Breakpoint.XSmall)) {
197
+ autoCloseStart = this._startMode !== "over" && this.start;
198
+ this._startMode = "over";
199
+ } else {
200
+ this._startMode = "side";
201
+ }
202
+ } else {
203
+ this._startMode = this.startMode;
204
+ }
205
+
206
+ if (this.endMode === "auto") {
207
+ if (breakpoints?.get(Breakpoint.Medium)) {
208
+ this._endMode = "side";
209
+ } else if (breakpoints?.get(Breakpoint.Small)) {
210
+ autoCloseEnd = this._endMode === "side" && this.end;
211
+ this._endMode = "push";
212
+ } else if (breakpoints?.get(Breakpoint.XSmall)) {
213
+ autoCloseEnd = this._endMode !== "over" && this.end;
214
+ this._endMode = "over";
215
+ } else {
216
+ this._endMode = "side";
217
+ }
218
+ } else {
219
+ this._endMode = this.endMode;
220
+ }
221
+
222
+ this.#clearMode();
223
+
224
+ this.classList.add(`-start-${this._startMode}`);
225
+ this.classList.add(`-end-${this._endMode}`);
226
+
227
+ if (autoClose && (autoCloseStart || autoCloseEnd)) {
228
+ if (autoCloseStart) {
229
+ this.start = false;
230
+ }
231
+ if (autoCloseEnd) {
232
+ this.end = false;
233
+ }
234
+
235
+ this.dispatchEvent(new Event("change", { bubbles: true }));
236
+ }
237
+ }
238
+ }
239
+
240
+ declare global {
241
+ interface HTMLElementTagNameMap {
242
+ "m3e-drawer-container": M3eDrawerContainerElement;
243
+ }
244
+ }
@@ -0,0 +1,2 @@
1
+ /** Specifies the possible display modes for a drawer. */
2
+ export type DrawerMode = "over" | "push" | "side" | "auto";
@@ -0,0 +1,2 @@
1
+ /** Specifies the possible positions of a drawer. */
2
+ export type DrawerPosition = "start" | "end";