Skip to content

Commit 23e8a6a

Browse files
Added overlay components, refactor inputs, controllers
1 parent 7d09f4e commit 23e8a6a

26 files changed

+367
-226
lines changed

src/components/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './overlays';
2+
export * from './inputs';
3+
export * from './navigation';

src/components/inputs.ts

Lines changed: 39 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,39 @@
1-
import Vue, { CreateElement, RenderContext } from 'vue';
2-
3-
interface EventHandler {
4-
[key: string]: (e: Event) => void;
5-
}
6-
7-
type Callback = (value: Event | string) => void;
8-
9-
// Events to register handlers for
10-
const events: string[] = ['ionChange', 'ionInput', 'ionBlur', 'ionFocus', 'ionCancel', 'ionSelect'];
11-
12-
// Arguments to be passed to the factory function
13-
const inputComponentsToBeCreated = [
14-
['IonCheckboxVue', 'ion-checkbox', 'ionChange', 'checked'],
15-
['IonDatetimeVue', 'ion-datetime'],
16-
['IonInputVue', 'ion-input', 'ionInput'],
17-
['IonRadioVue', 'ion-radio', 'ionSelect'],
18-
['IonRangeVue', 'ion-range'],
19-
['IonSearchbarVue', 'ion-searchbar', 'ionInput'],
20-
['IonSelectVue', 'ion-select'],
21-
['IonTextareaVue', 'ion-textarea'],
22-
['IonToggleVue', 'ion-toggle', 'ionChange', 'checked'],
23-
];
24-
25-
// Factory function for creation of input components
26-
export function createInputComponents() {
27-
inputComponentsToBeCreated.map(args => (createInputComponent as any)(...args));
28-
}
29-
30-
/**
31-
* Create a wrapped input component that captures typical ionic input events
32-
* and emits core ones so v-model works.
33-
* @param name the vue name of the component
34-
* @param coreTag the actual tag to render (such as ion-datetime)
35-
* @param modelEvent to be used for v-model
36-
* @param valueProperty to be used for v-model
37-
*/
38-
function createInputComponent(name: string, coreTag: string, modelEvent = 'ionChange', valueProperty = 'value') {
39-
Vue.component(name, {
40-
name,
41-
functional: true,
42-
model: {
43-
event: modelEvent,
44-
prop: valueProperty,
45-
},
46-
render(h: CreateElement, { data, listeners, slots }: RenderContext) {
47-
return h(coreTag, {
48-
...data,
49-
on: buildEventHandlers(listeners, modelEvent, valueProperty),
50-
}, slots().default);
51-
},
52-
});
53-
}
54-
55-
function buildEventHandlers(listeners: RenderContext['listeners'], modelEvent: string, valueProperty: string) {
56-
const handlers: EventHandler = {};
57-
58-
// Loop through all the events
59-
events.map((eventName: string) => {
60-
if (!listeners[eventName]) {
61-
return;
62-
}
63-
64-
// Normalize listeners coming from context as Function | Function[]
65-
const callbacks: Callback[] = Array.isArray(listeners[eventName])
66-
? listeners[eventName] as Callback[]
67-
: [listeners[eventName] as Callback];
68-
69-
// Assign handlers
70-
handlers[eventName] = (e: Event) => {
71-
callbacks.map(f => {
72-
if (e) {
73-
f(modelEvent === eventName
74-
? (e.target as any)[valueProperty]
75-
: e
76-
);
77-
}
78-
});
79-
};
80-
});
81-
82-
return handlers;
83-
}
1+
import { createInputComponent } from '../utils';
2+
3+
export const IonCheckboxVue = createInputComponent(
4+
'IonCheckboxVue',
5+
'ion-checkbox',
6+
'ionChange',
7+
'checked'
8+
);
9+
export const IonDatetimeVue = createInputComponent(
10+
'IonDatetimeVue',
11+
'ion-datetime'
12+
);
13+
export const IonInputVue = createInputComponent(
14+
'IonInputVue',
15+
'ion-input',
16+
'ionInput'
17+
);
18+
export const IonRadioVue = createInputComponent(
19+
'IonRadioVue',
20+
'ion-radio',
21+
'ionSelect'
22+
);
23+
export const IonRangeVue = createInputComponent('IonRangeVue', 'ion-range');
24+
export const IonSearchbarVue = createInputComponent(
25+
'IonSearchbarVue',
26+
'ion-searchbar',
27+
'ionInput'
28+
);
29+
export const IonSelectVue = createInputComponent('IonSelectVue', 'ion-select');
30+
export const IonTextareaVue = createInputComponent(
31+
'IonTextareaVue',
32+
'ion-textarea'
33+
);
34+
export const IonToggleVue = createInputComponent(
35+
'IonToggleVue',
36+
'ion-toggle',
37+
'ionChange',
38+
'checked'
39+
);

src/components/navigation/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './ion-page';
2+
export * from './ion-tabs';

src/components/overlays.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { createOverlayComponent } from '../utils';
2+
import {
3+
actionSheetController,
4+
modalController,
5+
popoverController
6+
} from '../controllers';
7+
8+
export const IonModalVue = createOverlayComponent<HTMLIonModalElement>(
9+
'IonModal',
10+
modalController
11+
);
12+
13+
export const IonActionSheetVue = createOverlayComponent<
14+
HTMLIonActionSheetElement
15+
>('IonActionSheet', actionSheetController);
16+
17+
export const IonPopoverVue = createOverlayComponent<HTMLIonPopoverElement>(
18+
'IonPopover',
19+
popoverController
20+
);

src/controllers/modal-controller.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import Vue from 'vue';
2-
import { ModalOptions, modalController as _modalController } from '@ionic/core';
1+
import {
2+
ModalOptions,
3+
OverlayController,
4+
modalController as _modalController
5+
} from '@ionic/core';
36
import { VueDelegate } from './vue-delegate';
47

5-
export const modalController = (delegate?: VueDelegate) => {
6-
delegate = delegate || new VueDelegate(Vue);
8+
export interface ModalController extends OverlayController {
9+
create(options: ModalOptions): Promise<HTMLIonModalElement>;
10+
}
11+
12+
export const modalController = (): ModalController => {
713
return {
814
..._modalController,
915
create(options: ModalOptions) {
1016
return _modalController.create({
1117
...options,
12-
delegate,
18+
delegate: new VueDelegate()
1319
});
1420
}
1521
};

src/controllers/popover-controller.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import Vue from 'vue';
2-
import { PopoverOptions, popoverController as _popoverController } from '@ionic/core';
1+
import {
2+
PopoverOptions,
3+
popoverController as _popoverController
4+
} from '@ionic/core';
35
import { VueDelegate } from './vue-delegate';
46

5-
export const popoverController = (delegate?: VueDelegate) => {
6-
delegate = delegate || new VueDelegate(Vue);
7+
export const popoverController = () => {
78
return {
89
..._popoverController,
910
create(options: PopoverOptions) {
1011
return _popoverController.create({
1112
...options,
12-
delegate,
13+
delegate: new VueDelegate()
1314
});
1415
}
1516
};

src/controllers/vue-delegate.ts

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
import { VueConstructor } from 'vue';
2-
import { FrameworkDelegate, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from '@ionic/core';
1+
import Vue, { VueConstructor } from 'vue';
2+
import {
3+
FrameworkDelegate,
4+
LIFECYCLE_DID_ENTER,
5+
LIFECYCLE_DID_LEAVE,
6+
LIFECYCLE_WILL_ENTER,
7+
LIFECYCLE_WILL_LEAVE,
8+
LIFECYCLE_WILL_UNLOAD
9+
} from '@ionic/core';
310
import { EsModule, HTMLVueElement, WebpackFunction } from '../interfaces';
411

5-
612
// Handle creation of sync and async components
7-
function createVueComponent(vue: VueConstructor, component: WebpackFunction | object | VueConstructor): Promise<VueConstructor> {
8-
return Promise.resolve(
9-
typeof component === 'function' && (component as WebpackFunction).cid === undefined
10-
? (component as WebpackFunction)().then((cmp: any) => vue.extend(isESModule(cmp) ? cmp.default : cmp))
11-
: vue.extend(component)
12-
);
13+
async function createVueComponent(
14+
component: WebpackFunction | object | VueConstructor
15+
): Promise<VueConstructor> {
16+
if (
17+
typeof component === 'function' &&
18+
(component as WebpackFunction).cid === undefined
19+
) {
20+
const cmp = await (component as WebpackFunction)();
21+
return Vue.extend(isESModule(cmp) ? cmp.default : cmp);
22+
}
23+
return Vue.extend(component);
1324
}
1425

1526
export class VueDelegate implements FrameworkDelegate {
16-
constructor(
17-
public vue: VueConstructor,
18-
) {}
19-
2027
// Attach the passed Vue component to DOM
21-
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | VueConstructor, opts?: object, classes?: string[]): Promise<HTMLElement> {
28+
async attachViewToDom(
29+
parentElement: HTMLElement,
30+
component: HTMLElement | WebpackFunction | object | VueConstructor,
31+
opts?: object,
32+
classes?: string[]
33+
): Promise<HTMLElement> {
2234
// Handle HTML elements
2335
if (isElement(component)) {
2436
// Add any classes to the element
@@ -30,22 +42,24 @@ export class VueDelegate implements FrameworkDelegate {
3042
return Promise.resolve(component as HTMLElement);
3143
}
3244

33-
// Get the Vue controller
34-
return createVueComponent(this.vue, component).then((Component: VueConstructor) => {
35-
const componentInstance = new Component(opts);
36-
componentInstance.$mount();
45+
// Get the Vue constructor
46+
const constructor = await createVueComponent(component);
47+
const componentInstance = new constructor(opts);
48+
componentInstance.$mount();
3749

38-
// Add any classes to the Vue component's root element
39-
addClasses(componentInstance.$el as HTMLElement, classes);
50+
// Add any classes to the Vue component's root element
51+
addClasses(componentInstance.$el as HTMLElement, classes);
4052

41-
// Append the Vue component to DOM
42-
parentElement.appendChild(componentInstance.$el);
43-
return componentInstance.$el as HTMLElement;
44-
});
53+
// Append the Vue component to DOM
54+
parentElement.appendChild(componentInstance.$el);
55+
return componentInstance.$el as HTMLElement;
4556
}
4657

4758
// Remove the earlier created Vue component from DOM
48-
removeViewFromDom(_parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void> {
59+
removeViewFromDom(
60+
_parentElement: HTMLElement,
61+
childElement: HTMLVueElement
62+
): Promise<void> {
4963
// Destroy the Vue component instance
5064
if (childElement.__vue__) {
5165
childElement.__vue__.$destroy();
@@ -74,7 +88,8 @@ export function bindLifecycleEvents(instance: any, element: HTMLElement) {
7488
}
7589

7690
// Check Symbol support
77-
const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
91+
const hasSymbol =
92+
typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
7893

7994
// Check if object is an ES module
8095
function isESModule(obj: EsModule) {

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default {
3636
export { default as IonicVueRouter } from './router';
3737

3838
export * from './controllers';
39-
export * from './components/inputs';
39+
export * from './components';
4040

4141
// Icons that are used by internal components
4242
addIcons({

0 commit comments

Comments
 (0)