UNPKG

@ionic/vue

Version:

Vue specific wrapper for @ionic/core

1,307 lines (1,293 loc) • 90.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const vue = require('vue'); const ionAccordion_js = require('@ionic/core/components/ion-accordion.js'); const ionAccordionGroup_js = require('@ionic/core/components/ion-accordion-group.js'); const ionAvatar_js = require('@ionic/core/components/ion-avatar.js'); const ionBackdrop_js = require('@ionic/core/components/ion-backdrop.js'); const ionBadge_js = require('@ionic/core/components/ion-badge.js'); const ionBreadcrumb_js = require('@ionic/core/components/ion-breadcrumb.js'); const ionBreadcrumbs_js = require('@ionic/core/components/ion-breadcrumbs.js'); const ionButton_js = require('@ionic/core/components/ion-button.js'); const ionButtons_js = require('@ionic/core/components/ion-buttons.js'); const ionCard_js = require('@ionic/core/components/ion-card.js'); const ionCardContent_js = require('@ionic/core/components/ion-card-content.js'); const ionCardHeader_js = require('@ionic/core/components/ion-card-header.js'); const ionCardSubtitle_js = require('@ionic/core/components/ion-card-subtitle.js'); const ionCardTitle_js = require('@ionic/core/components/ion-card-title.js'); const ionCheckbox_js = require('@ionic/core/components/ion-checkbox.js'); const ionChip_js = require('@ionic/core/components/ion-chip.js'); const ionCol_js = require('@ionic/core/components/ion-col.js'); const ionContent_js = require('@ionic/core/components/ion-content.js'); const ionDatetime_js = require('@ionic/core/components/ion-datetime.js'); const ionDatetimeButton_js = require('@ionic/core/components/ion-datetime-button.js'); const ionFab_js = require('@ionic/core/components/ion-fab.js'); const ionFabButton_js = require('@ionic/core/components/ion-fab-button.js'); const ionFabList_js = require('@ionic/core/components/ion-fab-list.js'); const ionFooter_js = require('@ionic/core/components/ion-footer.js'); const ionGrid_js = require('@ionic/core/components/ion-grid.js'); const ionHeader_js = require('@ionic/core/components/ion-header.js'); const ionImg_js = require('@ionic/core/components/ion-img.js'); const ionInfiniteScroll_js = require('@ionic/core/components/ion-infinite-scroll.js'); const ionInfiniteScrollContent_js = require('@ionic/core/components/ion-infinite-scroll-content.js'); const ionInput_js = require('@ionic/core/components/ion-input.js'); const ionItem_js = require('@ionic/core/components/ion-item.js'); const ionItemDivider_js = require('@ionic/core/components/ion-item-divider.js'); const ionItemGroup_js = require('@ionic/core/components/ion-item-group.js'); const ionItemOption_js = require('@ionic/core/components/ion-item-option.js'); const ionItemOptions_js = require('@ionic/core/components/ion-item-options.js'); const ionItemSliding_js = require('@ionic/core/components/ion-item-sliding.js'); const ionLabel_js = require('@ionic/core/components/ion-label.js'); const ionList_js = require('@ionic/core/components/ion-list.js'); const ionListHeader_js = require('@ionic/core/components/ion-list-header.js'); const ionMenu_js = require('@ionic/core/components/ion-menu.js'); const ionMenuButton_js = require('@ionic/core/components/ion-menu-button.js'); const ionMenuToggle_js = require('@ionic/core/components/ion-menu-toggle.js'); const ionNav_js = require('@ionic/core/components/ion-nav.js'); const ionNavLink_js = require('@ionic/core/components/ion-nav-link.js'); const ionNote_js = require('@ionic/core/components/ion-note.js'); const ionProgressBar_js = require('@ionic/core/components/ion-progress-bar.js'); const ionRadio_js = require('@ionic/core/components/ion-radio.js'); const ionRadioGroup_js = require('@ionic/core/components/ion-radio-group.js'); const ionRange_js = require('@ionic/core/components/ion-range.js'); const ionRefresher_js = require('@ionic/core/components/ion-refresher.js'); const ionRefresherContent_js = require('@ionic/core/components/ion-refresher-content.js'); const ionReorder_js = require('@ionic/core/components/ion-reorder.js'); const ionReorderGroup_js = require('@ionic/core/components/ion-reorder-group.js'); const ionRippleEffect_js = require('@ionic/core/components/ion-ripple-effect.js'); const ionRow_js = require('@ionic/core/components/ion-row.js'); const ionSearchbar_js = require('@ionic/core/components/ion-searchbar.js'); const ionSegment_js = require('@ionic/core/components/ion-segment.js'); const ionSegmentButton_js = require('@ionic/core/components/ion-segment-button.js'); const ionSelect_js = require('@ionic/core/components/ion-select.js'); const ionSelectOption_js = require('@ionic/core/components/ion-select-option.js'); const ionSkeletonText_js = require('@ionic/core/components/ion-skeleton-text.js'); const ionSlide_js = require('@ionic/core/components/ion-slide.js'); const ionSlides_js = require('@ionic/core/components/ion-slides.js'); const ionSpinner_js = require('@ionic/core/components/ion-spinner.js'); const ionSplitPane_js = require('@ionic/core/components/ion-split-pane.js'); const ionText_js = require('@ionic/core/components/ion-text.js'); const ionTextarea_js = require('@ionic/core/components/ion-textarea.js'); const ionThumbnail_js = require('@ionic/core/components/ion-thumbnail.js'); const ionTitle_js = require('@ionic/core/components/ion-title.js'); const ionToggle_js = require('@ionic/core/components/ion-toggle.js'); const ionToolbar_js = require('@ionic/core/components/ion-toolbar.js'); const ionVirtualScroll_js = require('@ionic/core/components/ion-virtual-scroll.js'); const components = require('@ionic/core/components'); const ionBackButton_js = require('@ionic/core/components/ion-back-button.js'); const ionRouterOutlet_js = require('@ionic/core/components/ion-router-outlet.js'); const vueRouter = require('vue-router'); const ionTabButton_js = require('@ionic/core/components/ion-tab-button.js'); const ionTabBar_js = require('@ionic/core/components/ion-tab-bar.js'); const ionApp_js = require('@ionic/core/components/ion-app.js'); const ionIcon_js = require('ionicons/components/ion-icon.js'); const ionActionSheet_js = require('@ionic/core/components/ion-action-sheet.js'); const ionAlert_js = require('@ionic/core/components/ion-alert.js'); const ionLoading_js = require('@ionic/core/components/ion-loading.js'); const ionPicker_js = require('@ionic/core/components/ion-picker.js'); const ionToast_js = require('@ionic/core/components/ion-toast.js'); const ionModal_js = require('@ionic/core/components/ion-modal.js'); const ionPopover_js = require('@ionic/core/components/ion-popover.js'); const UPDATE_VALUE_EVENT = 'update:modelValue'; const MODEL_VALUE = 'modelValue'; const ROUTER_LINK_VALUE = 'routerLink'; const NAV_MANAGER = 'navManager'; const ROUTER_PROP_PREFIX = 'router'; /** * Starting in Vue 3.1.0, all properties are * added as keys to the props object, even if * they are not being used. In order to correctly * account for both value props and v-model props, * we need to check if the key exists for Vue <3.1.0 * and then check if it is not undefined for Vue >= 3.1.0. * See https://github.com/vuejs/vue-next/issues/3889 */ const EMPTY_PROP = Symbol(); const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP }; const getComponentClasses = (classes) => { return (classes === null || classes === void 0 ? void 0 : classes.split(' ')) || []; }; const getElementClasses = (ref, componentClasses, defaultClasses = []) => { var _a; return [...Array.from(((_a = ref.value) === null || _a === void 0 ? void 0 : _a.classList) || []), ...defaultClasses] .filter((c, i, self) => !componentClasses.has(c) && self.indexOf(c) === i); }; /** * Create a callback to define a Vue component wrapper around a Web Component. * * @prop name - The component tag name (i.e. `ion-button`) * @prop componentProps - An array of properties on the * component. These usually match up with the @Prop definitions * in each component's TSX file. * @prop customElement - An option custom element instance to pass * to customElements.define. Only set if `includeImportCustomElements: true` in your config. * @prop modelProp - The prop that v-model binds to (i.e. value) * @prop modelUpdateEvent - The event that is fired from your Web Component when the value changes (i.e. ionChange) * @prop externalModelUpdateEvent - The external event to fire from your Vue component when modelUpdateEvent fires. This is used for ensuring that v-model references have been * correctly updated when a user's event callback fires. */ const defineContainer = (name, defineCustomElement, componentProps = [], modelProp, modelUpdateEvent, externalModelUpdateEvent) => { /** * Create a Vue component wrapper around a Web Component. * Note: The `props` here are not all properties on a component. * They refer to whatever properties are set on an instance of a component. */ if (defineCustomElement !== undefined) { defineCustomElement(); } const Container = vue.defineComponent((props, { attrs, slots, emit }) => { var _a; let modelPropValue = props[modelProp]; const containerRef = vue.ref(); const classes = new Set(getComponentClasses(attrs.class)); const onVnodeBeforeMount = (vnode) => { // Add a listener to tell Vue to update the v-model if (vnode.el) { const eventsNames = Array.isArray(modelUpdateEvent) ? modelUpdateEvent : [modelUpdateEvent]; eventsNames.forEach((eventName) => { vnode.el.addEventListener(eventName.toLowerCase(), (e) => { modelPropValue = (e === null || e === void 0 ? void 0 : e.target)[modelProp]; emit(UPDATE_VALUE_EVENT, modelPropValue); /** * We need to emit the change event here * rather than on the web component to ensure * that any v-model bindings have been updated. * Otherwise, the developer will listen on the * native web component, but the v-model will * not have been updated yet. */ if (externalModelUpdateEvent) { emit(externalModelUpdateEvent, e); } }); }); } }; const currentInstance = vue.getCurrentInstance(); const hasRouter = (_a = currentInstance === null || currentInstance === void 0 ? void 0 : currentInstance.appContext) === null || _a === void 0 ? void 0 : _a.provides[NAV_MANAGER]; const navManager = hasRouter ? vue.inject(NAV_MANAGER) : undefined; const handleRouterLink = (ev) => { const { routerLink } = props; if (routerLink === EMPTY_PROP) return; if (navManager !== undefined) { let navigationPayload = { event: ev }; for (const key in props) { const value = props[key]; if (props.hasOwnProperty(key) && key.startsWith(ROUTER_PROP_PREFIX) && value !== EMPTY_PROP) { navigationPayload[key] = value; } } navManager.navigate(navigationPayload); } else { console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.'); } }; return () => { modelPropValue = props[modelProp]; getComponentClasses(attrs.class).forEach(value => { classes.add(value); }); const oldClick = props.onClick; const handleClick = (ev) => { if (oldClick !== undefined) { oldClick(ev); } if (!ev.defaultPrevented) { handleRouterLink(ev); } }; let propsToAdd = { ref: containerRef, class: getElementClasses(containerRef, classes), onClick: handleClick, onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined }; /** * We can use Object.entries here * to avoid the hasOwnProperty check, * but that would require 2 iterations * where as this only requires 1. */ for (const key in props) { const value = props[key]; if (props.hasOwnProperty(key) && value !== EMPTY_PROP) { propsToAdd[key] = value; } } if (modelProp) { /** * If form value property was set using v-model * then we should use that value. * Otherwise, check to see if form value property * was set as a static value (i.e. no v-model). */ if (props[MODEL_VALUE] !== EMPTY_PROP) { propsToAdd = Object.assign(Object.assign({}, propsToAdd), { [modelProp]: props[MODEL_VALUE] }); } else if (modelPropValue !== EMPTY_PROP) { propsToAdd = Object.assign(Object.assign({}, propsToAdd), { [modelProp]: modelPropValue }); } } return vue.h(name, propsToAdd, slots.default && slots.default()); }; }); Container.displayName = name; Container.props = { [ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP }; componentProps.forEach(componentProp => { Container.props[componentProp] = DEFAULT_EMPTY_PROP; }); if (modelProp) { Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP; Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent]; } return Container; }; /* eslint-disable */ const IonAccordion = /*@__PURE__*/ defineContainer('ion-accordion', ionAccordion_js.defineCustomElement, [ 'value', 'disabled', 'readonly', 'toggleIcon', 'toggleIconSlot' ]); const IonAccordionGroup = /*@__PURE__*/ defineContainer('ion-accordion-group', ionAccordionGroup_js.defineCustomElement, [ 'animated', 'multiple', 'value', 'disabled', 'readonly', 'expand', 'ionChange' ], 'value', 'v-ion-change', 'ionChange'); const IonAvatar = /*@__PURE__*/ defineContainer('ion-avatar', ionAvatar_js.defineCustomElement); const IonBackdrop = /*@__PURE__*/ defineContainer('ion-backdrop', ionBackdrop_js.defineCustomElement, [ 'visible', 'tappable', 'stopPropagation', 'ionBackdropTap' ]); const IonBadge = /*@__PURE__*/ defineContainer('ion-badge', ionBadge_js.defineCustomElement, [ 'color' ]); const IonBreadcrumb = /*@__PURE__*/ defineContainer('ion-breadcrumb', ionBreadcrumb_js.defineCustomElement, [ 'collapsed', 'last', 'showCollapsedIndicator', 'color', 'active', 'disabled', 'download', 'href', 'rel', 'separator', 'target', 'routerDirection', 'routerAnimation', 'ionFocus', 'ionBlur', 'collapsedClick' ]); const IonBreadcrumbs = /*@__PURE__*/ defineContainer('ion-breadcrumbs', ionBreadcrumbs_js.defineCustomElement, [ 'color', 'maxItems', 'itemsBeforeCollapse', 'itemsAfterCollapse', 'ionCollapsedClick' ]); const IonButton = /*@__PURE__*/ defineContainer('ion-button', ionButton_js.defineCustomElement, [ 'color', 'buttonType', 'disabled', 'expand', 'fill', 'routerDirection', 'routerAnimation', 'download', 'href', 'rel', 'shape', 'size', 'strong', 'target', 'type', 'form', 'ionFocus', 'ionBlur' ]); const IonButtons = /*@__PURE__*/ defineContainer('ion-buttons', ionButtons_js.defineCustomElement, [ 'collapse' ]); const IonCard = /*@__PURE__*/ defineContainer('ion-card', ionCard_js.defineCustomElement, [ 'color', 'button', 'type', 'disabled', 'download', 'href', 'rel', 'routerDirection', 'routerAnimation', 'target' ]); const IonCardContent = /*@__PURE__*/ defineContainer('ion-card-content', ionCardContent_js.defineCustomElement); const IonCardHeader = /*@__PURE__*/ defineContainer('ion-card-header', ionCardHeader_js.defineCustomElement, [ 'color', 'translucent' ]); const IonCardSubtitle = /*@__PURE__*/ defineContainer('ion-card-subtitle', ionCardSubtitle_js.defineCustomElement, [ 'color' ]); const IonCardTitle = /*@__PURE__*/ defineContainer('ion-card-title', ionCardTitle_js.defineCustomElement, [ 'color' ]); const IonCheckbox = /*@__PURE__*/ defineContainer('ion-checkbox', ionCheckbox_js.defineCustomElement, [ 'color', 'name', 'checked', 'indeterminate', 'disabled', 'value', 'ionChange', 'ionFocus', 'ionBlur', 'ionStyle' ], 'checked', 'v-ion-change', 'ionChange'); const IonChip = /*@__PURE__*/ defineContainer('ion-chip', ionChip_js.defineCustomElement, [ 'color', 'outline', 'disabled' ]); const IonCol = /*@__PURE__*/ defineContainer('ion-col', ionCol_js.defineCustomElement, [ 'offset', 'offsetXs', 'offsetSm', 'offsetMd', 'offsetLg', 'offsetXl', 'pull', 'pullXs', 'pullSm', 'pullMd', 'pullLg', 'pullXl', 'push', 'pushXs', 'pushSm', 'pushMd', 'pushLg', 'pushXl', 'size', 'sizeXs', 'sizeSm', 'sizeMd', 'sizeLg', 'sizeXl' ]); const IonContent = /*@__PURE__*/ defineContainer('ion-content', ionContent_js.defineCustomElement, [ 'color', 'fullscreen', 'forceOverscroll', 'scrollX', 'scrollY', 'scrollEvents', 'ionScrollStart', 'ionScroll', 'ionScrollEnd' ]); const IonDatetime = /*@__PURE__*/ defineContainer('ion-datetime', ionDatetime_js.defineCustomElement, [ 'color', 'name', 'disabled', 'readonly', 'isDateEnabled', 'min', 'max', 'presentation', 'cancelText', 'doneText', 'clearText', 'yearValues', 'monthValues', 'dayValues', 'hourValues', 'minuteValues', 'locale', 'firstDayOfWeek', 'titleSelectedDatesFormatter', 'multiple', 'value', 'showDefaultTitle', 'showDefaultButtons', 'showClearButton', 'showDefaultTimeLabel', 'hourCycle', 'size', 'preferWheel', 'ionCancel', 'ionChange', 'ionFocus', 'ionBlur', 'ionStyle', 'ionRender' ], 'value', 'v-ion-change', 'ionChange'); const IonDatetimeButton = /*@__PURE__*/ defineContainer('ion-datetime-button', ionDatetimeButton_js.defineCustomElement, [ 'color', 'disabled', 'datetime' ]); const IonFab = /*@__PURE__*/ defineContainer('ion-fab', ionFab_js.defineCustomElement, [ 'horizontal', 'vertical', 'edge', 'activated' ]); const IonFabButton = /*@__PURE__*/ defineContainer('ion-fab-button', ionFabButton_js.defineCustomElement, [ 'color', 'activated', 'disabled', 'download', 'href', 'rel', 'routerDirection', 'routerAnimation', 'target', 'show', 'translucent', 'type', 'size', 'closeIcon', 'ionFocus', 'ionBlur' ]); const IonFabList = /*@__PURE__*/ defineContainer('ion-fab-list', ionFabList_js.defineCustomElement, [ 'activated', 'side' ]); const IonFooter = /*@__PURE__*/ defineContainer('ion-footer', ionFooter_js.defineCustomElement, [ 'collapse', 'translucent' ]); const IonGrid = /*@__PURE__*/ defineContainer('ion-grid', ionGrid_js.defineCustomElement, [ 'fixed' ]); const IonHeader = /*@__PURE__*/ defineContainer('ion-header', ionHeader_js.defineCustomElement, [ 'collapse', 'translucent' ]); const IonImg = /*@__PURE__*/ defineContainer('ion-img', ionImg_js.defineCustomElement, [ 'alt', 'src', 'ionImgWillLoad', 'ionImgDidLoad', 'ionError' ]); const IonInfiniteScroll = /*@__PURE__*/ defineContainer('ion-infinite-scroll', ionInfiniteScroll_js.defineCustomElement, [ 'threshold', 'disabled', 'position', 'ionInfinite' ]); const IonInfiniteScrollContent = /*@__PURE__*/ defineContainer('ion-infinite-scroll-content', ionInfiniteScrollContent_js.defineCustomElement, [ 'loadingSpinner', 'loadingText' ]); const IonInput = /*@__PURE__*/ defineContainer('ion-input', ionInput_js.defineCustomElement, [ 'fireFocusEvents', 'color', 'accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'debounce', 'disabled', 'enterkeyhint', 'inputmode', 'max', 'maxlength', 'min', 'minlength', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'spellcheck', 'step', 'size', 'type', 'value', 'ionInput', 'ionChange', 'ionBlur', 'ionFocus', 'ionStyle' ], 'value', 'v-ion-change', 'ionChange'); const IonItem = /*@__PURE__*/ defineContainer('ion-item', ionItem_js.defineCustomElement, [ 'color', 'button', 'detail', 'detailIcon', 'disabled', 'download', 'fill', 'shape', 'href', 'rel', 'lines', 'counter', 'routerAnimation', 'routerDirection', 'target', 'type', 'counterFormatter' ]); const IonItemDivider = /*@__PURE__*/ defineContainer('ion-item-divider', ionItemDivider_js.defineCustomElement, [ 'color', 'sticky' ]); const IonItemGroup = /*@__PURE__*/ defineContainer('ion-item-group', ionItemGroup_js.defineCustomElement); const IonItemOption = /*@__PURE__*/ defineContainer('ion-item-option', ionItemOption_js.defineCustomElement, [ 'color', 'disabled', 'download', 'expandable', 'href', 'rel', 'target', 'type' ]); const IonItemOptions = /*@__PURE__*/ defineContainer('ion-item-options', ionItemOptions_js.defineCustomElement, [ 'side', 'ionSwipe' ]); const IonItemSliding = /*@__PURE__*/ defineContainer('ion-item-sliding', ionItemSliding_js.defineCustomElement, [ 'disabled', 'ionDrag' ]); const IonLabel = /*@__PURE__*/ defineContainer('ion-label', ionLabel_js.defineCustomElement, [ 'color', 'position', 'ionColor', 'ionStyle' ]); const IonList = /*@__PURE__*/ defineContainer('ion-list', ionList_js.defineCustomElement, [ 'lines', 'inset' ]); const IonListHeader = /*@__PURE__*/ defineContainer('ion-list-header', ionListHeader_js.defineCustomElement, [ 'color', 'lines' ]); const IonMenu = /*@__PURE__*/ defineContainer('ion-menu', ionMenu_js.defineCustomElement, [ 'contentId', 'menuId', 'type', 'disabled', 'side', 'swipeGesture', 'maxEdgeStart', 'ionWillOpen', 'ionWillClose', 'ionDidOpen', 'ionDidClose', 'ionMenuChange' ]); const IonMenuButton = /*@__PURE__*/ defineContainer('ion-menu-button', ionMenuButton_js.defineCustomElement, [ 'color', 'disabled', 'menu', 'autoHide', 'type' ]); const IonMenuToggle = /*@__PURE__*/ defineContainer('ion-menu-toggle', ionMenuToggle_js.defineCustomElement, [ 'menu', 'autoHide' ]); const IonNavLink = /*@__PURE__*/ defineContainer('ion-nav-link', ionNavLink_js.defineCustomElement, [ 'component', 'componentProps', 'routerDirection', 'routerAnimation' ]); const IonNote = /*@__PURE__*/ defineContainer('ion-note', ionNote_js.defineCustomElement, [ 'color' ]); const IonProgressBar = /*@__PURE__*/ defineContainer('ion-progress-bar', ionProgressBar_js.defineCustomElement, [ 'type', 'reversed', 'value', 'buffer', 'color' ]); const IonRadio = /*@__PURE__*/ defineContainer('ion-radio', ionRadio_js.defineCustomElement, [ 'color', 'name', 'disabled', 'value', 'ionStyle', 'ionFocus', 'ionBlur' ], 'value', 'v-ion-change', 'ionChange'); const IonRadioGroup = /*@__PURE__*/ defineContainer('ion-radio-group', ionRadioGroup_js.defineCustomElement, [ 'allowEmptySelection', 'name', 'value', 'ionChange' ], 'value', 'v-ion-change', 'ionChange'); const IonRange = /*@__PURE__*/ defineContainer('ion-range', ionRange_js.defineCustomElement, [ 'color', 'debounce', 'name', 'dualKnobs', 'min', 'max', 'pin', 'pinFormatter', 'snaps', 'step', 'ticks', 'activeBarStart', 'disabled', 'value', 'ionChange', 'ionStyle', 'ionFocus', 'ionBlur', 'ionKnobMoveStart', 'ionKnobMoveEnd' ], 'value', 'v-ion-change', 'ionChange'); const IonRefresher = /*@__PURE__*/ defineContainer('ion-refresher', ionRefresher_js.defineCustomElement, [ 'pullMin', 'pullMax', 'closeDuration', 'snapbackDuration', 'pullFactor', 'disabled', 'ionRefresh', 'ionPull', 'ionStart' ]); const IonRefresherContent = /*@__PURE__*/ defineContainer('ion-refresher-content', ionRefresherContent_js.defineCustomElement, [ 'pullingIcon', 'pullingText', 'refreshingSpinner', 'refreshingText' ]); const IonReorder = /*@__PURE__*/ defineContainer('ion-reorder', ionReorder_js.defineCustomElement); const IonReorderGroup = /*@__PURE__*/ defineContainer('ion-reorder-group', ionReorderGroup_js.defineCustomElement, [ 'disabled', 'ionItemReorder' ]); const IonRippleEffect = /*@__PURE__*/ defineContainer('ion-ripple-effect', ionRippleEffect_js.defineCustomElement, [ 'type' ]); const IonRow = /*@__PURE__*/ defineContainer('ion-row', ionRow_js.defineCustomElement); const IonSearchbar = /*@__PURE__*/ defineContainer('ion-searchbar', ionSearchbar_js.defineCustomElement, [ 'color', 'animated', 'autocomplete', 'autocorrect', 'cancelButtonIcon', 'cancelButtonText', 'clearIcon', 'debounce', 'disabled', 'inputmode', 'enterkeyhint', 'placeholder', 'searchIcon', 'showCancelButton', 'showClearButton', 'spellcheck', 'type', 'value', 'ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus', 'ionStyle' ], 'value', 'v-ion-change', 'ionChange'); const IonSegment = /*@__PURE__*/ defineContainer('ion-segment', ionSegment_js.defineCustomElement, [ 'color', 'disabled', 'scrollable', 'swipeGesture', 'value', 'selectOnFocus', 'ionChange', 'ionSelect', 'ionStyle' ], 'value', 'v-ion-change', 'ionChange'); const IonSegmentButton = /*@__PURE__*/ defineContainer('ion-segment-button', ionSegmentButton_js.defineCustomElement, [ 'disabled', 'layout', 'type', 'value' ], 'value', 'v-ion-change', 'ionChange'); const IonSelect = /*@__PURE__*/ defineContainer('ion-select', ionSelect_js.defineCustomElement, [ 'disabled', 'cancelText', 'okText', 'placeholder', 'name', 'selectedText', 'multiple', 'interface', 'interfaceOptions', 'compareWith', 'value', 'ionChange', 'ionCancel', 'ionDismiss', 'ionFocus', 'ionBlur', 'ionStyle' ], 'value', 'v-ion-change', 'ionChange'); const IonSelectOption = /*@__PURE__*/ defineContainer('ion-select-option', ionSelectOption_js.defineCustomElement, [ 'disabled', 'value' ]); const IonSkeletonText = /*@__PURE__*/ defineContainer('ion-skeleton-text', ionSkeletonText_js.defineCustomElement, [ 'animated' ]); const IonSlide = /*@__PURE__*/ defineContainer('ion-slide', ionSlide_js.defineCustomElement); const IonSlides = /*@__PURE__*/ defineContainer('ion-slides', ionSlides_js.defineCustomElement, [ 'options', 'pager', 'scrollbar', 'ionSlidesDidLoad', 'ionSlideTap', 'ionSlideDoubleTap', 'ionSlideWillChange', 'ionSlideDidChange', 'ionSlideNextStart', 'ionSlidePrevStart', 'ionSlideNextEnd', 'ionSlidePrevEnd', 'ionSlideTransitionStart', 'ionSlideTransitionEnd', 'ionSlideDrag', 'ionSlideReachStart', 'ionSlideReachEnd', 'ionSlideTouchStart', 'ionSlideTouchEnd' ]); const IonSpinner = /*@__PURE__*/ defineContainer('ion-spinner', ionSpinner_js.defineCustomElement, [ 'color', 'duration', 'name', 'paused' ]); const IonSplitPane = /*@__PURE__*/ defineContainer('ion-split-pane', ionSplitPane_js.defineCustomElement, [ 'contentId', 'disabled', 'when', 'ionSplitPaneVisible' ]); const IonText = /*@__PURE__*/ defineContainer('ion-text', ionText_js.defineCustomElement, [ 'color' ]); const IonTextarea = /*@__PURE__*/ defineContainer('ion-textarea', ionTextarea_js.defineCustomElement, [ 'fireFocusEvents', 'color', 'autocapitalize', 'autofocus', 'clearOnEdit', 'debounce', 'disabled', 'inputmode', 'enterkeyhint', 'maxlength', 'minlength', 'name', 'placeholder', 'readonly', 'required', 'spellcheck', 'cols', 'rows', 'wrap', 'autoGrow', 'value', 'ionChange', 'ionInput', 'ionStyle', 'ionBlur', 'ionFocus' ], 'value', 'v-ion-change', 'ionChange'); const IonThumbnail = /*@__PURE__*/ defineContainer('ion-thumbnail', ionThumbnail_js.defineCustomElement); const IonTitle = /*@__PURE__*/ defineContainer('ion-title', ionTitle_js.defineCustomElement, [ 'color', 'size', 'ionStyle' ]); const IonToggle = /*@__PURE__*/ defineContainer('ion-toggle', ionToggle_js.defineCustomElement, [ 'color', 'name', 'checked', 'disabled', 'value', 'enableOnOffLabels', 'ionChange', 'ionFocus', 'ionBlur', 'ionStyle' ], 'checked', 'v-ion-change', 'ionChange'); const IonToolbar = /*@__PURE__*/ defineContainer('ion-toolbar', ionToolbar_js.defineCustomElement, [ 'color' ]); const IonVirtualScroll = /*@__PURE__*/ defineContainer('ion-virtual-scroll', ionVirtualScroll_js.defineCustomElement, [ 'approxItemHeight', 'approxHeaderHeight', 'approxFooterHeight', 'headerFn', 'footerFn', 'items', 'itemHeight', 'headerHeight', 'footerHeight', 'renderItem', 'renderHeader', 'renderFooter', 'nodeRender', 'domRender' ]); const useBackButton = (priority, handler) => { const callback = (ev) => ev.detail.register(priority, handler); const unregister = () => document.removeEventListener('ionBackButton', callback); document.addEventListener('ionBackButton', callback); return { unregister }; }; const useKeyboard = () => { let isOpen = vue.ref(false); let keyboardHeight = vue.ref(0); const showCallback = (ev) => { isOpen.value = true; keyboardHeight.value = ev.detail.keyboardHeight; }; const hideCallback = () => { isOpen.value = false; keyboardHeight.value = 0; }; const unregister = () => { if (typeof window !== 'undefined') { window.removeEventListener('ionKeyboardDidShow', showCallback); window.removeEventListener('ionKeyboardDidHide', hideCallback); } }; if (typeof window !== 'undefined') { window.addEventListener('ionKeyboardDidShow', showCallback); window.addEventListener('ionKeyboardDidHide', hideCallback); } return { isOpen, keyboardHeight, unregister }; }; var LifecycleHooks; (function (LifecycleHooks) { LifecycleHooks["WillEnter"] = "onIonViewWillEnter"; LifecycleHooks["DidEnter"] = "onIonViewDidEnter"; LifecycleHooks["WillLeave"] = "onIonViewWillLeave"; LifecycleHooks["DidLeave"] = "onIonViewDidLeave"; })(LifecycleHooks || (LifecycleHooks = {})); const hookNames = { [components.LIFECYCLE_WILL_ENTER]: LifecycleHooks.WillEnter, [components.LIFECYCLE_DID_ENTER]: LifecycleHooks.DidEnter, [components.LIFECYCLE_WILL_LEAVE]: LifecycleHooks.WillLeave, [components.LIFECYCLE_DID_LEAVE]: LifecycleHooks.DidLeave }; const ids = { main: 0 }; const generateId = (type = 'main') => { var _a; const id = ((_a = ids[type]) !== null && _a !== void 0 ? _a : 0) + 1; ids[type] = id; return (id).toString(); }; const fireLifecycle = (vueComponent, vueInstance, lifecycle) => { if (vueComponent === null || vueComponent === void 0 ? void 0 : vueComponent[lifecycle]) { vueComponent[lifecycle].bind(vueInstance === null || vueInstance === void 0 ? void 0 : vueInstance.value)(); } const instance = vueInstance === null || vueInstance === void 0 ? void 0 : vueInstance.value; if (instance === null || instance === void 0 ? void 0 : instance[lifecycle]) { instance[lifecycle](); } /** * Fire any Composition API * Ionic Lifecycle hooks */ if (instance) { const hook = hookNames[lifecycle]; const hooks = instance[hook]; if (hooks) { hooks.forEach((hook) => hook()); } } }; const getConfig = () => { if (typeof window !== 'undefined') { const Ionic = window.Ionic; if (Ionic && Ionic.config) { return Ionic.config; } } return null; }; /** * Creates an returns a function that * can be used to provide a lifecycle hook. */ const injectHook = (lifecycleType, hook, component) => { if (component) { // Add to public instance so it is accessible to IonRouterOutlet const target = component; const hooks = target.proxy[lifecycleType] || (target.proxy[lifecycleType] = []); /** * Define property on public instances using `setup` syntax in Vue 3.x */ if (target.exposed) { target.exposed[lifecycleType] = hooks; } const wrappedHook = (...args) => { if (target.isUnmounted) { return; } return args ? hook(...args) : hook(); }; hooks.push(wrappedHook); return wrappedHook; } else { console.warn('[@ionic/vue]: Ionic Lifecycle Hooks can only be used during execution of setup().'); } }; const createHook = (lifecycle) => { return (hook, target = vue.getCurrentInstance()) => injectHook(lifecycle, hook, target); }; const onIonViewWillEnter = createHook(LifecycleHooks.WillEnter); const onIonViewDidEnter = createHook(LifecycleHooks.DidEnter); const onIonViewWillLeave = createHook(LifecycleHooks.WillLeave); const onIonViewDidLeave = createHook(LifecycleHooks.DidLeave); /** * Used to navigate within Vue Router * while controlling the animation. */ const useIonRouter = () => { const { canGoBack, goBack, goForward, handleNavigate } = vue.inject('navManager'); const navigate = (location, routerDirection, routerAction, routerAnimation) => handleNavigate(location, routerAction, routerDirection, routerAnimation); const push = (location, routerAnimation) => navigate(location, 'forward', 'push', routerAnimation); const replace = (location, routerAnimation) => navigate(location, 'root', 'replace', routerAnimation); const back = (routerAnimation) => goBack(routerAnimation); const forward = (routerAnimation) => goForward(routerAnimation); return { canGoBack, push, replace, back, forward, navigate }; }; /** * We need to make sure that the web component fires an event * that will not conflict with the user's @ionChange binding, * otherwise the binding's callback will fire before any * v-model values have been updated. */ const toKebabCase = (eventName) => eventName === 'ionChange' ? 'v-ion-change' : eventName.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase(); const getHelperFunctions = () => { return { ael: (el, eventName, cb, opts) => el.addEventListener(toKebabCase(eventName), cb, opts), rel: (el, eventName, cb, opts) => el.removeEventListener(toKebabCase(eventName), cb, opts), ce: (eventName, opts) => new CustomEvent(toKebabCase(eventName), opts) }; }; const IonicVue = { async install(_, config = {}) { /** * By default Ionic Framework hides elements that * are not hydrated, but in the CE build there is no * hydration. * TODO FW-2797: Remove when all integrations have been * migrated to CE build. */ if (typeof document !== 'undefined') { document.documentElement.classList.add('ion-ce'); } const { ael, rel, ce } = getHelperFunctions(); components.initialize(Object.assign(Object.assign({}, config), { _ael: ael, _rel: rel, _ce: ce })); } }; const IonBackButton = /*@__PURE__*/ vue.defineComponent((_, { attrs, slots }) => { ionBackButton_js.defineCustomElement(); const ionRouter = vue.inject('navManager'); const onClick = () => { /** * When using ion-back-button outside of * a routing context, ionRouter is undefined. */ if (ionRouter === undefined) { return; } const defaultHref = attrs['default-href'] || attrs['defaultHref']; const routerAnimation = attrs['router-animation'] || attrs['routerAnimation']; ionRouter.handleNavigateBack(defaultHref, routerAnimation); }; return () => { return vue.h('ion-back-button', Object.assign({ onClick }, attrs), slots.default && slots.default()); }; }); const IonPage = /*@__PURE__*/ vue.defineComponent({ name: 'IonPage', props: { registerIonPage: { type: Function, default: () => { } } }, mounted() { this.$props.registerIonPage(this.$refs.ionPage); }, setup(_, { attrs, slots }) { return () => { return vue.h('div', Object.assign(Object.assign({}, attrs), { ['class']: 'ion-page', ref: 'ionPage' }), slots.default && slots.default()); }; } }); const isViewVisible = (enteringEl) => { return !enteringEl.classList.contains('ion-page-hidden') && !enteringEl.classList.contains('ion-page-invisible'); }; let viewDepthKey = Symbol(0); const IonRouterOutlet = /*@__PURE__*/ vue.defineComponent({ name: 'IonRouterOutlet', setup() { ionRouterOutlet_js.defineCustomElement(); const injectedRoute = vue.inject(vueRouter.routeLocationKey); const route = vueRouter.useRoute(); const depth = vue.inject(viewDepthKey, 0); const matchedRouteRef = vue.computed(() => route.matched[depth]); let previousMatchedRouteRef; let previousMatchedPath; vue.provide(viewDepthKey, depth + 1); vue.provide(vueRouter.matchedRouteKey, matchedRouteRef); const ionRouterOutlet = vue.ref(); const id = generateId('ion-router-outlet'); const ionRouter = vue.inject('navManager'); const viewStacks = vue.inject('viewStacks'); const components$1 = vue.shallowRef([]); let skipTransition = false; // The base url for this router outlet let parentOutletPath; /** * Note: Do not listen for matchedRouteRef by itself here * as the callback will not fire for parameterized routes (i.e. /page/:id). * So going from /page/1 to /page/2 would not fire this callback if we * only listened for changes to matchedRouteRef. */ vue.watch(() => [route, matchedRouteRef.value], ([currentRoute, currentMatchedRouteRef]) => { /** * This callback checks whether or not a router outlet * needs to respond to a change in the matched route. * It handles a few cases: * 1. The matched route is undefined. This means that * the matched route is not applicable to this outlet. * For example, a /settings route is not applicable * to a /tabs/... route. * * Note: When going back to a tabs outlet from a non-tabs outlet, * the tabs outlet should NOT attempt a page transition from the * previous tab to the active tab. To do this we compare the current * route with the previous route. Unfortunately, we cannot rely on the * previous value provided by Vue in the watch callback. This is because * when coming back to the tabs context, the previous matched route will * be undefined (because nothing in the tabs context matches /settings) * but the current matched route will be defined and so a transition * will always occur. * * 2. The matched route is defined and is different than * the previously matched route. This is the most * common case such as when you go from /page1 to /page2. * * 3. The matched route is the same but the parameters are different. * This is a special case for parameterized routes (i.e. /page/:id). * When going from /page/1 to /page/2, the matched route object will * be the same, but we still need to perform a page transition. To do this * we check if the parameters are different (i.e. 1 vs 2). To avoid enumerating * all of the keys in the params object, we check the url path to * see if they are different after ensuring we are in a parameterized route. */ if (currentMatchedRouteRef !== undefined) { const matchedDifferentRoutes = currentMatchedRouteRef !== previousMatchedRouteRef; const matchedDifferentParameterRoutes = (currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef && currentRoute.path !== previousMatchedPath); if (matchedDifferentRoutes || matchedDifferentParameterRoutes) { setupViewItem(matchedRouteRef); } } previousMatchedRouteRef = currentMatchedRouteRef; previousMatchedPath = currentRoute.path; }); const canStart = () => { const config = getConfig(); const swipeEnabled = config && config.get('swipeBackEnabled', ionRouterOutlet.value.mode === 'ios'); if (!swipeEnabled) return false; const stack = viewStacks.getViewStack(id); if (!stack || stack.length <= 1) return false; /** * We only want to outlet of the entering view * to respond to this gesture, so check * to make sure the view is in the outlet we want. */ const routeInfo = ionRouter.getLeavingRouteInfo(); const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); return !!enteringViewItem; }; const onStart = async () => { const routeInfo = ionRouter.getLeavingRouteInfo(); const { routerAnimation } = routeInfo; const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id); if (leavingViewItem) { let animationBuilder = routerAnimation; const enteringEl = enteringViewItem.ionPageElement; const leavingEl = leavingViewItem.ionPageElement; /** * If we are going back from a page that * was presented using a custom animation * we should default to using that * unless the developer explicitly * provided another animation. */ const customAnimation = enteringViewItem.routerAnimation; if (animationBuilder === undefined && customAnimation !== undefined) { animationBuilder = customAnimation; } leavingViewItem.routerAnimation = animationBuilder; await transition(enteringEl, leavingEl, 'back', ionRouter.canGoBack(2), true, animationBuilder); } return Promise.resolve(); }; const onEnd = (shouldContinue) => { if (shouldContinue) { skipTransition = true; /** * Use the same logic as clicking * ion-back-button to determine where * to go back to. */ ionRouter.handleNavigateBack(); } else { /** * In the event that the swipe * gesture was aborted, we should * re-hide the page that was going to enter. */ const routeInfo = ionRouter.getCurrentRouteInfo(); const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); enteringViewItem.ionPageElement.setAttribute('aria-hidden', 'true'); enteringViewItem.ionPageElement.classList.add('ion-page-hidden'); } }; vue.watch(ionRouterOutlet, () => { ionRouterOutlet.value.swipeHandler = { canStart, onStart, onEnd }; }); const transition = (enteringEl, leavingEl, direction, showGoBack, progressAnimation, animationBuilder) => { return new Promise(resolve => { if (skipTransition) { skipTransition = false; return resolve(false); } if (enteringEl === leavingEl) { return resolve(false); } requestAnimationFrame(() => { requestAnimationFrame(async () => { enteringEl.classList.add('ion-page-invisible'); const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none'; const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, { deepWait: true, /** * replace operations result in a direction of none. * These typically do not have need animations, so we set * the duration to 0. However, if a developer explicitly * passes an animationBuilder, we should assume that * they want an animation to be played even * though it is a replace operation. */ duration: hasRootDirection && animationBuilder === undefined ? 0 : undefined, direction, showGoBack, progressAnimation, animationBuilder }); return resolve(result); }); }); }); }; const handlePageTransition = async () => { const routeInfo = ionRouter.getCurrentRouteInfo(); const { routerDirection, routerAction, routerAnimation, prevRouteLastPathname, delta } = routeInfo; const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id); let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id); const enteringEl = enteringViewItem.ionPageElement; /** * All views that can be transitioned to must have * an `<ion-page>` element for transitions and lifecycle * methods to work properly. */ if (enteringEl === undefined) { console.warn(`[@ionic/vue Warning]: The view you are trying to render for path ${routeInfo.pathname} does not have the required <ion-page> component. Transitions and lifecycle methods may not work as expected. See https://ionicframework.com/docs/vue/navigation#ionpage for more information.`); } if (enteringViewItem === leavingViewItem) return; if (!leavingViewItem && prevRouteLastPathname) { leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id); } /** * If the entering view is already * visible, then no transition is needed. * This is most common when navigating * from a tabs page to a non-tabs page * and then back to the tabs page. * Even when the tabs context navigated away, * the inner tabs page was still active. * This also avoids an issue where * the previous tabs page is incorrectly * unmounted since it would automatically * unmount the previous view. * * This should also only apply to entering and * leaving items in the same router outlet (i.e. * Tab1 and Tab2), otherwise this will * return early for swipe to go back when * going from a non-tabs page to a tabs page. */ if (isViewVisible(enteringEl) && (leavingViewItem === null || leavingViewItem === void 0 ? void 0 : leavingViewItem.ionPageElement) !== undefined && !isViewVisible(leavingViewItem.ionPageElement)) { return; } fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, components.LIFECYCLE_WILL_ENTER); if ((leavingViewItem === null || leavingViewItem === void 0 ? void 0 : leavingViewItem.ionPageElement) && enteringViewItem !== leavingViewItem) { let animationBuilder = routerAnimation; const leavingEl = leavingViewItem.ionPageElement; fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, components.LIFECYCLE_WILL_LEAVE); /** * If we are going back from a page that * was presented using a custom a