mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
fix(vue): update Stencil Vue output target (#30159)
This patch includes some necessary updates for `@stencil/vue-output-target@v0.9.0`: - we started to export Stencils helpers as runtime via `@stencil/vue-output-target/runtime` similar to what we did in React - this version requires some updates to Vue and TypeScript as well - adjustments related to that update
This commit is contained in:

committed by
GitHub

parent
0030be8195
commit
eb725fce6e
@ -3,20 +3,24 @@ import type { VNode } from "vue";
|
||||
import { h, defineComponent, shallowRef } from "vue";
|
||||
|
||||
const userComponents = shallowRef([]);
|
||||
export const IonApp = /*@__PURE__*/ defineComponent((_, { attrs, slots }) => {
|
||||
defineCustomElement();
|
||||
return () => {
|
||||
return h(
|
||||
"ion-app",
|
||||
{
|
||||
...attrs,
|
||||
},
|
||||
[slots.default && slots.default(), ...userComponents.value]
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
IonApp.name = "IonApp";
|
||||
export const IonApp = /*@__PURE__*/ defineComponent(
|
||||
(_, { attrs, slots }) => {
|
||||
defineCustomElement();
|
||||
return () => {
|
||||
return h(
|
||||
"ion-app",
|
||||
{
|
||||
name: "IonApp",
|
||||
...attrs,
|
||||
},
|
||||
[slots.default && slots.default(), ...userComponents.value]
|
||||
);
|
||||
};
|
||||
},
|
||||
{
|
||||
name: "IonApp",
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* When rendering user components inside of
|
||||
|
@ -34,7 +34,8 @@ export const IonBackButton = /*@__PURE__*/ defineComponent(
|
||||
slots.default && slots.default()
|
||||
);
|
||||
};
|
||||
},
|
||||
{
|
||||
name: "IonBackButton",
|
||||
}
|
||||
);
|
||||
|
||||
IonBackButton.name = "IonBackButton";
|
||||
|
@ -4,54 +4,56 @@ import { defineComponent, h, shallowRef } from "vue";
|
||||
|
||||
import { VueDelegate } from "../framework-delegate";
|
||||
|
||||
export const IonNav = /*@__PURE__*/ defineComponent((props) => {
|
||||
defineCustomElement();
|
||||
const views = shallowRef([]);
|
||||
export const IonNav = /*@__PURE__*/ defineComponent(
|
||||
(props) => {
|
||||
defineCustomElement();
|
||||
const views = shallowRef([]);
|
||||
|
||||
/**
|
||||
* Allows us to create the component
|
||||
* within the Vue application context.
|
||||
*/
|
||||
const addView = (component: VNode) =>
|
||||
(views.value = [...views.value, component]);
|
||||
const removeView = (component: VNode) =>
|
||||
(views.value = views.value.filter((cmp) => cmp !== component));
|
||||
/**
|
||||
* Allows us to create the component
|
||||
* within the Vue application context.
|
||||
*/
|
||||
const addView = (component: VNode) =>
|
||||
(views.value = [...views.value, component]);
|
||||
const removeView = (component: VNode) =>
|
||||
(views.value = views.value.filter((cmp) => cmp !== component));
|
||||
|
||||
const delegate = VueDelegate(addView, removeView);
|
||||
return () => {
|
||||
return h("ion-nav", { ...props, delegate }, views.value);
|
||||
};
|
||||
});
|
||||
|
||||
IonNav.name = "IonNav";
|
||||
|
||||
/**
|
||||
* The default values follow what is defined at
|
||||
* https://ionicframework.com/docs/api/nav#properties
|
||||
* otherwise the default values on the Web Component
|
||||
* may be overridden. For example, if the default animated value
|
||||
* is not `true` below, then Vue would default the prop to `false`
|
||||
* which would override the Web Component default of `true`.
|
||||
*/
|
||||
IonNav.props = {
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
const delegate = VueDelegate(addView, removeView);
|
||||
return () => {
|
||||
return h("ion-nav", { ...props, delegate }, views.value);
|
||||
};
|
||||
},
|
||||
animation: {
|
||||
type: Function,
|
||||
default: undefined,
|
||||
},
|
||||
root: {
|
||||
type: [Function, Object, String],
|
||||
default: undefined,
|
||||
},
|
||||
rootParams: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
swipeGesture: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
};
|
||||
{
|
||||
name: "IonNav",
|
||||
/**
|
||||
* The default values follow what is defined at
|
||||
* https://ionicframework.com/docs/api/nav#properties
|
||||
* otherwise the default values on the Web Component
|
||||
* may be overridden. For example, if the default animated value
|
||||
* is not `true` below, then Vue would default the prop to `false`
|
||||
* which would override the Web Component default of `true`.
|
||||
*/
|
||||
props: {
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
animation: {
|
||||
type: Function,
|
||||
default: undefined,
|
||||
},
|
||||
root: {
|
||||
type: [Function, Object, String],
|
||||
default: undefined,
|
||||
},
|
||||
rootParams: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
swipeGesture: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -44,7 +44,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
|
||||
let previousMatchedRouteRef: Ref | undefined;
|
||||
let previousMatchedPath: string | undefined;
|
||||
|
||||
provide(viewDepthKey, depth + 1);
|
||||
provide(viewDepthKey, (depth + 1) as 0);
|
||||
provide(matchedRouteKey, matchedRouteRef);
|
||||
|
||||
const ionRouterOutlet = ref();
|
||||
|
@ -43,7 +43,7 @@ export const IonTabBar = defineComponent({
|
||||
data() {
|
||||
return {
|
||||
tabState: {
|
||||
activeTab: undefined,
|
||||
activeTab: undefined as string | undefined,
|
||||
tabs: {},
|
||||
/**
|
||||
* Passing this prop to each tab button
|
||||
@ -52,7 +52,7 @@ export const IonTabBar = defineComponent({
|
||||
*/
|
||||
hasRouterOutlet: false,
|
||||
},
|
||||
tabVnodes: [],
|
||||
tabVnodes: [] as VNode[],
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
_tabsWillChange: { type: Function, default: () => {} },
|
||||
_tabsDidChange: { type: Function, default: () => {} },
|
||||
|
@ -3,19 +3,18 @@
|
||||
* Changes made to this file will be overwritten on build.
|
||||
*/
|
||||
|
||||
import {
|
||||
import type {
|
||||
JSX,
|
||||
} from '@ionic/core/components';
|
||||
|
||||
import { defineCustomElement as defineIonActionSheetCustomElement } from '@ionic/core/components/ion-action-sheet.js'
|
||||
import { defineCustomElement as defineIonAlertCustomElement } from '@ionic/core/components/ion-alert.js'
|
||||
import { defineCustomElement as defineIonLoadingCustomElement } from '@ionic/core/components/ion-loading.js'
|
||||
import { defineCustomElement as defineIonPickerLegacyCustomElement } from '@ionic/core/components/ion-picker-legacy.js'
|
||||
import { defineCustomElement as defineIonToastCustomElement } from '@ionic/core/components/ion-toast.js'
|
||||
import { defineCustomElement as defineIonModalCustomElement } from '@ionic/core/components/ion-modal.js'
|
||||
import { defineCustomElement as defineIonPickerLegacyCustomElement } from '@ionic/core/components/ion-picker-legacy.js'
|
||||
import { defineCustomElement as defineIonPopoverCustomElement } from '@ionic/core/components/ion-popover.js'
|
||||
import { defineCustomElement as defineIonToastCustomElement } from '@ionic/core/components/ion-toast.js'
|
||||
|
||||
import { defineOverlayContainer } from '../vue-component-lib/overlays';
|
||||
import { defineOverlayContainer } from '../utils/overlays';
|
||||
|
||||
export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer<JSX.IonActionSheet>('ion-action-sheet', defineIonActionSheetCustomElement, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent', 'trigger']);
|
||||
|
||||
@ -23,11 +22,11 @@ export const IonAlert = /*@__PURE__*/ defineOverlayContainer<JSX.IonAlert>('ion-
|
||||
|
||||
export const IonLoading = /*@__PURE__*/ defineOverlayContainer<JSX.IonLoading>('ion-loading', defineIonLoadingCustomElement, ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent', 'trigger']);
|
||||
|
||||
export const IonPickerLegacy = /*@__PURE__*/ defineOverlayContainer<JSX.IonPickerLegacy>('ion-picker-legacy', defineIonPickerLegacyCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger']);
|
||||
|
||||
export const IonToast = /*@__PURE__*/ defineOverlayContainer<JSX.IonToast>('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'positionAnchor', 'swipeGesture', 'translucent', 'trigger']);
|
||||
|
||||
export const IonModal = /*@__PURE__*/ defineOverlayContainer<JSX.IonModal>('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'canDismiss', 'enterAnimation', 'focusTrap', 'handle', 'handleBehavior', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'trigger'], true);
|
||||
|
||||
export const IonPickerLegacy = /*@__PURE__*/ defineOverlayContainer<JSX.IonPickerLegacy>('ion-picker-legacy', defineIonPickerLegacyCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger']);
|
||||
|
||||
export const IonPopover = /*@__PURE__*/ defineOverlayContainer<JSX.IonPopover>('ion-popover', defineIonPopoverCustomElement, ['alignment', 'animated', 'arrow', 'backdropDismiss', 'component', 'componentProps', 'dismissOnSelect', 'enterAnimation', 'event', 'focusTrap', 'htmlAttributes', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'reference', 'showBackdrop', 'side', 'size', 'translucent', 'trigger', 'triggerAction']);
|
||||
|
||||
export const IonToast = /*@__PURE__*/ defineOverlayContainer<JSX.IonToast>('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'positionAnchor', 'swipeGesture', 'translucent', 'trigger']);
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* eslint-disable */
|
||||
/* tslint:disable */
|
||||
/* auto-generated vue proxies */
|
||||
import { defineContainer } from './vue-component-lib/utils';
|
||||
import { defineContainer } from '@stencil/vue-output-target/runtime';
|
||||
|
||||
import type { JSX } from '@ionic/core/components';
|
||||
import type { JSX } from '@ionic/core';
|
||||
|
||||
import { defineCustomElement as defineIonAccordion } from '@ionic/core/components/ion-accordion.js';
|
||||
import { defineCustomElement as defineIonAccordionGroup } from '@ionic/core/components/ion-accordion-group.js';
|
||||
@ -102,6 +102,9 @@ export const IonAccordionGroup = /*@__PURE__*/ defineContainer<JSX.IonAccordionG
|
||||
'expand',
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -114,6 +117,8 @@ export const IonBackdrop = /*@__PURE__*/ defineContainer<JSX.IonBackdrop>('ion-b
|
||||
'tappable',
|
||||
'stopPropagation',
|
||||
'ionBackdropTap'
|
||||
], [
|
||||
'ionBackdropTap'
|
||||
]);
|
||||
|
||||
|
||||
@ -139,6 +144,10 @@ export const IonBreadcrumb = /*@__PURE__*/ defineContainer<JSX.IonBreadcrumb>('i
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'collapsedClick'
|
||||
], [
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'collapsedClick'
|
||||
]);
|
||||
|
||||
|
||||
@ -148,6 +157,8 @@ export const IonBreadcrumbs = /*@__PURE__*/ defineContainer<JSX.IonBreadcrumbs>(
|
||||
'itemsBeforeCollapse',
|
||||
'itemsAfterCollapse',
|
||||
'ionCollapsedClick'
|
||||
], [
|
||||
'ionCollapsedClick'
|
||||
]);
|
||||
|
||||
|
||||
@ -170,6 +181,9 @@ export const IonButton = /*@__PURE__*/ defineContainer<JSX.IonButton>('ion-butto
|
||||
'form',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
], [
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
]);
|
||||
|
||||
|
||||
@ -224,6 +238,10 @@ export const IonCheckbox = /*@__PURE__*/ defineContainer<JSX.IonCheckbox, JSX.Io
|
||||
'ionChange',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
],
|
||||
'checked', 'ion-change');
|
||||
|
||||
@ -274,6 +292,10 @@ export const IonContent = /*@__PURE__*/ defineContainer<JSX.IonContent>('ion-con
|
||||
'ionScrollStart',
|
||||
'ionScroll',
|
||||
'ionScrollEnd'
|
||||
], [
|
||||
'ionScrollStart',
|
||||
'ionScroll',
|
||||
'ionScrollEnd'
|
||||
]);
|
||||
|
||||
|
||||
@ -315,6 +337,14 @@ export const IonDatetime = /*@__PURE__*/ defineContainer<JSX.IonDatetime, JSX.Io
|
||||
'ionBlur',
|
||||
'ionStyle',
|
||||
'ionRender'
|
||||
], [
|
||||
'ionCancel',
|
||||
'ionChange',
|
||||
'ionValueChange',
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'ionStyle',
|
||||
'ionRender'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -351,6 +381,9 @@ export const IonFabButton = /*@__PURE__*/ defineContainer<JSX.IonFabButton>('ion
|
||||
'closeIcon',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
], [
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
]);
|
||||
|
||||
|
||||
@ -383,6 +416,10 @@ export const IonImg = /*@__PURE__*/ defineContainer<JSX.IonImg>('ion-img', defin
|
||||
'ionImgWillLoad',
|
||||
'ionImgDidLoad',
|
||||
'ionError'
|
||||
], [
|
||||
'ionImgWillLoad',
|
||||
'ionImgDidLoad',
|
||||
'ionError'
|
||||
]);
|
||||
|
||||
|
||||
@ -391,6 +428,8 @@ export const IonInfiniteScroll = /*@__PURE__*/ defineContainer<JSX.IonInfiniteSc
|
||||
'disabled',
|
||||
'position',
|
||||
'ionInfinite'
|
||||
], [
|
||||
'ionInfinite'
|
||||
]);
|
||||
|
||||
|
||||
@ -439,6 +478,11 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput, JSX.IonInput
|
||||
'ionChange',
|
||||
'ionBlur',
|
||||
'ionFocus'
|
||||
], [
|
||||
'ionInput',
|
||||
'ionChange',
|
||||
'ionBlur',
|
||||
'ionFocus'
|
||||
],
|
||||
'value', 'ion-input');
|
||||
|
||||
@ -492,12 +536,16 @@ export const IonItemOption = /*@__PURE__*/ defineContainer<JSX.IonItemOption>('i
|
||||
export const IonItemOptions = /*@__PURE__*/ defineContainer<JSX.IonItemOptions>('ion-item-options', defineIonItemOptions, [
|
||||
'side',
|
||||
'ionSwipe'
|
||||
], [
|
||||
'ionSwipe'
|
||||
]);
|
||||
|
||||
|
||||
export const IonItemSliding = /*@__PURE__*/ defineContainer<JSX.IonItemSliding>('ion-item-sliding', defineIonItemSliding, [
|
||||
'disabled',
|
||||
'ionDrag'
|
||||
], [
|
||||
'ionDrag'
|
||||
]);
|
||||
|
||||
|
||||
@ -506,6 +554,9 @@ export const IonLabel = /*@__PURE__*/ defineContainer<JSX.IonLabel>('ion-label',
|
||||
'position',
|
||||
'ionColor',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionColor',
|
||||
'ionStyle'
|
||||
]);
|
||||
|
||||
|
||||
@ -534,6 +585,12 @@ export const IonMenu = /*@__PURE__*/ defineContainer<JSX.IonMenu>('ion-menu', de
|
||||
'ionDidOpen',
|
||||
'ionDidClose',
|
||||
'ionMenuChange'
|
||||
], [
|
||||
'ionWillOpen',
|
||||
'ionWillClose',
|
||||
'ionDidOpen',
|
||||
'ionDidClose',
|
||||
'ionMenuChange'
|
||||
]);
|
||||
|
||||
|
||||
@ -562,6 +619,10 @@ export const IonNav = /*@__PURE__*/ defineContainer<JSX.IonNav>('ion-nav', defin
|
||||
'ionNavWillLoad',
|
||||
'ionNavWillChange',
|
||||
'ionNavDidChange'
|
||||
], [
|
||||
'ionNavWillLoad',
|
||||
'ionNavWillChange',
|
||||
'ionNavDidChange'
|
||||
]);
|
||||
|
||||
|
||||
@ -580,6 +641,8 @@ export const IonNote = /*@__PURE__*/ defineContainer<JSX.IonNote>('ion-note', de
|
||||
|
||||
export const IonPicker = /*@__PURE__*/ defineContainer<JSX.IonPicker>('ion-picker', defineIonPicker, [
|
||||
'ionInputModeChange'
|
||||
], [
|
||||
'ionInputModeChange'
|
||||
]);
|
||||
|
||||
|
||||
@ -589,6 +652,8 @@ export const IonPickerColumn = /*@__PURE__*/ defineContainer<JSX.IonPickerColumn
|
||||
'color',
|
||||
'numericInput',
|
||||
'ionChange'
|
||||
], [
|
||||
'ionChange'
|
||||
]);
|
||||
|
||||
|
||||
@ -618,6 +683,9 @@ export const IonRadio = /*@__PURE__*/ defineContainer<JSX.IonRadio, JSX.IonRadio
|
||||
'alignment',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
], [
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -629,6 +697,9 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer<JSX.IonRadioGroup, JS
|
||||
'value',
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -656,6 +727,13 @@ export const IonRange = /*@__PURE__*/ defineContainer<JSX.IonRange, JSX.IonRange
|
||||
'ionBlur',
|
||||
'ionKnobMoveStart',
|
||||
'ionKnobMoveEnd'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionInput',
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'ionKnobMoveStart',
|
||||
'ionKnobMoveEnd'
|
||||
],
|
||||
'value', 'ion-input');
|
||||
|
||||
@ -670,6 +748,10 @@ export const IonRefresher = /*@__PURE__*/ defineContainer<JSX.IonRefresher>('ion
|
||||
'ionRefresh',
|
||||
'ionPull',
|
||||
'ionStart'
|
||||
], [
|
||||
'ionRefresh',
|
||||
'ionPull',
|
||||
'ionStart'
|
||||
]);
|
||||
|
||||
|
||||
@ -687,6 +769,8 @@ export const IonReorder = /*@__PURE__*/ defineContainer<JSX.IonReorder>('ion-reo
|
||||
export const IonReorderGroup = /*@__PURE__*/ defineContainer<JSX.IonReorderGroup>('ion-reorder-group', defineIonReorderGroup, [
|
||||
'disabled',
|
||||
'ionItemReorder'
|
||||
], [
|
||||
'ionItemReorder'
|
||||
]);
|
||||
|
||||
|
||||
@ -728,6 +812,14 @@ export const IonSearchbar = /*@__PURE__*/ defineContainer<JSX.IonSearchbar, JSX.
|
||||
'ionBlur',
|
||||
'ionFocus',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionInput',
|
||||
'ionChange',
|
||||
'ionCancel',
|
||||
'ionClear',
|
||||
'ionBlur',
|
||||
'ionFocus',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'ion-input');
|
||||
|
||||
@ -742,6 +834,10 @@ export const IonSegment = /*@__PURE__*/ defineContainer<JSX.IonSegment, JSX.IonS
|
||||
'ionChange',
|
||||
'ionSelect',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionSelect',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -752,7 +848,7 @@ export const IonSegmentButton = /*@__PURE__*/ defineContainer<JSX.IonSegmentButt
|
||||
'layout',
|
||||
'type',
|
||||
'value'
|
||||
],
|
||||
], [],
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
@ -762,6 +858,8 @@ export const IonSegmentContent = /*@__PURE__*/ defineContainer<JSX.IonSegmentCon
|
||||
export const IonSegmentView = /*@__PURE__*/ defineContainer<JSX.IonSegmentView>('ion-segment-view', defineIonSegmentView, [
|
||||
'disabled',
|
||||
'ionSegmentViewScroll'
|
||||
], [
|
||||
'ionSegmentViewScroll'
|
||||
]);
|
||||
|
||||
|
||||
@ -791,6 +889,13 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect, JSX.IonSel
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionCancel',
|
||||
'ionDismiss',
|
||||
'ionFocus',
|
||||
'ionBlur',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'ion-change');
|
||||
|
||||
@ -811,6 +916,8 @@ export const IonSelectOption = /*@__PURE__*/ defineContainer<JSX.IonSelectOption
|
||||
export const IonSkeletonText = /*@__PURE__*/ defineContainer<JSX.IonSkeletonText>('ion-skeleton-text', defineIonSkeletonText, [
|
||||
'animated',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionStyle'
|
||||
]);
|
||||
|
||||
|
||||
@ -827,6 +934,8 @@ export const IonSplitPane = /*@__PURE__*/ defineContainer<JSX.IonSplitPane>('ion
|
||||
'disabled',
|
||||
'when',
|
||||
'ionSplitPaneVisible'
|
||||
], [
|
||||
'ionSplitPaneVisible'
|
||||
]);
|
||||
|
||||
|
||||
@ -876,6 +985,11 @@ export const IonTextarea = /*@__PURE__*/ defineContainer<JSX.IonTextarea, JSX.Io
|
||||
'ionInput',
|
||||
'ionBlur',
|
||||
'ionFocus'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionInput',
|
||||
'ionBlur',
|
||||
'ionFocus'
|
||||
],
|
||||
'value', 'ion-input');
|
||||
|
||||
@ -887,6 +1001,8 @@ export const IonTitle = /*@__PURE__*/ defineContainer<JSX.IonTitle>('ion-title',
|
||||
'color',
|
||||
'size',
|
||||
'ionStyle'
|
||||
], [
|
||||
'ionStyle'
|
||||
]);
|
||||
|
||||
|
||||
@ -903,6 +1019,10 @@ export const IonToggle = /*@__PURE__*/ defineContainer<JSX.IonToggle, JSX.IonTog
|
||||
'ionChange',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
], [
|
||||
'ionChange',
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
],
|
||||
'checked', 'ion-change');
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { defineComponent, h, ref, VNode, onMounted } from 'vue';
|
||||
import type { VNode, ComponentOptions } from "vue";
|
||||
import { defineComponent, h, ref, onMounted } from "vue";
|
||||
|
||||
// TODO(FW-2969): types
|
||||
|
||||
@ -9,15 +10,20 @@ export interface OverlayProps {
|
||||
const EMPTY_PROP = Symbol();
|
||||
const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP };
|
||||
|
||||
export const defineOverlayContainer = <Props extends object>(name: string, defineCustomElement: () => void, componentProps: string[] = [], hasDelegateHost?: boolean, controller?: any) => {
|
||||
|
||||
const createControllerComponent = () => {
|
||||
export const defineOverlayContainer = <Props extends object>(
|
||||
name: string,
|
||||
defineCustomElement: () => void,
|
||||
componentProps: string[] = [],
|
||||
hasDelegateHost?: boolean,
|
||||
controller?: any
|
||||
) => {
|
||||
const createControllerComponent = (options: ComponentOptions) => {
|
||||
return defineComponent<Props & OverlayProps>((props, { slots, emit }) => {
|
||||
const eventListeners = [
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: 'willPresent' },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: 'didPresent' },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: 'willDismiss' },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: 'didDismiss' },
|
||||
{ componentEv: `${name}-will-present`, frameworkEv: "willPresent" },
|
||||
{ componentEv: `${name}-did-present`, frameworkEv: "didPresent" },
|
||||
{ componentEv: `${name}-will-dismiss`, frameworkEv: "willDismiss" },
|
||||
{ componentEv: `${name}-did-dismiss`, frameworkEv: "didDismiss" },
|
||||
];
|
||||
|
||||
if (defineCustomElement !== undefined) {
|
||||
@ -27,8 +33,8 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
const overlay = ref();
|
||||
const onVnodeMounted = async () => {
|
||||
const isOpen = props.isOpen;
|
||||
isOpen && (await present(props))
|
||||
}
|
||||
isOpen && (await present(props));
|
||||
};
|
||||
|
||||
const onVnodeUpdated = async (node: VNode, prevNode: VNode) => {
|
||||
const isOpen = node.props!.isOpen;
|
||||
@ -45,11 +51,11 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
} else {
|
||||
await dismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onVnodeBeforeUnmount = async () => {
|
||||
await dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
const dismiss = async () => {
|
||||
if (!overlay.value) return;
|
||||
@ -61,7 +67,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
await overlay.value;
|
||||
|
||||
overlay.value = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const present = async (props: Readonly<Props>) => {
|
||||
/**
|
||||
@ -77,7 +83,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
return;
|
||||
}
|
||||
|
||||
let restOfProps: any = {};
|
||||
const restOfProps: Record<string, unknown> = {};
|
||||
|
||||
/**
|
||||
* We can use Object.entries here
|
||||
@ -87,7 +93,10 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
*/
|
||||
for (const key in props) {
|
||||
const value = props[key] as any;
|
||||
if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(props, key) &&
|
||||
value !== EMPTY_PROP
|
||||
) {
|
||||
restOfProps[key] = value;
|
||||
}
|
||||
}
|
||||
@ -104,35 +113,32 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
const component = slots.default && slots.default()[0];
|
||||
overlay.value = controller.create({
|
||||
...restOfProps,
|
||||
component
|
||||
component,
|
||||
});
|
||||
|
||||
overlay.value = await overlay.value;
|
||||
|
||||
eventListeners.forEach(eventListener => {
|
||||
eventListeners.forEach((eventListener) => {
|
||||
overlay.value.addEventListener(eventListener.componentEv, () => {
|
||||
emit(eventListener.frameworkEv);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
await overlay.value.present();
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: { display: 'none' },
|
||||
onVnodeMounted,
|
||||
onVnodeUpdated,
|
||||
onVnodeBeforeUnmount,
|
||||
isOpen: props.isOpen === true
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
return h("div", {
|
||||
style: { display: "none" },
|
||||
onVnodeMounted,
|
||||
onVnodeUpdated,
|
||||
onVnodeBeforeUnmount,
|
||||
isOpen: props.isOpen === true,
|
||||
});
|
||||
};
|
||||
}, options);
|
||||
};
|
||||
const createInlineComponent = () => {
|
||||
const createInlineComponent = (options: any) => {
|
||||
return defineComponent((props, { slots }) => {
|
||||
if (defineCustomElement !== undefined) {
|
||||
defineCustomElement();
|
||||
@ -141,13 +147,22 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
const elementRef = ref();
|
||||
|
||||
onMounted(() => {
|
||||
elementRef.value.addEventListener('ion-mount', () => isOpen.value = true);
|
||||
elementRef.value.addEventListener('will-present', () => isOpen.value = true);
|
||||
elementRef.value.addEventListener('did-dismiss', () => isOpen.value = false);
|
||||
elementRef.value.addEventListener(
|
||||
"ion-mount",
|
||||
() => (isOpen.value = true)
|
||||
);
|
||||
elementRef.value.addEventListener(
|
||||
"will-present",
|
||||
() => (isOpen.value = true)
|
||||
);
|
||||
elementRef.value.addEventListener(
|
||||
"did-dismiss",
|
||||
() => (isOpen.value = false)
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
let restOfProps: any = {};
|
||||
const restOfProps: Record<string, unknown> = {};
|
||||
|
||||
/**
|
||||
* We can use Object.entries here
|
||||
@ -157,7 +172,10 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
*/
|
||||
for (const key in props) {
|
||||
const value = (props as any)[key];
|
||||
if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(props, key) &&
|
||||
value !== EMPTY_PROP
|
||||
) {
|
||||
restOfProps[key] = value;
|
||||
}
|
||||
}
|
||||
@ -168,11 +186,11 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
*/
|
||||
const renderChildren = () => {
|
||||
if (hasDelegateHost) {
|
||||
return h('div', { className: 'ion-delegate-host ion-page' }, slots);
|
||||
return h("div", { className: "ion-delegate-host ion-page" }, slots);
|
||||
}
|
||||
|
||||
return slots;
|
||||
}
|
||||
};
|
||||
|
||||
return h(
|
||||
name,
|
||||
@ -184,27 +202,32 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
||||
* the value of the prop will be the empty string which is
|
||||
* why we still call renderChildren() in that case.
|
||||
*/
|
||||
(isOpen.value || restOfProps.keepContentsMounted || restOfProps.keepContentsMounted === '') ? renderChildren() : undefined
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const Container = (controller !== undefined) ? createControllerComponent() : createInlineComponent();
|
||||
|
||||
Container.name = name;
|
||||
|
||||
Container.props = {
|
||||
'isOpen': DEFAULT_EMPTY_PROP
|
||||
isOpen.value ||
|
||||
restOfProps.keepContentsMounted ||
|
||||
restOfProps.keepContentsMounted === ""
|
||||
? renderChildren()
|
||||
: undefined
|
||||
);
|
||||
};
|
||||
}, options);
|
||||
};
|
||||
|
||||
componentProps.forEach(componentProp => {
|
||||
Container.props[componentProp] = DEFAULT_EMPTY_PROP;
|
||||
});
|
||||
const options: ComponentOptions = {
|
||||
name,
|
||||
props: {
|
||||
isOpen: DEFAULT_EMPTY_PROP,
|
||||
...componentProps.reduce((acc, prop) => {
|
||||
acc[prop] = DEFAULT_EMPTY_PROP;
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>),
|
||||
},
|
||||
emits:
|
||||
typeof controller !== "undefined"
|
||||
? ["willPresent", "didPresent", "willDismiss", "didDismiss"]
|
||||
: undefined,
|
||||
};
|
||||
|
||||
if (controller !== undefined) {
|
||||
Container.emits = ['willPresent', 'didPresent', 'willDismiss', 'didDismiss'];
|
||||
}
|
||||
|
||||
return Container;
|
||||
}
|
||||
return controller !== undefined
|
||||
? createControllerComponent(options)
|
||||
: createInlineComponent(options);
|
||||
};
|
@ -1,236 +0,0 @@
|
||||
// @ts-nocheck
|
||||
// It's easier and safer for Volar to disable typechecking and let the return type inference do its job.
|
||||
import { defineComponent, getCurrentInstance, h, inject, ref, Ref, withDirectives } from 'vue';
|
||||
|
||||
export interface InputProps<T> {
|
||||
modelValue?: T;
|
||||
}
|
||||
|
||||
const UPDATE_VALUE_EVENT = 'update:modelValue';
|
||||
const MODEL_VALUE = 'modelValue';
|
||||
const ROUTER_LINK_VALUE = 'routerLink';
|
||||
const NAV_MANAGER = 'navManager';
|
||||
const ROUTER_PROP_PREFIX = 'router';
|
||||
const ARIA_PROP_PREFIX = 'aria';
|
||||
/**
|
||||
* 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 };
|
||||
|
||||
interface NavManager<T = any> {
|
||||
navigate: (options: T) => void;
|
||||
}
|
||||
|
||||
const getComponentClasses = (classes: unknown) => {
|
||||
return (classes as string)?.split(' ') || [];
|
||||
};
|
||||
|
||||
const getElementClasses = (
|
||||
ref: Ref<HTMLElement | undefined>,
|
||||
componentClasses: Set<string>,
|
||||
defaultClasses: string[] = []
|
||||
) => {
|
||||
return [...Array.from(ref.value?.classList || []), ...defaultClasses].filter(
|
||||
(c: string, 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)
|
||||
*/
|
||||
export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
name: string,
|
||||
defineCustomElement: any,
|
||||
componentProps: string[] = [],
|
||||
modelProp?: string,
|
||||
modelUpdateEvent?: string
|
||||
) => {
|
||||
/**
|
||||
* 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 = defineComponent<Props & InputProps<VModelType>>((props, { attrs, slots, emit }) => {
|
||||
let modelPropValue = props[modelProp];
|
||||
const containerRef = ref<HTMLElement>();
|
||||
const classes = new Set(getComponentClasses(attrs.class));
|
||||
|
||||
/**
|
||||
* This directive is responsible for updating any reactive
|
||||
* reference associated with v-model on the component.
|
||||
* This code must be run inside of the "created" callback.
|
||||
* Since the following listener callbacks as well as any potential
|
||||
* event callback defined in the developer's app are set on
|
||||
* the same element, we need to make sure the following callbacks
|
||||
* are set first so they fire first. If the developer's callback fires first
|
||||
* then the reactive reference will not have been updated yet.
|
||||
*/
|
||||
const vModelDirective = {
|
||||
created: (el: HTMLElement) => {
|
||||
const eventsNames = Array.isArray(modelUpdateEvent) ? modelUpdateEvent : [modelUpdateEvent];
|
||||
eventsNames.forEach((eventName: string) => {
|
||||
el.addEventListener(eventName.toLowerCase(), (e: Event) => {
|
||||
/**
|
||||
* Only update the v-model binding if the event's target is the element we are
|
||||
* listening on. For example, Component A could emit ionChange, but it could also
|
||||
* have a descendant Component B that also emits ionChange. We only want to update
|
||||
* the v-model for Component A when ionChange originates from that element and not
|
||||
* when ionChange bubbles up from Component B.
|
||||
*/
|
||||
if (e.target.tagName === el.tagName) {
|
||||
modelPropValue = (e?.target as any)[modelProp];
|
||||
emit(UPDATE_VALUE_EVENT, modelPropValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const currentInstance = getCurrentInstance();
|
||||
const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
|
||||
const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
|
||||
const handleRouterLink = (ev: Event) => {
|
||||
const { routerLink } = props;
|
||||
if (routerLink === EMPTY_PROP) return;
|
||||
|
||||
if (navManager !== undefined) {
|
||||
/**
|
||||
* This prevents the browser from
|
||||
* performing a page reload when pressing
|
||||
* an Ionic component with routerLink.
|
||||
* The page reload interferes with routing
|
||||
* and causes ion-back-button to disappear
|
||||
* since the local history is wiped on reload.
|
||||
*/
|
||||
ev.preventDefault();
|
||||
|
||||
let navigationPayload: any = { 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: Event) => {
|
||||
if (oldClick !== undefined) {
|
||||
oldClick(ev);
|
||||
}
|
||||
if (!ev.defaultPrevented) {
|
||||
handleRouterLink(ev);
|
||||
}
|
||||
};
|
||||
|
||||
let propsToAdd: any = {
|
||||
ref: containerRef,
|
||||
class: getElementClasses(containerRef, classes),
|
||||
onClick: handleClick,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) || key.startsWith(ARIA_PROP_PREFIX)) {
|
||||
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 = {
|
||||
...propsToAdd,
|
||||
[modelProp]: props[MODEL_VALUE],
|
||||
};
|
||||
} else if (modelPropValue !== EMPTY_PROP) {
|
||||
propsToAdd = {
|
||||
...propsToAdd,
|
||||
[modelProp]: modelPropValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// If router link is defined, add href to props
|
||||
// in order to properly render an anchor tag inside
|
||||
// of components that should become activatable and
|
||||
// focusable with router link.
|
||||
if (props[ROUTER_LINK_VALUE] !== EMPTY_PROP) {
|
||||
propsToAdd = {
|
||||
...propsToAdd,
|
||||
href: props[ROUTER_LINK_VALUE],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* vModelDirective is only needed on components that support v-model.
|
||||
* As a result, we conditionally call withDirectives with v-model components.
|
||||
*/
|
||||
const node = h(name, propsToAdd, slots.default && slots.default());
|
||||
return modelProp === undefined ? node : withDirectives(node, [[vModelDirective]]);
|
||||
};
|
||||
});
|
||||
|
||||
if (typeof Container !== 'function') {
|
||||
Container.name = 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];
|
||||
}
|
||||
}
|
||||
|
||||
return Container;
|
||||
};
|
Reference in New Issue
Block a user