H. lib / js / custom / MdNavigationDrawer.js

1import { abreElementoHtml } from "../abreElementoHtml.js"
2import { cierraElementoHtmo } from "../cierraElementoHtmo.js"
3import { querySelector } from "../querySelector.js"
4
5export class MdNavigationDrawer extends HTMLElement {
6
7 /**
8 * @returns {string}
9 */
10 getHipervinculos() { throw new Error("abstract") }
11
12 getContent() {
13 return /* HTML */`
14
15 <link rel="stylesheet" href="/lib/css/material-symbols-outlined.css">
16 <link rel="stylesheet" href="/lib/css/md-ripple.css">
17 <link rel="stylesheet" href="/material-tokens/css/shape.css">
18 <link rel="stylesheet" href="/material-tokens/css/motion.css">
19
20 <style>
21
22 :host {
23 display: block;
24 }
25
26 :host([hidden]) {
27 display: none;
28 }
29
30 nav {
31 display: none;
32 flex-direction: column;
33 position: fixed;
34 z-index: 4;
35 box-sizing: border-box;
36 top: 0;
37 left: 0;
38 bottom: 0;
39 width: var(--anchoNav);
40 max-width: 80vw;
41 overflow: hidden;
42 overscroll-behavior: contain;
43 background-color: var(--md-sys-color-surface-container-low);
44 transform: translateX(-100%);
45 transition-property: display, transform;
46 transition-behavior: allow-discrete;
47 }
48
49 nav.open {
50 display: flex;
51 transform: translateX(0);
52 }
53
54 nav>div {
55 flex-grow: 1;
56 overflow: auto;
57 padding: 0.75rem 1rem;
58 }
59
60 h1 {
61 margin: 0;
62 height: 3.5rem;
63 line-height: 3.5rem;
64 padding: 0 0 0 0.75rem;
65 white-space: nowrap;
66 text-overflow: ellipsis;
67 overflow: hidden;
68 color: var(--md-sys-color-on-surface-variant);
69 font-family: var(--md-sys-typescale-title-small-font);
70 font-weight: var(--md-sys-typescale-title-small-weight);
71 font-size: var(--md-sys-typescale-title-small-size);
72 font-style: var(--md-sys-typescale-title-small-font-style);
73 letter-spacing: var(--md-sys-typescale-title-small-tracking);
74 text-transform: var(--md-sys-typescale-title-small-text-transform);
75 text-decoration: var(--md-sys-typescale-title-small-text-decoration);
76 }
77
78 a::after { /* container inactive */
79 content: "";
80 position: absolute;
81 z-index: -2;
82 top: 0;
83 right: 0;
84 left: 0;
85 bottom: 0;
86 }
87
88 a.active::after { /* container */
89 background-color: var(--md-sys-color-secondary-container);
90 }
91
92 a { /* label, shape inactive */
93 position: relative;
94 display: block;
95 box-sizing: border-box;
96 height: 3.5rem;
97 line-height: 3.5rem;
98 padding: 0 0.75rem;
99 border-radius: 1.75rem;
100 color: var(--md-sys-color-on-surface-variant);
101 font-family: var(--md-sys-typescale-label-large-font);
102 font-weight: var(--md-sys-typescale-label-large-weight);
103 font-size: var(--md-sys-typescale-label-large-size);
104 font-style: var(--md-sys-typescale-label-large-font-style);
105 letter-spacing: var(--md-sys-typescale-label-large-tracking);
106 text-transform: var(--md-sys-typescale-label-large-text-transform);
107 text-decoration: var(--md-sys-typescale-label-large-text-decoration);
108 overflow: hidden;
109 white-space: nowrap;
110 text-overflow: ellipsis;
111 }
112
113 a.active { /* label, shape */
114 font-weight: var(--md-sys-typescale-label-large-weight-prominent);
115 color: var(--md-sys-color-on-secondary-container);
116 }
117
118 a::before { /* state layer */
119 content: "";
120 position: absolute;
121 z-index: -1;
122 top: 0;
123 right: 0;
124 left: 0;
125 bottom: 0;
126 }
127
128 a span { /* inactive icon */
129 position: relative;
130 margin-right: 0.75rem;
131 vertical-align: middle;
132 color: var(--md-sys-color-on-surface-variant);
133 font-size: 1.5rem;
134 width: 1.5rem;
135 height: 1.5rem;
136 }
137
138 a.active span { /* icon */
139 color: var(--md-sys-color-on-secondary-container);
140 }
141
142 #scrim {
143 display: none;
144 position: fixed;
145 z-index: 3;
146 top: 0;
147 left: 0;
148 bottom: 0;
149 right: 0;
150 opacity: 0.4;
151 background-color: var(--md-ref-palette-neutral-variant20);
152 transform: translateX(-100%);
153 transition-property: display, transform;
154 transition-behavior: allow-discrete;
155 }
156
157 #scrim.open {
158 display: block;
159 transform: translateX(0);
160 }
161
162 @starting-style {
163 nav.open{
164 display: flex;
165 transform: translateX(-100%);
166 }
167 #scrim.open {
168 display: block;
169 transform: translateX(-100%);
170 }
171 }
172
173 a:hover { /* inactive label, shape */
174 color: var(--md-sys-color-on-surface);
175 }
176
177 a.active:hover { /* active label, shape */
178 color: var(--md-sys-color-on-secondary-container);
179 }
180
181 a:hover::before { /* inactive state layer */
182 background-color: var(--md-sys-color-on-surface);
183 opacity: var(--md-sys-state-hover-state-layer-opacity);
184 }
185
186 a.active:hover::before { /* state layer */
187 background-color: var(--md-sys-color-on-secondary-container);
188 }
189
190 a:hover span { /* inactive icon */
191 color: var(--md-sys-color-on-surface);
192 }
193
194 a.active:hover span { /* icon */
195 color: var(--md-sys-color-on-secondary-container);
196 }
197
198 a:focus { /* inactive label, shape */
199 outline: none;
200 color: var(--md-sys-color-on-surface);
201 }
202
203 a.active:focus { /* label, shape */
204 color: var(--md-sys-color-on-secondary-container);
205 }
206
207 a:focus::before { /* inactive state layer */
208 background-color: var(--md-sys-color-on-surface);
209 opacity: var(--md-sys-state-focus-state-layer-opacity);
210 }
211
212 a.active:focus::before { /* state layer */
213 background-color: var(--md-sys-color-on-secondary-container);
214 }
215
216 a:focus span { /* inactive icon */
217 color: var(--md-sys-color-on-surface);
218 }
219
220 a.active:focus span { /* icon */
221 color: var(--md-sys-color-on-secondary-container);
222 }
223
224 a:active { /* inactive pressed label, shape */
225 background-position: center;
226 background-image:
227 radial-gradient(circle, var(--md-riple-color) 1%, transparent 1%);
228 background-size: 100%;
229 animation-name: md-ripple;
230 animation-duration: var(--md-sys-motion-duration-500);
231 color: var(--md-sys-color-on-surface);
232 }
233
234 a.active:active { /* active pressed label, shape */
235 color: var(--md-sys-color-on-secondary-container);
236 }
237
238 a:active::before { /* inactive pressed state layer */
239 background-color: var(--md-sys-color-on-surface);
240 opacity: var(--md-sys-state-pressed-state-layer-opacity);
241 }
242
243 a.active:active::before { /* active pressed state layer */
244 background-color: var(--md-sys-color-on-secondary-container);
245 }
246
247 a:active span { /* inactive pressed icon */
248 color: var(--md-sys-color-on-surface);
249 }
250
251 a.active:focus span { /* active pressed icon */
252 color: var(--md-sys-color-on-secondary-container);
253 }
254
255 </style>
256
257 <div id="scrim"class="duration-700 easing-standard"></div>
258 <nav class="large-end duration-700 easing-standard"><div></div></nav>`
259 }
260
261 constructor() {
262 super()
263 const shadow = this.attachShadow({ mode: "open", delegatesFocus: true })
264 shadow.innerHTML = this.getContent()
265 this.cierra = this.cierra.bind(this)
266
267 /** @type {HTMLElement} */
268 this._nav = querySelector(shadow, "nav")
269
270 /** @type {HTMLUListElement} */
271 this._div = querySelector(this._nav, "div")
272
273 /** @type {HTMLUListElement} */
274 this._scrim = querySelector(shadow, "#scrim")
275 this._scrim.addEventListener("click", this.cierra)
276 }
277
278 connectedCallback() {
279 this.classList.add("drawer")
280 this._div.innerHTML = this.getHipervinculos()
281 }
282
283 abre() {
284 abreElementoHtml(this._nav)
285 abreElementoHtml(this._scrim)
286 }
287
288 cierra() {
289 cierraElementoHtmo(this._nav)
290 cierraElementoHtmo(this._scrim)
291 }
292
293}
skip_previous skip_next