material-inspired-component-library 1.2.2 → 2.0.0

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 (59) hide show
  1. package/README.md +18 -0
  2. package/components/badge/README.md +65 -0
  3. package/components/badge/index.scss +68 -0
  4. package/components/button/README.md +1 -1
  5. package/components/button/index.scss +60 -89
  6. package/components/button/index.ts +5 -0
  7. package/components/card/index.scss +29 -30
  8. package/components/checkbox/index.scss +1 -6
  9. package/components/dialog/index.scss +11 -7
  10. package/components/iconbutton/README.md +1 -1
  11. package/components/iconbutton/index.scss +46 -80
  12. package/components/iconbutton/index.ts +5 -0
  13. package/components/list/index.scss +39 -30
  14. package/components/list/index.ts +10 -9
  15. package/components/menu/README.md +67 -4
  16. package/components/menu/index.scss +29 -29
  17. package/components/menu/index.ts +47 -16
  18. package/components/navigationrail/README.md +150 -0
  19. package/components/navigationrail/index.scss +468 -0
  20. package/components/{checkbox → navigationrail}/index.ts +12 -7
  21. package/components/radio/index.scss +22 -12
  22. package/components/select/index.scss +5 -11
  23. package/components/textfield/index.scss +8 -2
  24. package/dist/badge.css +1 -0
  25. package/dist/badge.js +1 -0
  26. package/dist/bottomsheet.css +1 -1
  27. package/dist/button.css +1 -1
  28. package/dist/card.css +1 -1
  29. package/dist/checkbox.css +1 -1
  30. package/dist/components/menu/index.d.ts +0 -11
  31. package/dist/components/navigationrail/index.d.ts +5 -0
  32. package/dist/dialog.css +1 -1
  33. package/dist/iconbutton.css +1 -1
  34. package/dist/list.css +1 -1
  35. package/dist/menu.css +1 -1
  36. package/dist/micl.css +1 -1
  37. package/dist/micl.js +1 -1
  38. package/dist/navigationrail.css +1 -0
  39. package/dist/navigationrail.js +1 -0
  40. package/dist/radio.css +1 -1
  41. package/dist/select.css +1 -1
  42. package/dist/slider.css +1 -1
  43. package/dist/switch.css +1 -1
  44. package/dist/textfield.css +1 -1
  45. package/docs/button.html +5 -5
  46. package/docs/docs.css +2 -1
  47. package/docs/docs.js +2 -2
  48. package/docs/index.html +35 -2
  49. package/docs/menu.html +183 -3
  50. package/docs/micl.css +1 -1
  51. package/docs/micl.js +1 -1
  52. package/docs/navigationrail.html +81 -0
  53. package/micl.ts +20 -25
  54. package/package.json +10 -7
  55. package/styles/statelayer.scss +14 -0
  56. package/styles.scss +18 -1
  57. package/webpack.config.js +37 -0
  58. package/dist/components/checkbox/index.d.ts +0 -5
  59. package/styles/ripple.scss +0 -50
@@ -0,0 +1,150 @@
1
+ # Navigation rail
2
+ This component implements the the [Material Design 3 Expressive Navigation rail](https://m3.material.io/components/navigation-rail/overview) design.
3
+
4
+ ## Basic Usage
5
+
6
+ ### HTML
7
+ To create a simple navigation rail, use a `<div>` element with the `micl-navigationrail` class. Inside, use an `input type="radio"` group to create the selectable navigation items. The `input` elements must share the same `name` attribute to ensure that only one item can be selected at a time. The `label` elements are associated with their respective inputs using the `for` attribute.
8
+
9
+ ```HTML
10
+ <div id="mynavigationrail" class="micl-navigationrail">
11
+ <div class="micl-navigationrail__content">
12
+ <input type="radio" id="item1" name="navitem" value="email_inbox" checked>
13
+ <label for="item1" class="micl-navigationrail__item" tabindex="0">
14
+ <span class="micl-navigationrail__icon material-symbols-outlined" aria-hidden="true">inbox</span>
15
+ <span class="micl-navigationrail__text">Inbox</span>
16
+ </label>
17
+ <input type="radio" id="item2" name="navitem" value="email_outbox">
18
+ <label for="item2" class="micl-navigationrail__item" tabindex="0">
19
+ <span class="micl-navigationrail__icon material-symbols-outlined" aria-hidden="true">outbox</span>
20
+ <span class="micl-navigationrail__text">Outbox</span>
21
+ </label>
22
+ </div>
23
+ </div>
24
+ ```
25
+
26
+ ### CSS
27
+ Import the navigation rail styles into your project:
28
+
29
+ ```CSS
30
+ @use "material-inspired-component-library/dist/navigationrail";
31
+ ```
32
+
33
+ ### JavaScript
34
+ This component requires JavaScript to support keyboard navigation. The library will automatically initialize new components as they're added to the DOM.
35
+
36
+ ```JavaScript
37
+ import micl from "material-inspired-component-library/dist/micl";
38
+ ```
39
+
40
+ ### Demo
41
+ A live example of the [Navigation rail component](https://henkpb.github.io/micl/navigationrail.html) is available for you to interact with.
42
+
43
+ ## Variants
44
+ The basic example creates a **collapsed** navigation rail. Add a menu button to allow the user to toggle between a **collapsed** and an **expanded** view.
45
+
46
+ ```HTML
47
+ <div id="mynavigationrail" class="micl-navigationrail">
48
+ <div class="micl-navigationrail__headline">
49
+ <button
50
+ type="button"
51
+ class="micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined"
52
+ data-miclalt="menu_open"
53
+ aria-label="Toggle navigation rail"
54
+ >menu</button>
55
+ </div>
56
+ <div class="micl-navigationrail__content">
57
+ ...
58
+ </div>
59
+ </div>
60
+ ```
61
+
62
+ When the user clicks the menu button, the navigation rail is expanded and the toggle button is given the `micl-button--selected` class and the `micl-button--toggled` class that indicates that the toggle button has been clicked at least once.
63
+
64
+ ### Popover expanded navigation rail
65
+
66
+ Add the `popover` attribute to the navigation rail, and the `popovertarget` attribute to the menu button. The value of the `popovertarget` attribute must be the `id` of the navigation rail.
67
+
68
+ ```HTML
69
+ <div id="mynavigationrail" class="micl-navigationrail" popover="manual">
70
+ <div class="micl-navigationrail__headline">
71
+ <button
72
+ type="button"
73
+ class="micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined"
74
+ popovertarget="mynavigationrail"
75
+ data-miclalt="menu_open"
76
+ aria-label="Toggle navigation rail"
77
+ >menu</button>
78
+ </div>
79
+ <div class="micl-navigationrail__content">
80
+ ...
81
+ </div>
82
+ </div>
83
+ ```
84
+
85
+ [!WARNING]
86
+ The **popover** navigation rail component adds CSS rules to the `<body>` element to properly resize the main content area when the navigation rail is collapsed. Overriding these rules may cause the component to behave unexpectedly. The rules that are applied are:
87
+
88
+ ```CSS
89
+ margin-inline-start: var(--md-sys-navigationrail-collapsed-width);
90
+ ```
91
+
92
+ ### Modal navigation rail
93
+
94
+ A **modal** navigation rail is hidden until the user clicks a menu button. When shown, the **expanded** navigation rail is displayed on top of other page content. Use a `<dialog>` element instead of a `<div>`.
95
+
96
+ ```HTML
97
+ <dialog id="mynavigationrail" class="micl-navigationrail" closedby="closerequest">
98
+ <div class="micl-navigationrail__headline">
99
+ <button
100
+ type="button"
101
+ class="micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined"
102
+ popovertarget="mynavigationrail"
103
+ data-miclalt="menu_open"
104
+ aria-label="Toggle navigation rail"
105
+ >menu</button>
106
+ </div>
107
+ <div class="micl-navigationrail__content">
108
+ ...
109
+ </div>
110
+ </dialog>
111
+
112
+ <button
113
+ type="button"
114
+ class="micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined"
115
+ popovertarget="mynavigationrail"
116
+ aria-label="Toggle navigation rail"
117
+ >menu</button>
118
+ ```
119
+
120
+ The button inside the navigation rail is used to hide the navigation rail, while the button outside is responsible for opening it.
121
+
122
+ ## Customizations
123
+ You can customize the appearance of the Navigation rail component by overriding its global CSS variables. These variables are declared on the `:root` pseudo-class and can be changed on any appropriate parent element to affect its child navigation rails.
124
+
125
+ | Variable name | Default Value | Description |
126
+ | ------------- | ------------- | ----------- |
127
+ | --md-sys-navigationrail-collapsed-width | 96px | The width of the collapsed navigation rail |
128
+ | --md-sys-navigationrail-expanded-maxwidth | 360px | The largest allowed width of the expanded navigation rail |
129
+ | --md-sys-navigationrail-expanded-minwidth | 220px | The smallest allowed width of the expanded navigation rail |
130
+
131
+ **Example: Changing the width of the collapsed navigation rail**
132
+
133
+ ```HTML
134
+ <div style="--md-sys-navigationrail-collapsed-width:80px">
135
+ <div id="mynavigationrail" class="micl-navigationrail">
136
+ ...
137
+ </div>
138
+ </div>
139
+ ```
140
+
141
+ To add a vertical divider of the to the navigation rail, assign one to the following CSS variable:
142
+
143
+ ```CSS
144
+ #mynavigationrail {
145
+ --md-sys-divider-thickness: 1;
146
+ }
147
+ ```
148
+
149
+ ## Compatibility
150
+ This component uses the Popover API, which might not be supported in all browsers. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API#api.htmlelement.popover) for details.
@@ -0,0 +1,468 @@
1
+ //
2
+ // Copyright © 2025 Hermana AS
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+
22
+ @use '../../styles/elevation';
23
+ @use '../../styles/motion';
24
+ @use '../../styles/shapes';
25
+ @use '../../styles/statelayer';
26
+ @use '../../styles/typography';
27
+
28
+ :root {
29
+ --md-sys-navigationrail-collapsed-width: 96px;
30
+ --md-sys-navigationrail-expanded-maxwidth: 360px;
31
+ --md-sys-navigationrail-expanded-minwidth: 220px;
32
+ }
33
+
34
+ .micl-navigationrail {
35
+ --md-sys-navigationrail-spring-buffer: 200px;
36
+ --md-sys-navigationrail-header-space: 40px;
37
+ --md-sys-navigationrail-top-space: 44px;
38
+ --md-sys-navigationrail-item-space: 6px;
39
+ --md-sys-navigationrail-item-height: 56px;
40
+ --md-sys-divider-thickness: 0px;
41
+ --md-sys-navigationrail-motion-spatial: #{motion.$md-sys-motion-expressive-slow-spatial};
42
+ --md-sys-navigationrail-motion-duration: #{motion.$md-sys-motion-expressive-slow-spatial-duration};
43
+ --md-sys-navigationrail-motion-duration-reverse: #{motion.$md-sys-motion-expressive-default-spatial-duration};
44
+ --md-sys-navigationrail-morph-duration: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
45
+ --md-sys-navigationrail-morph-duration-reverse: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
46
+
47
+ box-sizing: border-box;
48
+ display: flex;
49
+ flex-direction: column;
50
+ align-items: flex-start;
51
+ min-inline-size: var(--md-sys-navigationrail-collapsed-width);
52
+ max-inline-size: var(--md-sys-navigationrail-collapsed-width);
53
+ block-size: 100vh;
54
+ min-block-size: 100%;
55
+ margin-block: 0;
56
+ margin-inline: 0 auto;
57
+ padding-block: var(--md-sys-navigationrail-top-space) 0;
58
+ padding-inline: 0;
59
+ background-color: var(--md-sys-color-surface);
60
+ border: none;
61
+ box-shadow: var(--md-sys-elevation-level0);
62
+ opacity: 100%;
63
+ overflow: hidden;
64
+ interpolate-size: allow-keywords;
65
+
66
+ &> .micl-navigationrail__headline {
67
+ padding-inline-start: 24px;
68
+ }
69
+ &> .micl-navigationrail__content {
70
+ box-sizing: border-box;
71
+ display: flex;
72
+ flex-direction: column;
73
+ flex: 1 1 auto;
74
+ align-items: flex-start;
75
+ row-gap: var(--md-sys-navigationrail-item-space);
76
+ inline-size: 100%;
77
+ padding-block: var(--md-sys-navigationrail-header-space) 0;
78
+ padding-inline: 20px 0;
79
+ overflow: hidden auto;
80
+ transition: row-gap var(--md-sys-navigationrail-morph-duration-reverse) linear;
81
+
82
+ &> input[type=radio] {
83
+ appearance: none;
84
+ display: none;
85
+ margin: 0;
86
+ }
87
+ &> label.micl-navigationrail__item {
88
+ --micl-ripple: 1;
89
+ --statelayer-color: var(--md-sys-color-on-secondary-container);
90
+
91
+ box-sizing: border-box;
92
+ display: flex;
93
+ flex-direction: column;
94
+ align-items: center;
95
+ block-size: var(--md-sys-navigationrail-item-height);
96
+ inline-size: var(--md-sys-navigationrail-item-height);
97
+ row-gap: 4px;
98
+ padding-block: 12px;
99
+ border-radius: calc(var(--md-sys-navigationrail-item-height) / 2);
100
+ outline: none;
101
+ background-color: transparent;
102
+ background-image:
103
+ radial-gradient(circle at var(--micl-x, center) var(--micl-y, center), transparent 0%, rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)) 10%, transparent 10%),
104
+ linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
105
+ background-repeat: no-repeat;
106
+ background-size: 10000%, 100%;
107
+ cursor: pointer;
108
+ transition:
109
+ inline-size calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
110
+ background-color calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
111
+ background-size 3000ms,
112
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
113
+
114
+ &> .micl-navigationrail__icon {
115
+ --micl-ripple: 1;
116
+
117
+ font-size: 24px;
118
+ inline-size: 24px;
119
+ margin: 0;
120
+ padding-block: 4px;
121
+ padding-inline: 16px;
122
+ border-radius: 16px;
123
+ color: var(--md-sys-color-on-surface-variant);
124
+ background-color: transparent;
125
+ background-image:
126
+ radial-gradient(circle at var(--micl-x, center) var(--micl-y, center), transparent 0%, rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)) 10%, transparent 10%),
127
+ linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
128
+ background-repeat: no-repeat;
129
+ background-size: 10000%, 100%;
130
+ font-variation-settings: 'FILL' 0;
131
+ transition:
132
+ background-size 3000ms,
133
+ background-color var(--md-sys-navigationrail-morph-duration-reverse) linear,
134
+ font-variation-settings var(--md-sys-navigationrail-morph-duration-reverse) linear,
135
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
136
+ }
137
+ &> .micl-navigationrail__text {
138
+ @include typography.label-medium;
139
+
140
+ min-block-size: var(--md-sys-typescale-label-medium-line-height);
141
+ margin-block-start: 0;
142
+ margin-inline-start: 0px;
143
+ padding-inline-end: 0px;
144
+ color: var(--md-sys-color-on-surface-variant);
145
+ opacity: 100%;
146
+ overflow: hidden;
147
+ }
148
+ }
149
+ &> input[type=radio]:checked + label.micl-navigationrail__item {
150
+ &> .micl-navigationrail__icon {
151
+ background-color: var(--md-sys-color-secondary-container);
152
+ color: var(--md-sys-color-on-secondary-container);
153
+ font-variation-settings: 'FILL' 1;
154
+ transition:
155
+ background-size 3000ms,
156
+ background-color var(--md-sys-navigationrail-morph-duration) linear,
157
+ font-variation-settings var(--md-sys-navigationrail-morph-duration) linear,
158
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
159
+ }
160
+ &> .micl-navigationrail__text {
161
+ color: var(--md-sys-color-secondary);
162
+ }
163
+ }
164
+ }
165
+ }
166
+ dialog.micl-navigationrail,
167
+ div.micl-navigationrail:has(> .micl-navigationrail__headline .micl-button--toggle.micl-button--selected) {
168
+ max-inline-size: var(--md-sys-navigationrail-expanded-maxwidth);
169
+ min-inline-size: var(--md-sys-navigationrail-expanded-minwidth);
170
+
171
+ &> .micl-navigationrail__content {
172
+ row-gap: 0px;
173
+
174
+ &> label.micl-navigationrail__item {
175
+ position: relative;
176
+ flex-direction: row;
177
+ inline-size: fit-content;
178
+
179
+ &::before {
180
+ content: "";
181
+ position: absolute;
182
+ inset: 0px;
183
+ inset-inline-end: calc(-1 * (var(--md-sys-navigationrail-expanded-maxwidth) - 20px - 100%));
184
+ background-color: transparent;
185
+ }
186
+ &:hover {
187
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
188
+ }
189
+ &:focus-visible {
190
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
191
+ }
192
+ &:active {
193
+ background-size: 0%, 100%;
194
+ transition: background-size 0ms;
195
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
196
+ }
197
+ &> .micl-navigationrail__text {
198
+ @include typography.label-large;
199
+
200
+ margin-inline-start: -8px;
201
+ padding-inline-end: 16px;
202
+ }
203
+ }
204
+ &> input[type=radio]:checked + label.micl-navigationrail__item {
205
+ background-color: var(--md-sys-color-secondary-container);
206
+
207
+ &> .micl-navigationrail__icon {
208
+ background-color: transparent;
209
+ }
210
+ }
211
+ }
212
+ }
213
+ div.micl-navigationrail:has(> .micl-navigationrail__headline .micl-button--toggle.micl-button--selected) {
214
+ &> .micl-navigationrail__content {
215
+ transition: row-gap var(--md-sys-navigationrail-morph-duration) linear;
216
+
217
+ &> label.micl-navigationrail__item {
218
+ transition:
219
+ inline-size calc(var(--md-sys-navigationrail-morph-duration) / 2) calc(var(--md-sys-navigationrail-morph-duration) / 2) linear,
220
+ background-color calc(var(--md-sys-navigationrail-morph-duration) / 2) calc(var(--md-sys-navigationrail-morph-duration) / 2) linear,
221
+ background-size 3000ms,
222
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
223
+ }
224
+ &> input[type=radio]:checked + label.micl-navigationrail__item {
225
+ &> .micl-navigationrail__icon {
226
+ transition:
227
+ background-size 3000ms,
228
+ background-color calc(var(--md-sys-navigationrail-morph-duration) / 2) linear,
229
+ font-variation-settings calc(var(--md-sys-navigationrail-morph-duration) / 2) linear,
230
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ div.micl-navigationrail:has(> .micl-navigationrail__headline .micl-button--toggle.micl-button--toggled.micl-button--selected) {
236
+ animation: var(--md-sys-navigationrail-morph-duration) linear forwards navigationrail-to-expanded;
237
+
238
+ &> .micl-navigationrail__content > label.micl-navigationrail__item {
239
+ animation: calc(var(--md-sys-navigationrail-morph-duration) / 2) linear forwards navigationrail-item-to-expanded;
240
+
241
+ &> .micl-navigationrail__text {
242
+ animation: var(--md-sys-navigationrail-morph-duration) linear forwards navigationrail-text-to-expanded;
243
+ }
244
+ }
245
+ }
246
+ div.micl-navigationrail:has(> .micl-navigationrail__headline .micl-button--toggle.micl-button--toggled:not(.micl-button--selected)) {
247
+ animation: var(--md-sys-navigationrail-morph-duration-reverse) linear forwards navigationrail-to-collapsed;
248
+
249
+ &> .micl-navigationrail__content {
250
+ &> label.micl-navigationrail__item {
251
+ animation: calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear forwards navigationrail-item-to-collapsed;
252
+
253
+ &> .micl-navigationrail__text {
254
+ animation: var(--md-sys-navigationrail-morph-duration-reverse) linear forwards navigationrail-text-to-collapsed;
255
+ }
256
+ }
257
+ &> input[type=radio]:checked + label.micl-navigationrail__item {
258
+ &> .micl-navigationrail__icon {
259
+ transition:
260
+ background-size 3000ms,
261
+ background-color calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
262
+ font-variation-settings calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
263
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
264
+ }
265
+ }
266
+ }
267
+ }
268
+ div.micl-navigationrail:has(> .micl-navigationrail__headline .micl-button--toggle:not(.micl-button--selected)) {
269
+ &> .micl-navigationrail__content > label.micl-navigationrail__item {
270
+ &:hover {
271
+ &> .micl-navigationrail__icon {
272
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
273
+ }
274
+ }
275
+ &:focus-visible {
276
+ &> .micl-navigationrail__icon {
277
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
278
+ }
279
+ }
280
+ &:active {
281
+ &> .micl-navigationrail__icon {
282
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
283
+
284
+ background-size: 0%, 100%;
285
+ transition:
286
+ background-size 0ms,
287
+ background-color calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
288
+ font-variation-settings calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) calc(var(--md-sys-navigationrail-morph-duration-reverse) / 2) linear,
289
+ --statelayer-opacity var(--md-sys-navigationrail-motion-duration) linear;
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ dialog.micl-navigationrail {
296
+ display: none;
297
+ min-inline-size: calc(var(--md-sys-navigationrail-expanded-minwidth) + var(--md-sys-navigationrail-spring-buffer));
298
+ max-inline-size: calc(var(--md-sys-navigationrail-expanded-maxwidth) + var(--md-sys-navigationrail-spring-buffer));
299
+ margin-inline-start: calc(-1 * (var(--md-sys-navigationrail-expanded-maxwidth) + var(--md-sys-navigationrail-spring-buffer)));
300
+ padding-inline: var(--md-sys-navigationrail-spring-buffer) 0;
301
+ opacity: 0%;
302
+ transition:
303
+ opacity var(--md-sys-navigationrail-motion-duration-reverse) linear,
304
+ margin-inline-start var(--md-sys-navigationrail-motion-duration-reverse) var(--md-sys-navigationrail-motion-spatial),
305
+ overlay var(--md-sys-navigationrail-motion-duration-reverse) linear allow-discrete,
306
+ display var(--md-sys-navigationrail-motion-duration-reverse) linear allow-discrete;
307
+
308
+ &[open] {
309
+ display: flex;
310
+ margin-inline-start: calc(-1 * var(--md-sys-navigationrail-spring-buffer));
311
+ opacity: 100%;
312
+
313
+ @starting-style {
314
+ margin-inline-start: calc(-1 * (var(--md-sys-navigationrail-expanded-maxwidth) + var(--md-sys-navigationrail-spring-buffer)));
315
+ opacity: 0%;
316
+ }
317
+ }
318
+ }
319
+ div.micl-navigationrail {
320
+ position: sticky;
321
+ float: inline-start;
322
+ inset: unset;
323
+ inset-block-start: 0;
324
+ inset-inline-start: 0;
325
+ border-inline-end: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
326
+ }
327
+ div.micl-navigationrail[popover] {
328
+ position: fixed;
329
+ }
330
+ .micl-navigationrail {
331
+ &[open],
332
+ &:popover-open {
333
+ border-start-end-radius: var(--md-sys-shape-corner-large);
334
+ border-end-end-radius: var(--md-sys-shape-corner-large);
335
+ box-shadow: var(--md-sys-elevation-level2);
336
+ background-color: var(--md-sys-color-surface-container);
337
+ transition:
338
+ opacity var(--md-sys-navigationrail-motion-duration) linear,
339
+ margin-inline-start var(--md-sys-navigationrail-motion-duration) var(--md-sys-navigationrail-motion-spatial),
340
+ overlay var(--md-sys-navigationrail-motion-duration) linear allow-discrete,
341
+ display var(--md-sys-navigationrail-motion-duration) linear allow-discrete;
342
+
343
+ &::backdrop {
344
+ background-color: rgba(0, 0, 0, 0.2);
345
+
346
+ @starting-style {
347
+ background-color: rgba(0, 0, 0, 0);
348
+ }
349
+ }
350
+ }
351
+ &::backdrop {
352
+ background-color: rgba(0, 0, 0, 0);
353
+ transition:
354
+ background-color var(--md-sys-navigationrail-motion-duration) linear,
355
+ overlay var(--md-sys-navigationrail-motion-duration) linear allow-discrete,
356
+ display var(--md-sys-navigationrail-motion-duration) linear allow-discrete;
357
+ }
358
+ }
359
+ body:has(div.micl-navigationrail[popover]) {
360
+ margin-inline-start: var(--md-sys-navigationrail-collapsed-width);
361
+ }
362
+
363
+ @keyframes navigationrail-to-expanded {
364
+ from {
365
+ max-inline-size: var(--md-sys-navigationrail-collapsed-width);
366
+ min-inline-size: var(--md-sys-navigationrail-collapsed-width);
367
+ }
368
+ to {
369
+ max-inline-size: var(--md-sys-navigationrail-expanded-maxwidth);
370
+ min-inline-size: var(--md-sys-navigationrail-expanded-minwidth);
371
+ }
372
+ }
373
+ @keyframes navigationrail-to-collapsed {
374
+ from {
375
+ max-inline-size: var(--md-sys-navigationrail-expanded-maxwidth);
376
+ min-inline-size: var(--md-sys-navigationrail-expanded-minwidth);
377
+ }
378
+ to {
379
+ max-inline-size: var(--md-sys-navigationrail-collapsed-width);
380
+ min-inline-size: var(--md-sys-navigationrail-collapsed-width);
381
+ }
382
+ }
383
+ @keyframes navigationrail-item-to-expanded {
384
+ 0% {
385
+ flex-direction: column;
386
+ }
387
+ 99% {
388
+ flex-direction: column;
389
+ }
390
+ 100% {
391
+ flex-direction: row;
392
+ }
393
+ }
394
+ @keyframes navigationrail-item-to-collapsed {
395
+ 0% {
396
+ flex-direction: row;
397
+ }
398
+ 99% {
399
+ flex-direction: row;
400
+ }
401
+ 100% {
402
+ flex-direction: column;
403
+ }
404
+ }
405
+ @keyframes navigationrail-text-to-collapsed {
406
+ 0% {
407
+ @include typography.label-large;
408
+ margin-block-start: 0;
409
+ margin-inline-start: -8px;
410
+ padding-inline-end: 16px;
411
+ opacity: 100%
412
+ }
413
+ 49.9% {
414
+ @include typography.label-large;
415
+ margin-block-start: 0;
416
+ margin-inline-start: -8px;
417
+ padding-inline-end: 16px;
418
+ opacity: 0%;
419
+ }
420
+ 50.1% {
421
+ @include typography.label-medium;
422
+ min-block-size: var(--md-sys-typescale-label-medium-line-height);
423
+ margin-block-start: -16px;
424
+ margin-inline-start: 0px;
425
+ padding-inline-end: 0px;
426
+ opacity: 0%;
427
+ }
428
+ 100% {
429
+ @include typography.label-medium;
430
+ min-block-size: var(--md-sys-typescale-label-medium-line-height);
431
+ margin-block-start: 0;
432
+ margin-inline-start: 0px;
433
+ padding-inline-end: 0px;
434
+ opacity: 100%;
435
+ }
436
+ }
437
+ @keyframes navigationrail-text-to-expanded {
438
+ 0% {
439
+ @include typography.label-medium;
440
+ min-block-size: var(--md-sys-typescale-label-medium-line-height);
441
+ margin-block-start: 0;
442
+ margin-inline-start: 0px;
443
+ padding-inline-end: 0px;
444
+ opacity: 100%;
445
+ }
446
+ 49.9% {
447
+ @include typography.label-medium;
448
+ min-block-size: var(--md-sys-typescale-label-medium-line-height);
449
+ margin-block-start: -16px;
450
+ margin-inline-start: 0px;
451
+ padding-inline-end: 0px;
452
+ opacity: 0%;
453
+ }
454
+ 50.1% {
455
+ @include typography.label-large;
456
+ margin-block-start: 0px;
457
+ margin-inline-start: -8px;
458
+ padding-inline-end: 16px;
459
+ opacity: 0%;
460
+ }
461
+ 100% {
462
+ @include typography.label-large;
463
+ margin-block-start: 0px;
464
+ margin-inline-start: -8px;
465
+ padding-inline-end: 16px;
466
+ opacity: 100%;
467
+ }
468
+ }
@@ -19,7 +19,7 @@
19
19
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
20
  // SOFTWARE.
21
21
 
22
- export const checkboxSelector = '.micl-checkbox';
22
+ export const navigationrailSelector = '.micl-navigationrail__item[for]:not(.micl-navigationrail__item--disabled)';
23
23
 
24
24
  export default (() =>
25
25
  {
@@ -27,19 +27,24 @@ export default (() =>
27
27
  keydown: (event: Event) =>
28
28
  {
29
29
  if (
30
- !(event.target as Element).matches(checkboxSelector)
31
- || !(event instanceof KeyboardEvent)
32
- || !(event.target instanceof HTMLInputElement)
33
- || (event.target as HTMLInputElement).disabled
30
+ !(event instanceof KeyboardEvent)
31
+ || !(event.target instanceof HTMLLabelElement)
32
+ || !event.target.matches(navigationrailSelector)
34
33
  ) {
35
34
  return;
36
35
  }
36
+ const input = document.getElementById(event.target.htmlFor) as HTMLInputElement;
37
+ if (!input) {
38
+ return;
39
+ }
37
40
 
38
41
  switch (event.key) {
39
42
  case 'Enter':
40
43
  case ' ':
41
- event.target.checked = !event.target.checked;
42
- event.preventDefault() // prevent page scrolling
44
+ event.preventDefault();
45
+ if (!input.checked) {
46
+ input.checked = !input.checked;
47
+ }
43
48
  break;
44
49
  default:
45
50
  }