UNPKG

29.2 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5const index = require('./index-a0a08b2a.js');
6const ionicGlobal = require('./ionic-global-06f21c1a.js');
7const cubicBezier = require('./cubic-bezier-0b2ccc35.js');
8const gestureController = require('./gesture-controller-29adda71.js');
9const helpers = require('./helpers-d381ec4d.js');
10const index$1 = require('./index-ea5f8e16.js');
11const theme = require('./theme-30b7a575.js');
12require('./hardware-back-button-148ce546.js');
13require('./animation-13cbbb20.js');
14
15const menuIosCss = ":host{--width:304px;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--background:var(--ion-background-color, #fff);left:0;right:0;top:0;bottom:0;display:none;position:absolute;contain:strict}:host(.show-menu){display:block}.menu-inner{left:0;right:auto;top:0;bottom:0;-webkit-transform:translate3d(-9999px, 0, 0);transform:translate3d(-9999px, 0, 0);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:strict}[dir=rtl] .menu-inner,:host-context([dir=rtl]) .menu-inner{left:unset;right:unset;left:auto;right:0}[dir=rtl] .menu-inner,:host-context([dir=rtl]) .menu-inner{-webkit-transform:translate3d(calc(-1 * -9999px), 0, 0);transform:translate3d(calc(-1 * -9999px), 0, 0)}:host(.menu-side-start) .menu-inner{--ion-safe-area-right:0px;right:auto;left:0}:host(.menu-side-end) .menu-inner{--ion-safe-area-left:0px;right:0;left:auto;}ion-backdrop{display:none;opacity:0.01;z-index:-1}@media (max-width: 340px){.menu-inner{--width:264px}}:host(.menu-type-reveal){z-index:0}:host(.menu-type-reveal.show-menu) .menu-inner{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}:host(.menu-type-overlay){z-index:1000}:host(.menu-type-overlay) .show-backdrop{display:block;cursor:pointer}:host(.menu-pane-visible){width:var(--width);min-width:var(--min-width);max-width:var(--max-width)}:host(.menu-pane-visible) .menu-inner{left:0;right:0;width:auto;-webkit-transform:none !important;transform:none !important;-webkit-box-shadow:none !important;box-shadow:none !important}:host(.menu-pane-visible) ion-backdrop{display:hidden !important;}:host(.menu-type-push){z-index:1000}:host(.menu-type-push) .show-backdrop{display:block}";
16
17const menuMdCss = ":host{--width:304px;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--background:var(--ion-background-color, #fff);left:0;right:0;top:0;bottom:0;display:none;position:absolute;contain:strict}:host(.show-menu){display:block}.menu-inner{left:0;right:auto;top:0;bottom:0;-webkit-transform:translate3d(-9999px, 0, 0);transform:translate3d(-9999px, 0, 0);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:strict}[dir=rtl] .menu-inner,:host-context([dir=rtl]) .menu-inner{left:unset;right:unset;left:auto;right:0}[dir=rtl] .menu-inner,:host-context([dir=rtl]) .menu-inner{-webkit-transform:translate3d(calc(-1 * -9999px), 0, 0);transform:translate3d(calc(-1 * -9999px), 0, 0)}:host(.menu-side-start) .menu-inner{--ion-safe-area-right:0px;right:auto;left:0}:host(.menu-side-end) .menu-inner{--ion-safe-area-left:0px;right:0;left:auto;}ion-backdrop{display:none;opacity:0.01;z-index:-1}@media (max-width: 340px){.menu-inner{--width:264px}}:host(.menu-type-reveal){z-index:0}:host(.menu-type-reveal.show-menu) .menu-inner{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}:host(.menu-type-overlay){z-index:1000}:host(.menu-type-overlay) .show-backdrop{display:block;cursor:pointer}:host(.menu-pane-visible){width:var(--width);min-width:var(--min-width);max-width:var(--max-width)}:host(.menu-pane-visible) .menu-inner{left:0;right:0;width:auto;-webkit-transform:none !important;transform:none !important;-webkit-box-shadow:none !important;box-shadow:none !important}:host(.menu-pane-visible) ion-backdrop{display:hidden !important;}:host(.menu-type-overlay) .menu-inner{-webkit-box-shadow:4px 0px 16px rgba(0, 0, 0, 0.18);box-shadow:4px 0px 16px rgba(0, 0, 0, 0.18)}";
18
19const iosEasing = 'cubic-bezier(0.32,0.72,0,1)';
20const mdEasing = 'cubic-bezier(0.0,0.0,0.2,1)';
21const iosEasingReverse = 'cubic-bezier(1, 0, 0.68, 0.28)';
22const mdEasingReverse = 'cubic-bezier(0.4, 0, 0.6, 1)';
23const Menu = class {
24 constructor(hostRef) {
25 index.registerInstance(this, hostRef);
26 this.ionWillOpen = index.createEvent(this, "ionWillOpen", 7);
27 this.ionWillClose = index.createEvent(this, "ionWillClose", 7);
28 this.ionDidOpen = index.createEvent(this, "ionDidOpen", 7);
29 this.ionDidClose = index.createEvent(this, "ionDidClose", 7);
30 this.ionMenuChange = index.createEvent(this, "ionMenuChange", 7);
31 this.lastOnEnd = 0;
32 this.blocker = gestureController.GESTURE_CONTROLLER.createBlocker({ disableScroll: true });
33 this.isAnimating = false;
34 this._isOpen = false;
35 this.isPaneVisible = false;
36 this.isEndSide = false;
37 /**
38 * If `true`, the menu is disabled.
39 */
40 this.disabled = false;
41 /**
42 * Which side of the view the menu should be placed.
43 */
44 this.side = 'start';
45 /**
46 * If `true`, swiping the menu is enabled.
47 */
48 this.swipeGesture = true;
49 /**
50 * The edge threshold for dragging the menu open.
51 * If a drag/swipe happens over this value, the menu is not triggered.
52 */
53 this.maxEdgeStart = 50;
54 }
55 typeChanged(type, oldType) {
56 const contentEl = this.contentEl;
57 if (contentEl) {
58 if (oldType !== undefined) {
59 contentEl.classList.remove(`menu-content-${oldType}`);
60 }
61 contentEl.classList.add(`menu-content-${type}`);
62 contentEl.removeAttribute('style');
63 }
64 if (this.menuInnerEl) {
65 // Remove effects of previous animations
66 this.menuInnerEl.removeAttribute('style');
67 }
68 this.animation = undefined;
69 }
70 disabledChanged() {
71 this.updateState();
72 this.ionMenuChange.emit({
73 disabled: this.disabled,
74 open: this._isOpen
75 });
76 }
77 sideChanged() {
78 this.isEndSide = helpers.isEndSide(this.side);
79 }
80 swipeGestureChanged() {
81 this.updateState();
82 }
83 async connectedCallback() {
84 if (this.type === undefined) {
85 this.type = ionicGlobal.config.get('menuType', 'overlay');
86 }
87 const el = this.el;
88 const parent = el.parentNode;
89 if (this.contentId === undefined) {
90 console.warn(`[DEPRECATED][ion-menu] Using the [main] attribute is deprecated, please use the "contentId" property instead:
91BEFORE:
92 <ion-menu>...</ion-menu>
93 <div main>...</div>
94
95AFTER:
96 <ion-menu contentId="main-content"></ion-menu>
97 <div id="main-content">...</div>
98`);
99 }
100 const content = this.contentId !== undefined
101 ? document.getElementById(this.contentId)
102 : parent && parent.querySelector && parent.querySelector('[main]');
103 if (!content || !content.tagName) {
104 // requires content element
105 console.error('Menu: must have a "content" element to listen for drag events on.');
106 return;
107 }
108 this.contentEl = content;
109 // add menu's content classes
110 content.classList.add('menu-content');
111 this.typeChanged(this.type, undefined);
112 this.sideChanged();
113 // register this menu with the app's menu controller
114 index$1.menuController._register(this);
115 this.gesture = (await Promise.resolve().then(function () { return require('./index-a1dd5c93.js'); })).createGesture({
116 el: document,
117 gestureName: 'menu-swipe',
118 gesturePriority: 30,
119 threshold: 10,
120 blurOnStart: true,
121 canStart: ev => this.canStart(ev),
122 onWillStart: () => this.onWillStart(),
123 onStart: () => this.onStart(),
124 onMove: ev => this.onMove(ev),
125 onEnd: ev => this.onEnd(ev),
126 });
127 this.updateState();
128 }
129 async componentDidLoad() {
130 this.ionMenuChange.emit({ disabled: this.disabled, open: this._isOpen });
131 this.updateState();
132 }
133 disconnectedCallback() {
134 this.blocker.destroy();
135 index$1.menuController._unregister(this);
136 if (this.animation) {
137 this.animation.destroy();
138 }
139 if (this.gesture) {
140 this.gesture.destroy();
141 this.gesture = undefined;
142 }
143 this.animation = undefined;
144 this.contentEl = this.backdropEl = this.menuInnerEl = undefined;
145 }
146 onSplitPaneChanged(ev) {
147 this.isPaneVisible = ev.detail.isPane(this.el);
148 this.updateState();
149 }
150 onBackdropClick(ev) {
151 if (this._isOpen && this.lastOnEnd < ev.timeStamp - 100) {
152 const shouldClose = (ev.composedPath)
153 ? !ev.composedPath().includes(this.menuInnerEl)
154 : false;
155 if (shouldClose) {
156 ev.preventDefault();
157 ev.stopPropagation();
158 this.close();
159 }
160 }
161 }
162 /**
163 * Returns `true` is the menu is open.
164 */
165 isOpen() {
166 return Promise.resolve(this._isOpen);
167 }
168 /**
169 * Returns `true` is the menu is active.
170 *
171 * A menu is active when it can be opened or closed, meaning it's enabled
172 * and it's not part of a `ion-split-pane`.
173 */
174 isActive() {
175 return Promise.resolve(this._isActive());
176 }
177 /**
178 * Opens the menu. If the menu is already open or it can't be opened,
179 * it returns `false`.
180 */
181 open(animated = true) {
182 return this.setOpen(true, animated);
183 }
184 /**
185 * Closes the menu. If the menu is already closed or it can't be closed,
186 * it returns `false`.
187 */
188 close(animated = true) {
189 return this.setOpen(false, animated);
190 }
191 /**
192 * Toggles the menu. If the menu is already open, it will try to close, otherwise it will try to open it.
193 * If the operation can't be completed successfully, it returns `false`.
194 */
195 toggle(animated = true) {
196 return this.setOpen(!this._isOpen, animated);
197 }
198 /**
199 * Opens or closes the button.
200 * If the operation can't be completed successfully, it returns `false`.
201 */
202 setOpen(shouldOpen, animated = true) {
203 return index$1.menuController._setOpen(this, shouldOpen, animated);
204 }
205 async _setOpen(shouldOpen, animated = true) {
206 // If the menu is disabled or it is currently being animated, let's do nothing
207 if (!this._isActive() || this.isAnimating || shouldOpen === this._isOpen) {
208 return false;
209 }
210 this.beforeAnimation(shouldOpen);
211 await this.loadAnimation();
212 await this.startAnimation(shouldOpen, animated);
213 this.afterAnimation(shouldOpen);
214 return true;
215 }
216 async loadAnimation() {
217 // Menu swipe animation takes the menu's inner width as parameter,
218 // If `offsetWidth` changes, we need to create a new animation.
219 const width = this.menuInnerEl.offsetWidth;
220 if (width === this.width && this.animation !== undefined) {
221 return;
222 }
223 this.width = width;
224 // Destroy existing animation
225 if (this.animation) {
226 this.animation.destroy();
227 this.animation = undefined;
228 }
229 // Create new animation
230 this.animation = await index$1.menuController._createAnimation(this.type, this);
231 if (!ionicGlobal.config.getBoolean('animated', true)) {
232 this.animation.duration(0);
233 }
234 this.animation.fill('both');
235 }
236 async startAnimation(shouldOpen, animated) {
237 const isReversed = !shouldOpen;
238 const mode = ionicGlobal.getIonMode(this);
239 const easing = mode === 'ios' ? iosEasing : mdEasing;
240 const easingReverse = mode === 'ios' ? iosEasingReverse : mdEasingReverse;
241 const ani = this.animation
242 .direction((isReversed) ? 'reverse' : 'normal')
243 .easing((isReversed) ? easingReverse : easing)
244 .onFinish(() => {
245 if (ani.getDirection() === 'reverse') {
246 ani.direction('normal');
247 }
248 });
249 if (animated) {
250 await ani.play();
251 }
252 else {
253 ani.play({ sync: true });
254 }
255 }
256 _isActive() {
257 return !this.disabled && !this.isPaneVisible;
258 }
259 canSwipe() {
260 return this.swipeGesture && !this.isAnimating && this._isActive();
261 }
262 canStart(detail) {
263 // Do not allow swipe gesture if a modal is open
264 const isModalPresented = !!document.querySelector('ion-modal.show-modal');
265 if (isModalPresented || !this.canSwipe()) {
266 return false;
267 }
268 if (this._isOpen) {
269 return true;
270 // TODO error
271 }
272 else if (index$1.menuController._getOpenSync()) {
273 return false;
274 }
275 return checkEdgeSide(window, detail.currentX, this.isEndSide, this.maxEdgeStart);
276 }
277 onWillStart() {
278 this.beforeAnimation(!this._isOpen);
279 return this.loadAnimation();
280 }
281 onStart() {
282 if (!this.isAnimating || !this.animation) {
283 helpers.assert(false, 'isAnimating has to be true');
284 return;
285 }
286 // the cloned animation should not use an easing curve during seek
287 this.animation.progressStart(true, (this._isOpen) ? 1 : 0);
288 }
289 onMove(detail) {
290 if (!this.isAnimating || !this.animation) {
291 helpers.assert(false, 'isAnimating has to be true');
292 return;
293 }
294 const delta = computeDelta(detail.deltaX, this._isOpen, this.isEndSide);
295 const stepValue = delta / this.width;
296 this.animation.progressStep((this._isOpen) ? 1 - stepValue : stepValue);
297 }
298 onEnd(detail) {
299 if (!this.isAnimating || !this.animation) {
300 helpers.assert(false, 'isAnimating has to be true');
301 return;
302 }
303 const isOpen = this._isOpen;
304 const isEndSide = this.isEndSide;
305 const delta = computeDelta(detail.deltaX, isOpen, isEndSide);
306 const width = this.width;
307 const stepValue = delta / width;
308 const velocity = detail.velocityX;
309 const z = width / 2.0;
310 const shouldCompleteRight = velocity >= 0 && (velocity > 0.2 || detail.deltaX > z);
311 const shouldCompleteLeft = velocity <= 0 && (velocity < -0.2 || detail.deltaX < -z);
312 const shouldComplete = isOpen
313 ? isEndSide ? shouldCompleteRight : shouldCompleteLeft
314 : isEndSide ? shouldCompleteLeft : shouldCompleteRight;
315 let shouldOpen = !isOpen && shouldComplete;
316 if (isOpen && !shouldComplete) {
317 shouldOpen = true;
318 }
319 this.lastOnEnd = detail.currentTime;
320 // Account for rounding errors in JS
321 let newStepValue = (shouldComplete) ? 0.001 : -0.001;
322 /**
323 * TODO: stepValue can sometimes return a negative
324 * value, but you can't have a negative time value
325 * for the cubic bezier curve (at least with web animations)
326 * Not sure if the negative step value is an error or not
327 */
328 const adjustedStepValue = (stepValue < 0) ? 0.01 : stepValue;
329 /**
330 * Animation will be reversed here, so need to
331 * reverse the easing curve as well
332 *
333 * Additionally, we need to account for the time relative
334 * to the new easing curve, as `stepValue` is going to be given
335 * in terms of a linear curve.
336 */
337 newStepValue += cubicBezier.getTimeGivenProgression([0, 0], [0.4, 0], [0.6, 1], [1, 1], helpers.clamp(0, adjustedStepValue, 0.9999))[0] || 0;
338 const playTo = (this._isOpen) ? !shouldComplete : shouldComplete;
339 this.animation
340 .easing('cubic-bezier(0.4, 0.0, 0.6, 1)')
341 .onFinish(() => this.afterAnimation(shouldOpen), { oneTimeCallback: true })
342 .progressEnd((playTo) ? 1 : 0, (this._isOpen) ? 1 - newStepValue : newStepValue, 300);
343 }
344 beforeAnimation(shouldOpen) {
345 helpers.assert(!this.isAnimating, '_before() should not be called while animating');
346 // this places the menu into the correct location before it animates in
347 // this css class doesn't actually kick off any animations
348 this.el.classList.add(SHOW_MENU);
349 if (this.backdropEl) {
350 this.backdropEl.classList.add(SHOW_BACKDROP);
351 }
352 this.blocker.block();
353 this.isAnimating = true;
354 if (shouldOpen) {
355 this.ionWillOpen.emit();
356 }
357 else {
358 this.ionWillClose.emit();
359 }
360 }
361 afterAnimation(isOpen) {
362 helpers.assert(this.isAnimating, '_before() should be called while animating');
363 // keep opening/closing the menu disabled for a touch more yet
364 // only add listeners/css if it's enabled and isOpen
365 // and only remove listeners/css if it's not open
366 // emit opened/closed events
367 this._isOpen = isOpen;
368 this.isAnimating = false;
369 if (!this._isOpen) {
370 this.blocker.unblock();
371 }
372 if (isOpen) {
373 // add css class
374 if (this.contentEl) {
375 this.contentEl.classList.add(MENU_CONTENT_OPEN);
376 }
377 // emit open event
378 this.ionDidOpen.emit();
379 }
380 else {
381 // remove css classes
382 this.el.classList.remove(SHOW_MENU);
383 if (this.contentEl) {
384 this.contentEl.classList.remove(MENU_CONTENT_OPEN);
385 }
386 if (this.backdropEl) {
387 this.backdropEl.classList.remove(SHOW_BACKDROP);
388 }
389 if (this.animation) {
390 this.animation.stop();
391 }
392 // emit close event
393 this.ionDidClose.emit();
394 }
395 }
396 updateState() {
397 const isActive = this._isActive();
398 if (this.gesture) {
399 this.gesture.enable(isActive && this.swipeGesture);
400 }
401 // Close menu immediately
402 if (!isActive && this._isOpen) {
403 // close if this menu is open, and should not be enabled
404 this.forceClosing();
405 }
406 if (!this.disabled) {
407 index$1.menuController._setActiveMenu(this);
408 }
409 helpers.assert(!this.isAnimating, 'can not be animating');
410 }
411 forceClosing() {
412 helpers.assert(this._isOpen, 'menu cannot be closed');
413 this.isAnimating = true;
414 const ani = this.animation.direction('reverse');
415 ani.play({ sync: true });
416 this.afterAnimation(false);
417 }
418 render() {
419 const { isEndSide, type, disabled, isPaneVisible } = this;
420 const mode = ionicGlobal.getIonMode(this);
421 return (index.h(index.Host, { role: "navigation", class: {
422 [mode]: true,
423 [`menu-type-${type}`]: true,
424 'menu-enabled': !disabled,
425 'menu-side-end': isEndSide,
426 'menu-side-start': !isEndSide,
427 'menu-pane-visible': isPaneVisible
428 } }, index.h("div", { class: "menu-inner", part: "container", ref: el => this.menuInnerEl = el }, index.h("slot", null)), index.h("ion-backdrop", { ref: el => this.backdropEl = el, class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
429 }
430 get el() { return index.getElement(this); }
431 static get watchers() { return {
432 "type": ["typeChanged"],
433 "disabled": ["disabledChanged"],
434 "side": ["sideChanged"],
435 "swipeGesture": ["swipeGestureChanged"]
436 }; }
437};
438const computeDelta = (deltaX, isOpen, isEndSide) => {
439 return Math.max(0, isOpen !== isEndSide ? -deltaX : deltaX);
440};
441const checkEdgeSide = (win, posX, isEndSide, maxEdgeStart) => {
442 if (isEndSide) {
443 return posX >= win.innerWidth - maxEdgeStart;
444 }
445 else {
446 return posX <= maxEdgeStart;
447 }
448};
449const SHOW_MENU = 'show-menu';
450const SHOW_BACKDROP = 'show-backdrop';
451const MENU_CONTENT_OPEN = 'menu-content-open';
452Menu.style = {
453 ios: menuIosCss,
454 md: menuMdCss
455};
456
457// Given a menu, return whether or not the menu toggle should be visible
458const updateVisibility = async (menu) => {
459 const menuEl = await index$1.menuController.get(menu);
460 return !!(menuEl && await menuEl.isActive());
461};
462
463const menuButtonIosCss = ":host{--background:transparent;--color-focused:currentColor;--border-radius:initial;--padding-top:0;--padding-bottom:0;color:var(--color);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.button-native{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}ion-icon{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;pointer-events:none}:host(.menu-button-hidden){display:none}:host(.menu-button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity, 0)}}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--background-focused:currentColor;--background-focused-opacity:.1;--border-radius:4px;--color:var(--ion-color-primary, #3880ff);--padding-start:5px;--padding-end:5px;height:32px;font-size:31px}:host(.ion-activated){opacity:0.4}@media (any-hover: hover){:host(:hover){opacity:0.6}}";
464
465const menuButtonMdCss = ":host{--background:transparent;--color-focused:currentColor;--border-radius:initial;--padding-top:0;--padding-bottom:0;color:var(--color);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.button-native{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}ion-icon{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;pointer-events:none}:host(.menu-button-hidden){display:none}:host(.menu-button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity, 0)}}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--background-focused:currentColor;--background-focused-opacity:.12;--background-hover:currentColor;--background-hover-opacity:.04;--border-radius:50%;--color:initial;--padding-start:8px;--padding-end:8px;width:48px;height:48px;font-size:24px}:host(.ion-color.ion-focused)::after{background:var(--ion-color-base)}@media (any-hover: hover){:host(.ion-color:hover) .button-native::after{background:var(--ion-color-base)}}";
466
467const MenuButton = class {
468 constructor(hostRef) {
469 index.registerInstance(this, hostRef);
470 this.inheritedAttributes = {};
471 this.visible = false;
472 /**
473 * If `true`, the user cannot interact with the menu button.
474 */
475 this.disabled = false;
476 /**
477 * Automatically hides the menu button when the corresponding menu is not active
478 */
479 this.autoHide = true;
480 /**
481 * The type of the button.
482 */
483 this.type = 'button';
484 this.onClick = async () => {
485 return index$1.menuController.toggle(this.menu);
486 };
487 }
488 componentWillLoad() {
489 this.inheritedAttributes = helpers.inheritAttributes(this.el, ['aria-label']);
490 }
491 componentDidLoad() {
492 this.visibilityChanged();
493 }
494 async visibilityChanged() {
495 this.visible = await updateVisibility(this.menu);
496 }
497 render() {
498 const { color, disabled, inheritedAttributes } = this;
499 const mode = ionicGlobal.getIonMode(this);
500 const menuIcon = ionicGlobal.config.get('menuIcon', mode === 'ios' ? 'menu-outline' : 'menu-sharp');
501 const hidden = this.autoHide && !this.visible;
502 const attrs = {
503 type: this.type
504 };
505 const ariaLabel = inheritedAttributes['aria-label'] || 'menu';
506 return (index.h(index.Host, { onClick: this.onClick, "aria-disabled": disabled ? 'true' : null, "aria-hidden": hidden ? 'true' : null, class: theme.createColorClasses(color, {
507 [mode]: true,
508 'button': true,
509 'menu-button-hidden': hidden,
510 'menu-button-disabled': disabled,
511 'in-toolbar': theme.hostContext('ion-toolbar', this.el),
512 'in-toolbar-color': theme.hostContext('ion-toolbar[color]', this.el),
513 'ion-activatable': true,
514 'ion-focusable': true
515 }) }, index.h("button", Object.assign({}, attrs, { disabled: disabled, class: "button-native", part: "native", "aria-label": ariaLabel }), index.h("span", { class: "button-inner" }, index.h("slot", null, index.h("ion-icon", { part: "icon", icon: menuIcon, mode: mode, lazy: false, "aria-hidden": "true" }))), mode === 'md' && index.h("ion-ripple-effect", { type: "unbounded" }))));
516 }
517 get el() { return index.getElement(this); }
518};
519MenuButton.style = {
520 ios: menuButtonIosCss,
521 md: menuButtonMdCss
522};
523
524const menuToggleCss = ":host(.menu-toggle-hidden){display:none}";
525
526const MenuToggle = class {
527 constructor(hostRef) {
528 index.registerInstance(this, hostRef);
529 this.visible = false;
530 /**
531 * Automatically hides the content when the corresponding menu is not active.
532 *
533 * By default, it's `true`. Change it to `false` in order to
534 * keep `ion-menu-toggle` always visible regardless the state of the menu.
535 */
536 this.autoHide = true;
537 this.onClick = () => {
538 return index$1.menuController.toggle(this.menu);
539 };
540 }
541 connectedCallback() {
542 this.visibilityChanged();
543 }
544 async visibilityChanged() {
545 this.visible = await updateVisibility(this.menu);
546 }
547 render() {
548 const mode = ionicGlobal.getIonMode(this);
549 const hidden = this.autoHide && !this.visible;
550 return (index.h(index.Host, { onClick: this.onClick, "aria-hidden": hidden ? 'true' : null, class: {
551 [mode]: true,
552 'menu-toggle-hidden': hidden,
553 } }, index.h("slot", null)));
554 }
555};
556MenuToggle.style = menuToggleCss;
557
558exports.ion_menu = Menu;
559exports.ion_menu_button = MenuButton;
560exports.ion_menu_toggle = MenuToggle;