Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vue): add vue support #291

Merged
merged 24 commits into from
Mar 8, 2023
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: build with latest output target
danielleroux committed Mar 7, 2023
commit 7ff8c586bd537ab5c36185ced65ce8c565fd5781
16 changes: 10 additions & 6 deletions packages/vue/src/components.ts
Original file line number Diff line number Diff line change
@@ -124,12 +124,6 @@ export const IxDatePicker = /*@__PURE__*/ defineContainer<JSX.IxDatePicker>('ix-
]);


export const IxDateTimeCard = /*@__PURE__*/ defineContainer<JSX.IxDateTimeCard>('ix-date-time-card', undefined, [
'individual',
'corners'
]);


export const IxDatetimePicker = /*@__PURE__*/ defineContainer<JSX.IxDatetimePicker>('ix-datetime-picker', undefined, [
'range',
'showHour',
@@ -153,6 +147,9 @@ export const IxDatetimePicker = /*@__PURE__*/ defineContainer<JSX.IxDatetimePick
]);


export const IxDivider = /*@__PURE__*/ defineContainer<JSX.IxDivider>('ix-divider', undefined);


export const IxDrawer = /*@__PURE__*/ defineContainer<JSX.IxDrawer>('ix-drawer', undefined, [
'show',
'closeOnClickOutside',
@@ -176,6 +173,8 @@ export const IxDropdown = /*@__PURE__*/ defineContainer<JSX.IxDropdown>('ix-drop
'adjustDropdownWidthToReferenceWidth',
'header',
'offset',
'triggerEvent',
'overwriteDropdownStyle',
'showChanged'
]);

@@ -201,6 +200,9 @@ export const IxDropdownItem = /*@__PURE__*/ defineContainer<JSX.IxDropdownItem>(
]);


export const IxDropdownQuickActions = /*@__PURE__*/ defineContainer<JSX.IxDropdownQuickActions>('ix-dropdown-quick-actions', undefined);


export const IxEventList = /*@__PURE__*/ defineContainer<JSX.IxEventList>('ix-event-list', undefined, [
'itemHeight',
'compact',
@@ -377,6 +379,8 @@ export const IxMenuAboutNews = /*@__PURE__*/ defineContainer<JSX.IxMenuAboutNews
export const IxMenuAvatar = /*@__PURE__*/ defineContainer<JSX.IxMenuAvatar>('ix-menu-avatar', undefined, [
'top',
'bottom',
'image',
'initials',
'i18nLogout',
'logoutClick'
]);
73 changes: 39 additions & 34 deletions packages/vue/src/vue-component-lib/utils.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ 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
@@ -30,26 +30,31 @@ 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);
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)
* @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>(
* 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.
*/
export const defineContainer = <Props, VModelType = string | number | boolean>(
name: string,
defineCustomElement: any,
componentProps: string[] = [],
@@ -58,10 +63,10 @@ export const defineContainer = <Props, VModelType=string|number|boolean>(
externalModelUpdateEvent?: 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.
*/
* 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();
@@ -116,12 +121,12 @@ export const defineContainer = <Props, VModelType=string|number|boolean>(
} 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 => {
getComponentClasses(attrs.class).forEach((value) => {
classes.add(value);
});

@@ -133,13 +138,13 @@ export const defineContainer = <Props, VModelType=string|number|boolean>(
if (!ev.defaultPrevented) {
handleRouterLink(ev);
}
}
};

let propsToAdd: any = {
ref: containerRef,
class: getElementClasses(containerRef, classes),
onClick: handleClick,
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
onVnodeBeforeMount: modelUpdateEvent ? onVnodeBeforeMount : undefined,
};

/**
@@ -150,7 +155,7 @@ export const defineContainer = <Props, VModelType=string|number|boolean>(
*/
for (const key in props) {
const value = props[key];
if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
if ((props.hasOwnProperty(key) && value !== EMPTY_PROP) || key.startsWith(ARIA_PROP_PREFIX)) {
propsToAdd[key] = value;
}
}
@@ -165,27 +170,27 @@ export const defineContainer = <Props, VModelType=string|number|boolean>(
if (props[MODEL_VALUE] !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
[modelProp]: props[MODEL_VALUE]
}
[modelProp]: props[MODEL_VALUE],
};
} else if (modelPropValue !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
[modelProp]: modelPropValue
}
[modelProp]: modelPropValue,
};
}
}

return h(name, propsToAdd, slots.default && slots.default());
}
};
});

Container.displayName = name;

Container.props = {
[ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP
[ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP,
};

componentProps.forEach(componentProp => {
componentProps.forEach((componentProp) => {
Container.props[componentProp] = DEFAULT_EMPTY_PROP;
});