@m3e/tabs 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.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 matraic
4
+ Contact: matraic@yahoo.com
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # @m3e/tabs
2
+
3
+ The `m3e-tabs` component provides a structured navigation surface for organizing content into distinct views, where only one view is visible at a time. It supports scrollable tab headers with optional pagination, accessible labeling for navigation controls, and configurable header positioning to suit various layout contexts. Two visual variants are available: `primary`, which emphasizes active indicators and shape styling for prominent navigation, and `secondary`, which offers a more subtle presentation with reduced indicator thickness. Stretch behavior allows tabs to expand and align rhythmically within their container, consistent with Material 3 guidance.
4
+
5
+ > **Part of the [M3E](../../README.md) monorepo**
6
+ > This package is maintained within the unified M3E repository, which provides a suite of Material 3 web components.
7
+
8
+ ## 📦 Installation
9
+
10
+ ```bash
11
+ npm install @m3e/tabs
12
+ ```
13
+
14
+ ## 💻 Editor Integration
15
+
16
+ This package includes a [Custom Elements Manifest](https://github.com/webcomponents/custom-elements-manifest) to support enhanced editor tooling and developer experience.
17
+
18
+ ### Visual Studio Code
19
+
20
+ To enable autocomplete and hover documentation for `@m3e/tabs`, install the [Custom Elements Manifest Language Server](https://marketplace.visualstudio.com/items?itemName=pwrs.cem-language-server-vscode) extension. It will automatically detect the manifest bundled with this package and surface tag names, attributes, slots, and events in supported files.
21
+
22
+ Alternately, you can explicitly reference the `html-custom-data.json` and `css-custom-data.json` in your workspace settings:
23
+
24
+ ```json
25
+ {
26
+ "html.customData": ["./node_modules/@m3e/tabs/dist/html-custom-data.json"],
27
+ "css.customData": ["./node_modules/@m3e/tabs/dist/css-custom-data.json"]
28
+ }
29
+ ```
30
+
31
+ ## 🚀 Browser Usage
32
+
33
+ This package uses [JavaScript Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#module_specifiers). To use it directly in a browser without a bundler, use a module script similar to the following.
34
+
35
+ ```html
36
+ <script type="module" src="/node_modules/@m3e/tabs/dist/index.js"></script>
37
+ ```
38
+
39
+ You also need a module script for `@m3e/icon-button` and `m3e/slide-group` due to these being a dependency.
40
+
41
+ ```html
42
+ <script type="module" src="/node_modules/@m3e/icon-button/dist/index.js"></script>
43
+ <script type="module" src="/node_modules/@m3e/slide-group/dist/index.js"></script>
44
+ ```
45
+
46
+ In addition, you must use an [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap) to include dependencies.
47
+
48
+ ```html
49
+ <script type="importmap">
50
+ {
51
+ "imports": {
52
+ "lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
53
+ "@m3e/core": "/node_modules/@m3e/core/dist/index.js",
54
+ "@m3e/core/a11y": "/node_modules/@m3e/core/dist/a11y.js"
55
+ }
56
+ }
57
+ </script>
58
+ ```
59
+
60
+ > For production, use index.min.js and a11y.min.js for faster load times.
61
+
62
+ ## 🗂️ Elements
63
+
64
+ - `m3e-tabs` — Organizes content into separate views where only one view can be visible at a time.
65
+ - `m3e-tab` — An interactive element that, when activated, presents an associated tab panel.
66
+ - `m3e-tab-panel` — A panel presented for a tab.
67
+
68
+ ## 🧪 Examples
69
+
70
+ The following example illustrates using the `m3e-tabs`, `m3e-tab`, and `m3e-tab-panel` components to present secondary tabs.
71
+
72
+ ```html
73
+ <m3e-tabs>
74
+ <m3e-tab selected for="videos"><m3e-icon slot="icon" name="videocam"></m3e-icon>Video</m3e-tab>
75
+ <m3e-tab for="photos"><m3e-icon slot="icon" name="photo"></m3e-icon>Photos</m3e-tab>
76
+ <m3e-tab for="audio"><m3e-icon slot="icon" name="music_note"></m3e-icon>Audio</m3e-tab>
77
+ <m3e-tab-panel id="videos">Videos</m3e-tab-panel>
78
+ <m3e-tab-panel id="photos">Photos</m3e-tab-panel>
79
+ <m3e-tab-panel id="audio">Audio</m3e-tab-panel>
80
+ </m3e-tabs>
81
+ ```
82
+
83
+ ## 📖 API Reference
84
+
85
+ ### 🗂️ m3e-tabs
86
+
87
+ This section details the attributes, events, slots and CSS custom properties available for the `m3e-tabs` component.
88
+
89
+ #### ⚙️ Attributes
90
+
91
+ | Attribute | Type | Default | Description |
92
+ | --------------------- | ---------------------------- | ----------------- | --------------------------------------------------------------------------- |
93
+ | `disable-pagination` | `boolean` | `false` | Whether scroll buttons are disabled. |
94
+ | `header-position` | `"before"` \| `"after"` | `"before"` | The position of the tab headers. |
95
+ | `next-page-label` | `string` | `"Next page"` | The accessible label given to the button used to move to the previous page. |
96
+ | `previous-page-label` | `string` | `"Previous page"` | The accessible label given to the button used to move to the next page. |
97
+ | `stretch` | `boolean` | `false` | Whether tabs are stretched to fill the header. |
98
+ | `variant` | `"primary"` \| `"secondary"` | `"secondary"` | The appearance variant of the tabs. |
99
+
100
+ #### 🔔 Events
101
+
102
+ | Event | Description |
103
+ | -------- | -------------------------------------- |
104
+ | `change` | Emitted when the selected tab changes. |
105
+
106
+ #### 🧩 Slots
107
+
108
+ | Slot | Description |
109
+ | ----------- | --------------------------------------------------------------------- |
110
+ | _(default)_ | Renders the tabs. |
111
+ | `panel` | Renders the panels of the tabs. |
112
+ | `next-icon` | Renders the icon to present for the next button used to paginate. |
113
+ | `prev-icon` | Renders the icon to present for the previous button used to paginate. |
114
+
115
+ #### 🎛️ CSS Custom Properties
116
+
117
+ | Property | Description |
118
+ | -------------------------------------------------- | -------------------------------------------------------------------------------- |
119
+ | `--m3e-tabs-paginator-button-icon-size` | Overrides the icon size for paginator buttons. |
120
+ | `--m3e-tabs-active-indicator-color` | Color of the active tab indicator. |
121
+ | `--m3e-tabs-primary-before-active-indicator-shape` | Border radius for active indicator when header is before and variant is primary. |
122
+ | `--m3e-tabs-primary-after-active-indicator-shape` | Border radius for active indicator when header is after and variant is primary. |
123
+ | `--m3e-tabs-primary-active-indicator-inset` | Inset for primary variant's active indicator. |
124
+ | `--m3e-tabs-primary-active-indicator-thickness` | Thickness for primary variant's active indicator. |
125
+ | `--m3e-tabs-secondary-active-indicator-thickness` | Thickness for secondary variant's active indicator. |
126
+
127
+ ### 🗂️ m3e-tab
128
+
129
+ This section details the attributes, slots and CSS custom properties available for the `m3e-tab` component.
130
+
131
+ #### ⚙️ Attributes
132
+
133
+ | Attribute | Type | Default | Description |
134
+ | ---------- | --------- | ------- | ----------------------------------------------------------------------- |
135
+ | `disabled` | `boolean` | `false` | Whether the element is disabled. |
136
+ | `for` | `string` | | The query selector used to specify the element related to this element. |
137
+ | `selected` | `boolean` | `false` | Whether the element is selected. |
138
+
139
+ #### 🧩 Slots
140
+
141
+ | Slot | Description |
142
+ | ----------- | --------------------------------------- |
143
+ | _(default)_ | Renders the label of the tab. |
144
+ | `icon` | Renders an icon before the tab's label. |
145
+
146
+ #### 🎛️ CSS Custom Properties
147
+
148
+ | Property | Description |
149
+ | -------------------------------------------- | ------------------------------------------- |
150
+ | `--m3e-tab-font-size` | Font size for tab label. |
151
+ | `--m3e-tab-font-weight` | Font weight for tab label. |
152
+ | `--m3e-tab-line-height` | Line height for tab label. |
153
+ | `--m3e-tab-tracking` | Letter spacing for tab label. |
154
+ | `--m3e-tab-padding-start` | Padding on the inline start of the tab. |
155
+ | `--m3e-tab-padding-end` | Padding on the inline end of the tab. |
156
+ | `--m3e-tab-focus-ring-shape` | Border radius for the focus ring. |
157
+ | `--m3e-tab-selected-color` | Text color for selected tab. |
158
+ | `--m3e-tab-selected-container-hover-color` | Hover state-layer color for selected tab. |
159
+ | `--m3e-tab-selected-container-focus-color` | Focus state-layer color for selected tab. |
160
+ | `--m3e-tab-selected-ripple-color` | Ripple color for selected tab. |
161
+ | `--m3e-tab-unselected-color` | Text color for unselected tab. |
162
+ | `--m3e-tab-unselected-container-hover-color` | Hover state-layer color for unselected tab. |
163
+ | `--m3e-tab-unselected-container-focus-color` | Focus state-layer color for unselected tab. |
164
+ | `--m3e-tab-unselected-ripple-color` | Ripple color for unselected tab. |
165
+ | `--m3e-tab-disabled-color` | Text color for disabled tab. |
166
+ | `--m3e-tab-disabled-opacity` | Text opacity for disabled tab. |
167
+ | `--m3e-tab-spacing` | Column gap between icon and label. |
168
+ | `--m3e-tab-icon-size` | Font size for slotted icon. |
169
+
170
+ ### 🗂️ m3e-tab-panel
171
+
172
+ This section details the slots available for the `m3e-tab-panel` component.
173
+
174
+ #### 🧩 Slots
175
+
176
+ | Slot | Description |
177
+ | ----------- | --------------------------------- |
178
+ | _(default)_ | Renders the content of the panel. |
179
+
180
+ ## 🤝 Contributing
181
+
182
+ See the root monorepo `CONTRIBUTING.md` for guidelines on contributing to this package.
183
+
184
+ ## 📄 License
185
+
186
+ This package is licensed under the MIT License.
package/cem.config.mjs ADDED
@@ -0,0 +1,16 @@
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
+ };
@@ -0,0 +1,103 @@
1
+ <!doctype html>
2
+ <html lang="en" style="overflow-y: auto">
3
+ <head>
4
+ <title>Tabs for M3E</title>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <meta name="description" content="Tabs 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
+ }
26
+ }
27
+ </script>
28
+ <script type="module" src="../../theme/dist/index.min.js"></script>
29
+ <script type="module" src="../../icon/dist/index.min.js"></script>
30
+ <script type="module" src="../../icon-button/dist/index.min.js"></script>
31
+ <script type="module" src="../../slide-group/dist/index.min.js"></script>
32
+ <script type="module" src="../dist/index.min.js"></script>
33
+ <style>
34
+ body {
35
+ font-family: "Roboto";
36
+ }
37
+ *:not(:defined) {
38
+ display: none;
39
+ }
40
+ label {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ justify-content: space-between;
44
+ width: 400px;
45
+ margin-bottom: 1rem;
46
+ }
47
+ </style>
48
+ </head>
49
+ <body>
50
+ <m3e-theme strong-focus motion="expressive">
51
+ <m3e-tabs>
52
+ <m3e-tab selected for="videos"><m3e-icon slot="icon" name="videocam"></m3e-icon>Video</m3e-tab>
53
+ <m3e-tab for="photos"><m3e-icon slot="icon" name="photo"></m3e-icon>Photos</m3e-tab>
54
+ <m3e-tab for="audio"><m3e-icon slot="icon" name="music_note"></m3e-icon>Audio</m3e-tab>
55
+ <m3e-tab-panel id="videos">Videos</m3e-tab-panel>
56
+ <m3e-tab-panel id="photos">Photos</m3e-tab-panel>
57
+ <m3e-tab-panel id="audio">Audio</m3e-tab-panel>
58
+ </m3e-tabs>
59
+ <br />
60
+ <m3e-tabs>
61
+ <m3e-tab selected for="t1"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 1</m3e-tab>
62
+ <m3e-tab for="t2" disabled><m3e-icon slot="icon" name="face"></m3e-icon>Disabled tab</m3e-tab>
63
+ <m3e-tab for="t3"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 3</m3e-tab>
64
+ <m3e-tab-panel id="t1">Tab 1</m3e-tab-panel>
65
+ <m3e-tab-panel id="t2">Tab 2</m3e-tab-panel>
66
+ <m3e-tab-panel id="t3">Tab 3</m3e-tab-panel>
67
+ </m3e-tabs>
68
+ <m3e-tabs stretch>
69
+ <m3e-tab selected for="t4"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 1</m3e-tab>
70
+ <m3e-tab for="t5"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 2</m3e-tab>
71
+ <m3e-tab for="t6"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 3</m3e-tab>
72
+ <m3e-tab-panel id="t4">Tab 1</m3e-tab-panel>
73
+ <m3e-tab-panel id="t5">Tab 2</m3e-tab-panel>
74
+ <m3e-tab-panel id="t6">Tab 3</m3e-tab-panel>
75
+ </m3e-tabs>
76
+ <m3e-tabs header-position="after">
77
+ <m3e-tab selected for="t7"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 1</m3e-tab>
78
+ <m3e-tab for="t8"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 2</m3e-tab>
79
+ <m3e-tab for="t9"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 3</m3e-tab>
80
+ <m3e-tab-panel id="t7">Tab 1</m3e-tab-panel>
81
+ <m3e-tab-panel id="t8">Tab 2</m3e-tab-panel>
82
+ <m3e-tab-panel id="t9">Tab 3</m3e-tab-panel>
83
+ </m3e-tabs>
84
+ <m3e-tabs variant="primary">
85
+ <m3e-tab selected for="t10"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 1</m3e-tab>
86
+ <m3e-tab for="t11"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 2</m3e-tab>
87
+ <m3e-tab for="t12"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 3</m3e-tab>
88
+ <m3e-tab-panel id="t10">Tab 1</m3e-tab-panel>
89
+ <m3e-tab-panel id="t11">Tab 2</m3e-tab-panel>
90
+ <m3e-tab-panel id="t12">Tab 3</m3e-tab-panel>
91
+ </m3e-tabs>
92
+ <br />
93
+ <m3e-tabs variant="primary" header-position="after">
94
+ <m3e-tab selected for="t13"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 1</m3e-tab>
95
+ <m3e-tab for="t14"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 2</m3e-tab>
96
+ <m3e-tab for="t15"><m3e-icon slot="icon" name="face"></m3e-icon>Tab 3</m3e-tab>
97
+ <m3e-tab-panel id="t13">Tab 1</m3e-tab-panel>
98
+ <m3e-tab-panel id="t14">Tab 2</m3e-tab-panel>
99
+ <m3e-tab-panel id="t15">Tab 3</m3e-tab-panel>
100
+ </m3e-tabs>
101
+ </m3e-theme>
102
+ </body>
103
+ </html>
@@ -0,0 +1,137 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/main/docs/customData.schema.json",
3
+ "version": 1.1,
4
+ "properties": [
5
+ {
6
+ "name": "--m3e-tab-font-size",
7
+ "description": "Font size for tab label.",
8
+ "values": []
9
+ },
10
+ {
11
+ "name": "--m3e-tab-font-weight",
12
+ "description": "Font weight for tab label.",
13
+ "values": []
14
+ },
15
+ {
16
+ "name": "--m3e-tab-line-height",
17
+ "description": "Line height for tab label.",
18
+ "values": []
19
+ },
20
+ {
21
+ "name": "--m3e-tab-tracking",
22
+ "description": "Letter spacing for tab label.",
23
+ "values": []
24
+ },
25
+ {
26
+ "name": "--m3e-tab-padding-start",
27
+ "description": "Padding on the inline start of the tab.",
28
+ "values": []
29
+ },
30
+ {
31
+ "name": "--m3e-tab-padding-end",
32
+ "description": "Padding on the inline end of the tab.",
33
+ "values": []
34
+ },
35
+ {
36
+ "name": "--m3e-tab-focus-ring-shape",
37
+ "description": "Border radius for the focus ring.",
38
+ "values": []
39
+ },
40
+ {
41
+ "name": "--m3e-tab-selected-color",
42
+ "description": "Text color for selected tab.",
43
+ "values": []
44
+ },
45
+ {
46
+ "name": "--m3e-tab-selected-container-hover-color",
47
+ "description": "Hover state-layer color for selected tab.",
48
+ "values": []
49
+ },
50
+ {
51
+ "name": "--m3e-tab-selected-container-focus-color",
52
+ "description": "Focus state-layer color for selected tab.",
53
+ "values": []
54
+ },
55
+ {
56
+ "name": "--m3e-tab-selected-ripple-color",
57
+ "description": "Ripple color for selected tab.",
58
+ "values": []
59
+ },
60
+ {
61
+ "name": "--m3e-tab-unselected-color",
62
+ "description": "Text color for unselected tab.",
63
+ "values": []
64
+ },
65
+ {
66
+ "name": "--m3e-tab-unselected-container-hover-color",
67
+ "description": "Hover state-layer color for unselected tab.",
68
+ "values": []
69
+ },
70
+ {
71
+ "name": "--m3e-tab-unselected-container-focus-color",
72
+ "description": "Focus state-layer color for unselected tab.",
73
+ "values": []
74
+ },
75
+ {
76
+ "name": "--m3e-tab-unselected-ripple-color",
77
+ "description": "Ripple color for unselected tab.",
78
+ "values": []
79
+ },
80
+ {
81
+ "name": "--m3e-tab-disabled-color",
82
+ "description": "Text color for disabled tab.",
83
+ "values": []
84
+ },
85
+ {
86
+ "name": "--m3e-tab-disabled-opacity",
87
+ "description": "Text opacity for disabled tab.",
88
+ "values": []
89
+ },
90
+ {
91
+ "name": "--m3e-tab-spacing",
92
+ "description": "Column gap between icon and label.",
93
+ "values": []
94
+ },
95
+ {
96
+ "name": "--m3e-tab-icon-size",
97
+ "description": "Font size for slotted icon.",
98
+ "values": []
99
+ },
100
+ {
101
+ "name": "--m3e-tabs-paginator-button-icon-size",
102
+ "description": "Overrides the icon size for paginator buttons.",
103
+ "values": []
104
+ },
105
+ {
106
+ "name": "--m3e-tabs-active-indicator-color",
107
+ "description": "Color of the active tab indicator.",
108
+ "values": []
109
+ },
110
+ {
111
+ "name": "--m3e-tabs-primary-before-active-indicator-shape",
112
+ "description": "Border radius for active indicator when header is before and variant is primary.",
113
+ "values": []
114
+ },
115
+ {
116
+ "name": "--m3e-tabs-primary-after-active-indicator-shape",
117
+ "description": "Border radius for active indicator when header is after and variant is primary.",
118
+ "values": []
119
+ },
120
+ {
121
+ "name": "--m3e-tabs-primary-active-indicator-inset",
122
+ "description": "Inset for primary variant's active indicator.",
123
+ "values": []
124
+ },
125
+ {
126
+ "name": "--m3e-tabs-primary-active-indicator-thickness",
127
+ "description": "Thickness for primary variant's active indicator.",
128
+ "values": []
129
+ },
130
+ {
131
+ "name": "--m3e-tabs-secondary-active-indicator-thickness",
132
+ "description": "Thickness for secondary variant's active indicator.",
133
+ "values": []
134
+ }
135
+ ],
136
+ "pseudoElements": []
137
+ }