mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
chore: sync
This commit is contained in:
@ -4,24 +4,10 @@ import type { App, Plugin } from "vue";
|
||||
|
||||
// TODO(FW-2969): types
|
||||
|
||||
/**
|
||||
* 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: string) => {
|
||||
const kebabConvert = (name: string) =>
|
||||
name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
||||
|
||||
switch (eventName) {
|
||||
case "ionInput":
|
||||
return "v-ion-input";
|
||||
case "ionChange":
|
||||
return "v-ion-change";
|
||||
default:
|
||||
return kebabConvert(eventName);
|
||||
}
|
||||
return eventName
|
||||
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2")
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
const getHelperFunctions = () => {
|
||||
|
@ -95,7 +95,7 @@ export const IonAccordionGroup = /*@__PURE__*/ defineContainer<JSX.IonAccordionG
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonAvatar = /*@__PURE__*/ defineContainer<JSX.IonAvatar>('ion-avatar', defineIonAvatar);
|
||||
@ -219,7 +219,7 @@ export const IonCheckbox = /*@__PURE__*/ defineContainer<JSX.IonCheckbox, JSX.Io
|
||||
'ionBlur',
|
||||
'ionStyle'
|
||||
],
|
||||
'checked', 'v-ion-change', 'ionChange');
|
||||
'checked', 'ion-change');
|
||||
|
||||
|
||||
export const IonChip = /*@__PURE__*/ defineContainer<JSX.IonChip>('ion-chip', defineIonChip, [
|
||||
@ -308,7 +308,7 @@ export const IonDatetime = /*@__PURE__*/ defineContainer<JSX.IonDatetime, JSX.Io
|
||||
'ionStyle',
|
||||
'ionRender'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonDatetimeButton = /*@__PURE__*/ defineContainer<JSX.IonDatetimeButton>('ion-datetime-button', defineIonDatetimeButton, [
|
||||
@ -435,7 +435,7 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput, JSX.IonInput
|
||||
'ionFocus',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'v-ion-input', 'ionInput');
|
||||
'value', 'ion-input');
|
||||
|
||||
|
||||
export const IonItem = /*@__PURE__*/ defineContainer<JSX.IonItem>('ion-item', defineIonItem, [
|
||||
@ -591,7 +591,7 @@ export const IonRadio = /*@__PURE__*/ defineContainer<JSX.IonRadio, JSX.IonRadio
|
||||
'ionFocus',
|
||||
'ionBlur'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonRadioGroup = /*@__PURE__*/ defineContainer<JSX.IonRadioGroup, JSX.IonRadioGroup["value"]>('ion-radio-group', defineIonRadioGroup, [
|
||||
@ -602,7 +602,7 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer<JSX.IonRadioGroup, JS
|
||||
'ionChange',
|
||||
'ionValueChange'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonRange = /*@__PURE__*/ defineContainer<JSX.IonRange, JSX.IonRange["value"]>('ion-range', defineIonRange, [
|
||||
@ -631,7 +631,7 @@ export const IonRange = /*@__PURE__*/ defineContainer<JSX.IonRange, JSX.IonRange
|
||||
'ionKnobMoveStart',
|
||||
'ionKnobMoveEnd'
|
||||
],
|
||||
'value', 'v-ion-input', 'ionInput');
|
||||
'value', 'ion-input');
|
||||
|
||||
|
||||
export const IonRefresher = /*@__PURE__*/ defineContainer<JSX.IonRefresher>('ion-refresher', defineIonRefresher, [
|
||||
@ -700,7 +700,7 @@ export const IonSearchbar = /*@__PURE__*/ defineContainer<JSX.IonSearchbar, JSX.
|
||||
'ionFocus',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'v-ion-input', 'ionInput');
|
||||
'value', 'ion-input');
|
||||
|
||||
|
||||
export const IonSegment = /*@__PURE__*/ defineContainer<JSX.IonSegment, JSX.IonSegment["value"]>('ion-segment', defineIonSegment, [
|
||||
@ -714,7 +714,7 @@ export const IonSegment = /*@__PURE__*/ defineContainer<JSX.IonSegment, JSX.IonS
|
||||
'ionSelect',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonSegmentButton = /*@__PURE__*/ defineContainer<JSX.IonSegmentButton, JSX.IonSegmentButton["value"]>('ion-segment-button', defineIonSegmentButton, [
|
||||
@ -723,7 +723,7 @@ export const IonSegmentButton = /*@__PURE__*/ defineContainer<JSX.IonSegmentButt
|
||||
'type',
|
||||
'value'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect, JSX.IonSelect["value"]>('ion-select', defineIonSelect, [
|
||||
@ -754,7 +754,7 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect, JSX.IonSel
|
||||
'ionBlur',
|
||||
'ionStyle'
|
||||
],
|
||||
'value', 'v-ion-change', 'ionChange');
|
||||
'value', 'ion-change');
|
||||
|
||||
|
||||
export const IonSelectOption = /*@__PURE__*/ defineContainer<JSX.IonSelectOption>('ion-select-option', defineIonSelectOption, [
|
||||
@ -826,7 +826,7 @@ export const IonTextarea = /*@__PURE__*/ defineContainer<JSX.IonTextarea, JSX.Io
|
||||
'ionBlur',
|
||||
'ionFocus'
|
||||
],
|
||||
'value', 'v-ion-input', 'ionInput');
|
||||
'value', 'ion-input');
|
||||
|
||||
|
||||
export const IonThumbnail = /*@__PURE__*/ defineContainer<JSX.IonThumbnail>('ion-thumbnail', defineIonThumbnail);
|
||||
@ -855,7 +855,7 @@ export const IonToggle = /*@__PURE__*/ defineContainer<JSX.IonToggle, JSX.IonTog
|
||||
'ionBlur',
|
||||
'ionStyle'
|
||||
],
|
||||
'checked', 'v-ion-change', 'ionChange');
|
||||
'checked', 'ion-change');
|
||||
|
||||
|
||||
export const IonToolbar = /*@__PURE__*/ defineContainer<JSX.IonToolbar>('ion-toolbar', defineIonToolbar, [
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
// It's easier and safer for Volar to disable typechecking and let the return type inference do its job.
|
||||
import { VNode, defineComponent, getCurrentInstance, h, inject, ref, Ref } from 'vue';
|
||||
import { defineComponent, getCurrentInstance, h, inject, ref, Ref, withDirectives } from 'vue';
|
||||
|
||||
export interface InputProps<T> {
|
||||
modelValue?: T;
|
||||
@ -53,16 +53,13 @@ const getElementClasses = (
|
||||
* 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.
|
||||
*/
|
||||
export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
name: string,
|
||||
defineCustomElement: any,
|
||||
componentProps: string[] = [],
|
||||
modelProp?: string,
|
||||
modelUpdateEvent?: string,
|
||||
externalModelUpdateEvent?: string
|
||||
modelUpdateEvent?: string
|
||||
) => {
|
||||
/**
|
||||
* Create a Vue component wrapper around a Web Component.
|
||||
@ -78,29 +75,27 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
let modelPropValue = props[modelProp];
|
||||
const containerRef = ref<HTMLElement>();
|
||||
const classes = new Set(getComponentClasses(attrs.class));
|
||||
const onVnodeBeforeMount = (vnode: VNode) => {
|
||||
// Add a listener to tell Vue to update the v-model
|
||||
if (vnode.el) {
|
||||
|
||||
/**
|
||||
* 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) => {
|
||||
vnode.el!.addEventListener(eventName.toLowerCase(), (e: Event) => {
|
||||
el.addEventListener(eventName.toLowerCase(), (e: Event) => {
|
||||
modelPropValue = (e?.target as any)[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 = getCurrentInstance();
|
||||
@ -146,7 +141,6 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
ref: containerRef,
|
||||
class: getElementClasses(containerRef, classes),
|
||||
onClick: handleClick,
|
||||
onVnodeBeforeMount: modelUpdateEvent ? onVnodeBeforeMount : undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -182,7 +176,12 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
}
|
||||
}
|
||||
|
||||
return h(name, propsToAdd, slots.default && slots.default());
|
||||
/**
|
||||
* 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]]);
|
||||
};
|
||||
});
|
||||
|
||||
@ -199,7 +198,7 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
|
||||
|
||||
if (modelProp) {
|
||||
Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
|
||||
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
|
||||
Container.emits = [UPDATE_VALUE_EVENT];
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user